提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5789 lines
172 KiB

  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const asyncLib = require("neo-async");
  8. const {
  9. AsyncParallelHook,
  10. AsyncSeriesBailHook,
  11. AsyncSeriesHook,
  12. HookMap,
  13. SyncBailHook,
  14. SyncHook,
  15. SyncWaterfallHook
  16. } = require("tapable");
  17. const { CachedSource } = require("webpack-sources");
  18. const { MultiItemCache } = require("./CacheFacade");
  19. const Chunk = require("./Chunk");
  20. const ChunkGraph = require("./ChunkGraph");
  21. const ChunkGroup = require("./ChunkGroup");
  22. const ChunkRenderError = require("./ChunkRenderError");
  23. const ChunkTemplate = require("./ChunkTemplate");
  24. const CodeGenerationError = require("./CodeGenerationError");
  25. const CodeGenerationResults = require("./CodeGenerationResults");
  26. const Dependency = require("./Dependency");
  27. const DependencyTemplates = require("./DependencyTemplates");
  28. const Entrypoint = require("./Entrypoint");
  29. const ErrorHelpers = require("./ErrorHelpers");
  30. const FileSystemInfo = require("./FileSystemInfo");
  31. const {
  32. connectChunkGroupAndChunk,
  33. connectChunkGroupParentAndChild,
  34. connectEntrypointAndDependOn
  35. } = require("./GraphHelpers");
  36. const {
  37. makeWebpackError,
  38. tryRunOrWebpackError
  39. } = require("./HookWebpackError");
  40. const MainTemplate = require("./MainTemplate");
  41. const Module = require("./Module");
  42. const ModuleDependencyError = require("./ModuleDependencyError");
  43. const ModuleDependencyWarning = require("./ModuleDependencyWarning");
  44. const ModuleGraph = require("./ModuleGraph");
  45. const ModuleHashingError = require("./ModuleHashingError");
  46. const ModuleNotFoundError = require("./ModuleNotFoundError");
  47. const ModuleProfile = require("./ModuleProfile");
  48. const ModuleRestoreError = require("./ModuleRestoreError");
  49. const ModuleStoreError = require("./ModuleStoreError");
  50. const ModuleTemplate = require("./ModuleTemplate");
  51. const { WEBPACK_MODULE_TYPE_RUNTIME } = require("./ModuleTypeConstants");
  52. const RuntimeGlobals = require("./RuntimeGlobals");
  53. const RuntimeTemplate = require("./RuntimeTemplate");
  54. const Stats = require("./Stats");
  55. const WebpackError = require("./WebpackError");
  56. const buildChunkGraph = require("./buildChunkGraph");
  57. const BuildCycleError = require("./errors/BuildCycleError");
  58. const { LogType, Logger } = require("./logging/Logger");
  59. const StatsFactory = require("./stats/StatsFactory");
  60. const StatsPrinter = require("./stats/StatsPrinter");
  61. const { equals: arrayEquals } = require("./util/ArrayHelpers");
  62. const AsyncQueue = require("./util/AsyncQueue");
  63. const LazySet = require("./util/LazySet");
  64. const { getOrInsert } = require("./util/MapHelpers");
  65. const WeakTupleMap = require("./util/WeakTupleMap");
  66. const { cachedCleverMerge } = require("./util/cleverMerge");
  67. const {
  68. compareIds,
  69. compareLocations,
  70. compareModulesByIdentifier,
  71. compareSelect,
  72. compareStringsNumeric,
  73. concatComparators
  74. } = require("./util/comparators");
  75. const createHash = require("./util/createHash");
  76. const {
  77. arrayToSetDeprecation,
  78. createFakeHook,
  79. soonFrozenObjectDeprecation
  80. } = require("./util/deprecation");
  81. const processAsyncTree = require("./util/processAsyncTree");
  82. const { getRuntimeKey } = require("./util/runtime");
  83. const { isSourceEqual } = require("./util/source");
  84. /** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */
  85. /** @typedef {import("webpack-sources").Source} Source */
  86. /** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
  87. /** @typedef {import("../declarations/WebpackOptions").HashFunction} HashFunction */
  88. /** @typedef {import("../declarations/WebpackOptions").HashDigest} HashDigest */
  89. /** @typedef {import("../declarations/WebpackOptions").HashDigestLength} HashDigestLength */
  90. /** @typedef {import("../declarations/WebpackOptions").StatsOptions} StatsOptions */
  91. /** @typedef {import("../declarations/WebpackOptions").Plugins} Plugins */
  92. /** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  93. /** @typedef {import("./config/defaults").OutputNormalizedWithDefaults} OutputOptionsWithDefaults */
  94. /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
  95. /** @typedef {import("./Cache")} Cache */
  96. /** @typedef {import("./CacheFacade")} CacheFacade */
  97. /** @typedef {import("./Chunk").ChunkName} ChunkName */
  98. /** @typedef {import("./Chunk").ChunkId} ChunkId */
  99. /** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
  100. /** @typedef {import("./Compiler")} Compiler */
  101. /** @typedef {import("./Compiler").CompilationParams} CompilationParams */
  102. /** @typedef {import("./Compiler").MemCache} MemCache */
  103. /** @typedef {import("./Compiler").WeakReferences} WeakReferences */
  104. /** @typedef {import("./Compiler").ModuleMemCachesItem} ModuleMemCachesItem */
  105. /** @typedef {import("./Compiler").Records} Records */
  106. /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
  107. /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
  108. /** @typedef {import("./Dependency").ReferencedExports} ReferencedExports */
  109. /** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
  110. /** @typedef {import("./Module").NameForCondition} NameForCondition */
  111. /** @typedef {import("./Module").BuildInfo} BuildInfo */
  112. /** @typedef {import("./Module").ValueCacheVersions} ValueCacheVersions */
  113. /** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
  114. /** @typedef {import("./NormalModule").NormalModuleCompilationHooks} NormalModuleCompilationHooks */
  115. /** @typedef {import("./Module").FactoryMeta} FactoryMeta */
  116. /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
  117. /** @typedef {import("./ModuleFactory")} ModuleFactory */
  118. /** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
  119. /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
  120. /** @typedef {import("./ModuleGraphConnection")} ModuleGraphConnection */
  121. /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */
  122. /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
  123. /** @typedef {import("./NormalModule").ParserOptions} ParserOptions */
  124. /** @typedef {import("./NormalModule").GeneratorOptions} GeneratorOptions */
  125. /** @typedef {import("./RequestShortener")} RequestShortener */
  126. /** @typedef {import("./RuntimeModule")} RuntimeModule */
  127. /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
  128. /** @typedef {import("./Template").RenderManifestOptions} RenderManifestOptions */
  129. /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
  130. /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsError} StatsError */
  131. /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModule} StatsModule */
  132. /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */
  133. /** @typedef {import("./util/Hash")} Hash */
  134. /**
  135. * @template T
  136. * @typedef {import("./util/deprecation").FakeHook<T>} FakeHook<T>
  137. */
  138. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  139. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  140. /**
  141. * @callback Callback
  142. * @param {(WebpackError | null)=} err
  143. * @returns {void}
  144. */
  145. /**
  146. * @callback ModuleCallback
  147. * @param {WebpackError | null=} err
  148. * @param {Module | null=} result
  149. * @returns {void}
  150. */
  151. /**
  152. * @callback ModuleFactoryResultCallback
  153. * @param {WebpackError | null=} err
  154. * @param {ModuleFactoryResult | null=} result
  155. * @returns {void}
  156. */
  157. /**
  158. * @callback ModuleOrModuleFactoryResultCallback
  159. * @param {WebpackError | null=} err
  160. * @param {Module | ModuleFactoryResult | null=} result
  161. * @returns {void}
  162. */
  163. /**
  164. * @callback ExecuteModuleCallback
  165. * @param {WebpackError | null=} err
  166. * @param {ExecuteModuleResult | null=} result
  167. * @returns {void}
  168. */
  169. /** @typedef {new (...args: EXPECTED_ANY[]) => Dependency} DependencyConstructor */
  170. /** @typedef {Record<string, Source>} CompilationAssets */
  171. /**
  172. * @typedef {object} AvailableModulesChunkGroupMapping
  173. * @property {ChunkGroup} chunkGroup
  174. * @property {Set<Module>} availableModules
  175. * @property {boolean} needCopy
  176. */
  177. /**
  178. * @typedef {object} DependenciesBlockLike
  179. * @property {Dependency[]} dependencies
  180. * @property {AsyncDependenciesBlock[]} blocks
  181. */
  182. /** @typedef {Set<Chunk>} Chunks */
  183. /**
  184. * @typedef {object} ChunkPathData
  185. * @property {string | number} id
  186. * @property {string=} name
  187. * @property {string} hash
  188. * @property {((length: number) => string)=} hashWithLength
  189. * @property {(Record<string, string>)=} contentHash
  190. * @property {(Record<string, (length: number) => string>)=} contentHashWithLength
  191. */
  192. /**
  193. * @typedef {object} ChunkHashContext
  194. * @property {CodeGenerationResults} codeGenerationResults results of code generation
  195. * @property {RuntimeTemplate} runtimeTemplate the runtime template
  196. * @property {ModuleGraph} moduleGraph the module graph
  197. * @property {ChunkGraph} chunkGraph the chunk graph
  198. */
  199. /**
  200. * @typedef {object} RuntimeRequirementsContext
  201. * @property {ChunkGraph} chunkGraph the chunk graph
  202. * @property {CodeGenerationResults} codeGenerationResults the code generation results
  203. */
  204. /**
  205. * @typedef {object} ExecuteModuleOptions
  206. * @property {EntryOptions=} entryOptions
  207. */
  208. /** @typedef {EXPECTED_ANY} ExecuteModuleExports */
  209. /**
  210. * @typedef {object} ExecuteModuleResult
  211. * @property {ExecuteModuleExports} exports
  212. * @property {boolean} cacheable
  213. * @property {Map<string, { source: Source, info: AssetInfo | undefined }>} assets
  214. * @property {LazySet<string>} fileDependencies
  215. * @property {LazySet<string>} contextDependencies
  216. * @property {LazySet<string>} missingDependencies
  217. * @property {LazySet<string>} buildDependencies
  218. */
  219. /**
  220. * @typedef {object} ExecuteModuleObject
  221. * @property {string=} id module id
  222. * @property {ExecuteModuleExports} exports exports
  223. * @property {boolean} loaded is loaded
  224. * @property {Error=} error error
  225. */
  226. /**
  227. * @typedef {object} ExecuteModuleArgument
  228. * @property {Module} module
  229. * @property {ExecuteModuleObject=} moduleObject
  230. * @property {CodeGenerationResult} codeGenerationResult
  231. */
  232. /** @typedef {((id: string) => ExecuteModuleExports) & { i?: ((options: ExecuteOptions) => void)[], c?: Record<string, ExecuteModuleObject> }} WebpackRequire */
  233. /**
  234. * @typedef {object} ExecuteOptions
  235. * @property {string=} id module id
  236. * @property {ExecuteModuleObject} module module
  237. * @property {WebpackRequire} require require function
  238. */
  239. /**
  240. * @typedef {object} ExecuteModuleContext
  241. * @property {Map<string, { source: Source, info: AssetInfo | undefined }>} assets
  242. * @property {Chunk} chunk
  243. * @property {ChunkGraph} chunkGraph
  244. * @property {WebpackRequire=} __webpack_require__
  245. */
  246. /**
  247. * @typedef {object} EntryData
  248. * @property {Dependency[]} dependencies dependencies of the entrypoint that should be evaluated at startup
  249. * @property {Dependency[]} includeDependencies dependencies of the entrypoint that should be included but not evaluated
  250. * @property {EntryOptions} options options of the entrypoint
  251. */
  252. /**
  253. * @typedef {object} LogEntry
  254. * @property {string} type
  255. * @property {EXPECTED_ANY[]=} args
  256. * @property {number} time
  257. * @property {string[]=} trace
  258. */
  259. /**
  260. * @typedef {object} KnownAssetInfo
  261. * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash)
  262. * @property {boolean=} minimized whether the asset is minimized
  263. * @property {string | string[]=} fullhash the value(s) of the full hash used for this asset
  264. * @property {string | string[]=} chunkhash the value(s) of the chunk hash used for this asset
  265. * @property {string | string[]=} modulehash the value(s) of the module hash used for this asset
  266. * @property {string | string[]=} contenthash the value(s) of the content hash used for this asset
  267. * @property {string=} sourceFilename when asset was created from a source file (potentially transformed), the original filename relative to compilation context
  268. * @property {number=} size size in bytes, only set after asset has been emitted
  269. * @property {boolean=} development true, when asset is only used for development and doesn't count towards user-facing assets
  270. * @property {boolean=} hotModuleReplacement true, when asset ships data for updating an existing application (HMR)
  271. * @property {boolean=} javascriptModule true, when asset is javascript and an ESM
  272. * @property {Record<string, null | string | string[]>=} related object of pointers to other assets, keyed by type of relation (only points from parent to child)
  273. */
  274. /** @typedef {KnownAssetInfo & Record<string, EXPECTED_ANY>} AssetInfo */
  275. /** @typedef {{ path: string, info: AssetInfo }} InterpolatedPathAndAssetInfo */
  276. /**
  277. * @typedef {object} Asset
  278. * @property {string} name the filename of the asset
  279. * @property {Source} source source of the asset
  280. * @property {AssetInfo} info info about the asset
  281. */
  282. /**
  283. * @typedef {object} ModulePathData
  284. * @property {string | number} id
  285. * @property {string} hash
  286. * @property {((length: number) => string)=} hashWithLength
  287. */
  288. /**
  289. * @typedef {object} PathData
  290. * @property {ChunkGraph=} chunkGraph
  291. * @property {string=} hash
  292. * @property {((length: number) => string)=} hashWithLength
  293. * @property {(Chunk | ChunkPathData)=} chunk
  294. * @property {(Module | ModulePathData)=} module
  295. * @property {RuntimeSpec=} runtime
  296. * @property {string=} filename
  297. * @property {string=} basename
  298. * @property {string=} query
  299. * @property {string=} contentHashType
  300. * @property {string=} contentHash
  301. * @property {((length: number) => string)=} contentHashWithLength
  302. * @property {boolean=} noChunkHash
  303. * @property {string=} url
  304. */
  305. /** @typedef {"module" | "chunk" | "root-of-chunk" | "nested"} ExcludeModulesType */
  306. /**
  307. * @typedef {object} KnownNormalizedStatsOptions
  308. * @property {string} context
  309. * @property {RequestShortener} requestShortener
  310. * @property {string | false} chunksSort
  311. * @property {string | false} modulesSort
  312. * @property {string | false} chunkModulesSort
  313. * @property {string | false} nestedModulesSort
  314. * @property {string | false} assetsSort
  315. * @property {boolean} ids
  316. * @property {boolean} cachedAssets
  317. * @property {boolean} groupAssetsByEmitStatus
  318. * @property {boolean} groupAssetsByPath
  319. * @property {boolean} groupAssetsByExtension
  320. * @property {number} assetsSpace
  321. * @property {((value: string, asset: StatsAsset) => boolean)[]} excludeAssets
  322. * @property {((name: string, module: StatsModule, type: ExcludeModulesType) => boolean)[]} excludeModules
  323. * @property {((warning: StatsError, textValue: string) => boolean)[]} warningsFilter
  324. * @property {boolean} cachedModules
  325. * @property {boolean} orphanModules
  326. * @property {boolean} dependentModules
  327. * @property {boolean} runtimeModules
  328. * @property {boolean} groupModulesByCacheStatus
  329. * @property {boolean} groupModulesByLayer
  330. * @property {boolean} groupModulesByAttributes
  331. * @property {boolean} groupModulesByPath
  332. * @property {boolean} groupModulesByExtension
  333. * @property {boolean} groupModulesByType
  334. * @property {boolean | "auto"} entrypoints
  335. * @property {boolean} chunkGroups
  336. * @property {boolean} chunkGroupAuxiliary
  337. * @property {boolean} chunkGroupChildren
  338. * @property {number} chunkGroupMaxAssets
  339. * @property {number} modulesSpace
  340. * @property {number} chunkModulesSpace
  341. * @property {number} nestedModulesSpace
  342. * @property {false | "none" | "error" | "warn" | "info" | "log" | "verbose"} logging
  343. * @property {((value: string) => boolean)[]} loggingDebug
  344. * @property {boolean} loggingTrace
  345. * @property {EXPECTED_ANY} _env
  346. */
  347. /** @typedef {KnownNormalizedStatsOptions & Omit<StatsOptions, keyof KnownNormalizedStatsOptions> & Record<string, EXPECTED_ANY>} NormalizedStatsOptions */
  348. /**
  349. * @typedef {object} KnownCreateStatsOptionsContext
  350. * @property {boolean=} forToString
  351. */
  352. /** @typedef {KnownCreateStatsOptionsContext & Record<string, EXPECTED_ANY>} CreateStatsOptionsContext */
  353. /** @typedef {{ module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}} CodeGenerationJob */
  354. /** @typedef {CodeGenerationJob[]} CodeGenerationJobs */
  355. /** @typedef {{javascript: ModuleTemplate}} ModuleTemplates */
  356. /** @typedef {Set<Module>} NotCodeGeneratedModules */
  357. /** @type {AssetInfo} */
  358. const EMPTY_ASSET_INFO = Object.freeze({});
  359. const esmDependencyCategory = "esm";
  360. // TODO webpack 6: remove
  361. const deprecatedNormalModuleLoaderHook = util.deprecate(
  362. /**
  363. * @param {Compilation} compilation compilation
  364. * @returns {NormalModuleCompilationHooks["loader"]} hooks
  365. */
  366. (compilation) =>
  367. require("./NormalModule").getCompilationHooks(compilation).loader,
  368. "Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader",
  369. "DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK"
  370. );
  371. // TODO webpack 6: remove
  372. /**
  373. * @param {ModuleTemplates | undefined} moduleTemplates module templates
  374. */
  375. const defineRemovedModuleTemplates = (moduleTemplates) => {
  376. Object.defineProperties(moduleTemplates, {
  377. asset: {
  378. enumerable: false,
  379. configurable: false,
  380. get: () => {
  381. throw new WebpackError(
  382. "Compilation.moduleTemplates.asset has been removed"
  383. );
  384. }
  385. },
  386. webassembly: {
  387. enumerable: false,
  388. configurable: false,
  389. get: () => {
  390. throw new WebpackError(
  391. "Compilation.moduleTemplates.webassembly has been removed"
  392. );
  393. }
  394. }
  395. });
  396. moduleTemplates = undefined;
  397. };
  398. const byId = compareSelect((c) => c.id, compareIds);
  399. const byNameOrHash = concatComparators(
  400. compareSelect((c) => c.name, compareIds),
  401. compareSelect((c) => c.fullHash, compareIds)
  402. );
  403. const byMessage = compareSelect(
  404. (err) => `${err.message}`,
  405. compareStringsNumeric
  406. );
  407. const byModule = compareSelect(
  408. (err) => (err.module && err.module.identifier()) || "",
  409. compareStringsNumeric
  410. );
  411. const byLocation = compareSelect((err) => err.loc, compareLocations);
  412. const compareErrors = concatComparators(byModule, byLocation, byMessage);
  413. /**
  414. * @typedef {object} KnownUnsafeCacheData
  415. * @property {FactoryMeta=} factoryMeta factory meta
  416. * @property {ResolveOptions=} resolveOptions resolve options
  417. * @property {ParserOptions=} parserOptions
  418. * @property {GeneratorOptions=} generatorOptions
  419. */
  420. /** @typedef {KnownUnsafeCacheData & Record<string, EXPECTED_ANY>} UnsafeCacheData */
  421. /**
  422. * @typedef {Module & { restoreFromUnsafeCache?: (unsafeCacheData: UnsafeCacheData, moduleFactory: ModuleFactory, compilationParams: CompilationParams) => void }} ModuleWithRestoreFromUnsafeCache
  423. */
  424. /** @type {WeakMap<Dependency, ModuleWithRestoreFromUnsafeCache | null>} */
  425. const unsafeCacheDependencies = new WeakMap();
  426. /** @type {WeakMap<ModuleWithRestoreFromUnsafeCache, UnsafeCacheData>} */
  427. const unsafeCacheData = new WeakMap();
  428. /** @typedef {{ id: ModuleId, modules?: Map<Module, ModuleId>, blocks?: (ChunkId | null)[] }} References */
  429. /** @typedef {Map<Module, WeakTupleMap<EXPECTED_ANY[], EXPECTED_ANY>>} ModuleMemCaches */
  430. class Compilation {
  431. /**
  432. * Creates an instance of Compilation.
  433. * @param {Compiler} compiler the compiler which created the compilation
  434. * @param {CompilationParams} params the compilation parameters
  435. */
  436. constructor(compiler, params) {
  437. this._backCompat = compiler._backCompat;
  438. const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this);
  439. /** @typedef {{ additionalAssets?: boolean | ((assets: CompilationAssets) => void) }} ProcessAssetsAdditionalOptions */
  440. /** @type {AsyncSeriesHook<[CompilationAssets], ProcessAssetsAdditionalOptions>} */
  441. const processAssetsHook = new AsyncSeriesHook(["assets"]);
  442. let savedAssets = new Set();
  443. /**
  444. * @param {CompilationAssets} assets assets
  445. * @returns {CompilationAssets} new assets
  446. */
  447. const popNewAssets = (assets) => {
  448. let newAssets;
  449. for (const file of Object.keys(assets)) {
  450. if (savedAssets.has(file)) continue;
  451. if (newAssets === undefined) {
  452. newAssets = Object.create(null);
  453. }
  454. newAssets[file] = assets[file];
  455. savedAssets.add(file);
  456. }
  457. return newAssets;
  458. };
  459. processAssetsHook.intercept({
  460. name: "Compilation",
  461. call: () => {
  462. savedAssets = new Set(Object.keys(this.assets));
  463. },
  464. register: (tap) => {
  465. const { type, name } = tap;
  466. const { fn, additionalAssets, ...remainingTap } = tap;
  467. const additionalAssetsFn =
  468. additionalAssets === true ? fn : additionalAssets;
  469. /** @typedef {WeakSet<CompilationAssets>} ProcessedAssets */
  470. /** @type {ProcessedAssets | undefined} */
  471. const processedAssets = additionalAssetsFn ? new WeakSet() : undefined;
  472. /**
  473. * @param {CompilationAssets} assets to be processed by additionalAssetsFn
  474. * @returns {CompilationAssets} available assets
  475. */
  476. const getAvailableAssets = (assets) => {
  477. /** @type {CompilationAssets} */
  478. const availableAssets = {};
  479. for (const file of Object.keys(assets)) {
  480. // https://github.com/webpack-contrib/compression-webpack-plugin/issues/390
  481. if (this.assets[file]) {
  482. availableAssets[file] = assets[file];
  483. }
  484. }
  485. return availableAssets;
  486. };
  487. switch (type) {
  488. case "sync":
  489. if (additionalAssetsFn) {
  490. this.hooks.processAdditionalAssets.tap(name, (assets) => {
  491. if (
  492. /** @type {ProcessedAssets} */
  493. (processedAssets).has(this.assets)
  494. ) {
  495. additionalAssetsFn(getAvailableAssets(assets));
  496. }
  497. });
  498. }
  499. return {
  500. ...remainingTap,
  501. type: "async",
  502. /**
  503. * @param {CompilationAssets} assets assets
  504. * @param {(err?: Error | null, result?: void) => void} callback callback
  505. * @returns {void}
  506. */
  507. fn: (assets, callback) => {
  508. try {
  509. fn(assets);
  510. } catch (err) {
  511. return callback(/** @type {Error} */ (err));
  512. }
  513. if (processedAssets !== undefined) {
  514. processedAssets.add(this.assets);
  515. }
  516. const newAssets = popNewAssets(assets);
  517. if (newAssets !== undefined) {
  518. this.hooks.processAdditionalAssets.callAsync(
  519. newAssets,
  520. callback
  521. );
  522. return;
  523. }
  524. callback();
  525. }
  526. };
  527. case "async":
  528. if (additionalAssetsFn) {
  529. this.hooks.processAdditionalAssets.tapAsync(
  530. name,
  531. (assets, callback) => {
  532. if (
  533. /** @type {ProcessedAssets} */
  534. (processedAssets).has(this.assets)
  535. ) {
  536. return additionalAssetsFn(
  537. getAvailableAssets(assets),
  538. callback
  539. );
  540. }
  541. callback();
  542. }
  543. );
  544. }
  545. return {
  546. ...remainingTap,
  547. /**
  548. * @param {CompilationAssets} assets assets
  549. * @param {(err?: Error | null, result?: void) => void} callback callback
  550. * @returns {void}
  551. */
  552. fn: (assets, callback) => {
  553. fn(
  554. assets,
  555. /**
  556. * @param {Error} err err
  557. * @returns {void}
  558. */
  559. (err) => {
  560. if (err) return callback(err);
  561. if (processedAssets !== undefined) {
  562. processedAssets.add(this.assets);
  563. }
  564. const newAssets = popNewAssets(assets);
  565. if (newAssets !== undefined) {
  566. this.hooks.processAdditionalAssets.callAsync(
  567. newAssets,
  568. callback
  569. );
  570. return;
  571. }
  572. callback();
  573. }
  574. );
  575. }
  576. };
  577. case "promise":
  578. if (additionalAssetsFn) {
  579. this.hooks.processAdditionalAssets.tapPromise(name, (assets) => {
  580. if (
  581. /** @type {ProcessedAssets} */
  582. (processedAssets).has(this.assets)
  583. ) {
  584. return additionalAssetsFn(getAvailableAssets(assets));
  585. }
  586. return Promise.resolve();
  587. });
  588. }
  589. return {
  590. ...remainingTap,
  591. /**
  592. * @param {CompilationAssets} assets assets
  593. * @returns {Promise<CompilationAssets>} result
  594. */
  595. fn: (assets) => {
  596. const p = fn(assets);
  597. if (!p || !p.then) return p;
  598. return p.then(() => {
  599. if (processedAssets !== undefined) {
  600. processedAssets.add(this.assets);
  601. }
  602. const newAssets = popNewAssets(assets);
  603. if (newAssets !== undefined) {
  604. return this.hooks.processAdditionalAssets.promise(
  605. newAssets
  606. );
  607. }
  608. });
  609. }
  610. };
  611. }
  612. }
  613. });
  614. /** @type {SyncHook<[CompilationAssets]>} */
  615. const afterProcessAssetsHook = new SyncHook(["assets"]);
  616. /**
  617. * @template T
  618. * @param {string} name name of the hook
  619. * @param {number} stage new stage
  620. * @param {() => AsArray<T>} getArgs get old hook function args
  621. * @param {string=} code deprecation code (not deprecated when unset)
  622. * @returns {FakeHook<Pick<AsyncSeriesHook<T>, "tap" | "tapAsync" | "tapPromise" | "name">> | undefined} fake hook which redirects
  623. */
  624. const createProcessAssetsHook = (name, stage, getArgs, code) => {
  625. if (!this._backCompat && code) return;
  626. /**
  627. * @param {string} reason reason
  628. * @returns {string} error message
  629. */
  630. const errorMessage = (
  631. reason
  632. ) => `Can't automatically convert plugin using Compilation.hooks.${name} to Compilation.hooks.processAssets because ${reason}.
  633. BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a single Compilation.hooks.processAssets hook.`;
  634. /**
  635. * @param {string | (import("tapable").TapOptions & { name: string; } & ProcessAssetsAdditionalOptions)} options hook options
  636. * @returns {import("tapable").TapOptions & { name: string; } & ProcessAssetsAdditionalOptions} modified options
  637. */
  638. const getOptions = (options) => {
  639. if (typeof options === "string") options = { name: options };
  640. if (options.stage) {
  641. throw new Error(errorMessage("it's using the 'stage' option"));
  642. }
  643. return { ...options, stage };
  644. };
  645. return createFakeHook(
  646. {
  647. name,
  648. /** @type {AsyncSeriesHook<T>["intercept"]} */
  649. intercept(_interceptor) {
  650. throw new Error(errorMessage("it's using 'intercept'"));
  651. },
  652. /** @type {AsyncSeriesHook<T>["tap"]} */
  653. tap: (options, fn) => {
  654. processAssetsHook.tap(getOptions(options), () => fn(...getArgs()));
  655. },
  656. /** @type {AsyncSeriesHook<T>["tapAsync"]} */
  657. tapAsync: (options, fn) => {
  658. processAssetsHook.tapAsync(
  659. getOptions(options),
  660. (assets, callback) =>
  661. /** @type {EXPECTED_ANY} */ (fn)(...getArgs(), callback)
  662. );
  663. },
  664. /** @type {AsyncSeriesHook<T>["tapPromise"]} */
  665. tapPromise: (options, fn) => {
  666. processAssetsHook.tapPromise(getOptions(options), () =>
  667. fn(...getArgs())
  668. );
  669. }
  670. },
  671. `${name} is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)`,
  672. code
  673. );
  674. };
  675. this.hooks = Object.freeze({
  676. /** @type {SyncHook<[Module]>} */
  677. buildModule: new SyncHook(["module"]),
  678. /** @type {SyncHook<[Module]>} */
  679. rebuildModule: new SyncHook(["module"]),
  680. /** @type {SyncHook<[Module, WebpackError]>} */
  681. failedModule: new SyncHook(["module", "error"]),
  682. /** @type {SyncHook<[Module]>} */
  683. succeedModule: new SyncHook(["module"]),
  684. /** @type {SyncHook<[Module]>} */
  685. stillValidModule: new SyncHook(["module"]),
  686. /** @type {SyncHook<[Dependency, EntryOptions]>} */
  687. addEntry: new SyncHook(["entry", "options"]),
  688. /** @type {SyncHook<[Dependency, EntryOptions, Error]>} */
  689. failedEntry: new SyncHook(["entry", "options", "error"]),
  690. /** @type {SyncHook<[Dependency, EntryOptions, Module]>} */
  691. succeedEntry: new SyncHook(["entry", "options", "module"]),
  692. /** @type {SyncWaterfallHook<[ReferencedExports, Dependency, RuntimeSpec]>} */
  693. dependencyReferencedExports: new SyncWaterfallHook([
  694. "referencedExports",
  695. "dependency",
  696. "runtime"
  697. ]),
  698. /** @type {SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
  699. executeModule: new SyncHook(["options", "context"]),
  700. /** @type {AsyncParallelHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
  701. prepareModuleExecution: new AsyncParallelHook(["options", "context"]),
  702. /** @type {AsyncSeriesHook<[Iterable<Module>]>} */
  703. finishModules: new AsyncSeriesHook(["modules"]),
  704. /** @type {AsyncSeriesHook<[Module]>} */
  705. finishRebuildingModule: new AsyncSeriesHook(["module"]),
  706. /** @type {SyncHook<[]>} */
  707. unseal: new SyncHook([]),
  708. /** @type {SyncHook<[]>} */
  709. seal: new SyncHook([]),
  710. /** @type {SyncHook<[]>} */
  711. beforeChunks: new SyncHook([]),
  712. /**
  713. * The `afterChunks` hook is called directly after the chunks and module graph have
  714. * been created and before the chunks and modules have been optimized. This hook is useful to
  715. * inspect, analyze, and/or modify the chunk graph.
  716. * @type {SyncHook<[Iterable<Chunk>]>}
  717. */
  718. afterChunks: new SyncHook(["chunks"]),
  719. /** @type {SyncBailHook<[Iterable<Module>], boolean | void>} */
  720. optimizeDependencies: new SyncBailHook(["modules"]),
  721. /** @type {SyncHook<[Iterable<Module>]>} */
  722. afterOptimizeDependencies: new SyncHook(["modules"]),
  723. /** @type {SyncHook<[]>} */
  724. optimize: new SyncHook([]),
  725. /** @type {SyncBailHook<[Iterable<Module>], boolean | void>} */
  726. optimizeModules: new SyncBailHook(["modules"]),
  727. /** @type {SyncHook<[Iterable<Module>]>} */
  728. afterOptimizeModules: new SyncHook(["modules"]),
  729. /** @type {SyncBailHook<[Iterable<Chunk>, ChunkGroup[]], boolean | void>} */
  730. optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
  731. /** @type {SyncHook<[Iterable<Chunk>, ChunkGroup[]]>} */
  732. afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
  733. /** @type {AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>} */
  734. optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
  735. /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
  736. afterOptimizeTree: new SyncHook(["chunks", "modules"]),
  737. /** @type {AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>], void>} */
  738. optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]),
  739. /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
  740. afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
  741. /** @type {SyncBailHook<[], boolean | void>} */
  742. shouldRecord: new SyncBailHook([]),
  743. /** @type {SyncHook<[Chunk, RuntimeRequirements, RuntimeRequirementsContext]>} */
  744. additionalChunkRuntimeRequirements: new SyncHook([
  745. "chunk",
  746. "runtimeRequirements",
  747. "context"
  748. ]),
  749. /** @type {HookMap<SyncBailHook<[Chunk, RuntimeRequirements, RuntimeRequirementsContext], void>>} */
  750. runtimeRequirementInChunk: new HookMap(
  751. () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
  752. ),
  753. /** @type {SyncHook<[Module, RuntimeRequirements, RuntimeRequirementsContext]>} */
  754. additionalModuleRuntimeRequirements: new SyncHook([
  755. "module",
  756. "runtimeRequirements",
  757. "context"
  758. ]),
  759. /** @type {HookMap<SyncBailHook<[Module, RuntimeRequirements, RuntimeRequirementsContext], void>>} */
  760. runtimeRequirementInModule: new HookMap(
  761. () => new SyncBailHook(["module", "runtimeRequirements", "context"])
  762. ),
  763. /** @type {SyncHook<[Chunk, RuntimeRequirements, RuntimeRequirementsContext]>} */
  764. additionalTreeRuntimeRequirements: new SyncHook([
  765. "chunk",
  766. "runtimeRequirements",
  767. "context"
  768. ]),
  769. /** @type {HookMap<SyncBailHook<[Chunk, RuntimeRequirements, RuntimeRequirementsContext], void>>} */
  770. runtimeRequirementInTree: new HookMap(
  771. () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
  772. ),
  773. /** @type {SyncHook<[RuntimeModule, Chunk]>} */
  774. runtimeModule: new SyncHook(["module", "chunk"]),
  775. /** @type {SyncHook<[Iterable<Module>, Records]>} */
  776. reviveModules: new SyncHook(["modules", "records"]),
  777. /** @type {SyncHook<[Iterable<Module>]>} */
  778. beforeModuleIds: new SyncHook(["modules"]),
  779. /** @type {SyncHook<[Iterable<Module>]>} */
  780. moduleIds: new SyncHook(["modules"]),
  781. /** @type {SyncHook<[Iterable<Module>]>} */
  782. optimizeModuleIds: new SyncHook(["modules"]),
  783. /** @type {SyncHook<[Iterable<Module>]>} */
  784. afterOptimizeModuleIds: new SyncHook(["modules"]),
  785. /** @type {SyncHook<[Iterable<Chunk>, Records]>} */
  786. reviveChunks: new SyncHook(["chunks", "records"]),
  787. /** @type {SyncHook<[Iterable<Chunk>]>} */
  788. beforeChunkIds: new SyncHook(["chunks"]),
  789. /** @type {SyncHook<[Iterable<Chunk>]>} */
  790. chunkIds: new SyncHook(["chunks"]),
  791. /** @type {SyncHook<[Iterable<Chunk>]>} */
  792. optimizeChunkIds: new SyncHook(["chunks"]),
  793. /** @type {SyncHook<[Iterable<Chunk>]>} */
  794. afterOptimizeChunkIds: new SyncHook(["chunks"]),
  795. /** @type {SyncHook<[Iterable<Module>, Records]>} */
  796. recordModules: new SyncHook(["modules", "records"]),
  797. /** @type {SyncHook<[Iterable<Chunk>, Records]>} */
  798. recordChunks: new SyncHook(["chunks", "records"]),
  799. /** @type {SyncHook<[Iterable<Module>]>} */
  800. optimizeCodeGeneration: new SyncHook(["modules"]),
  801. /** @type {SyncHook<[]>} */
  802. beforeModuleHash: new SyncHook([]),
  803. /** @type {SyncHook<[]>} */
  804. afterModuleHash: new SyncHook([]),
  805. /** @type {SyncHook<[]>} */
  806. beforeCodeGeneration: new SyncHook([]),
  807. /** @type {SyncHook<[]>} */
  808. afterCodeGeneration: new SyncHook([]),
  809. /** @type {SyncHook<[]>} */
  810. beforeRuntimeRequirements: new SyncHook([]),
  811. /** @type {SyncHook<[]>} */
  812. afterRuntimeRequirements: new SyncHook([]),
  813. /** @type {SyncHook<[]>} */
  814. beforeHash: new SyncHook([]),
  815. /** @type {SyncHook<[Chunk]>} */
  816. contentHash: new SyncHook(["chunk"]),
  817. /** @type {SyncHook<[]>} */
  818. afterHash: new SyncHook([]),
  819. /** @type {SyncHook<[Records]>} */
  820. recordHash: new SyncHook(["records"]),
  821. /** @type {SyncHook<[Compilation, Records]>} */
  822. record: new SyncHook(["compilation", "records"]),
  823. /** @type {SyncHook<[]>} */
  824. beforeModuleAssets: new SyncHook([]),
  825. /** @type {SyncBailHook<[], boolean | void>} */
  826. shouldGenerateChunkAssets: new SyncBailHook([]),
  827. /** @type {SyncHook<[]>} */
  828. beforeChunkAssets: new SyncHook([]),
  829. // TODO webpack 6 remove
  830. /** @deprecated */
  831. additionalChunkAssets:
  832. /** @type {FakeHook<Pick<AsyncSeriesHook<[Chunks]>, "tap" | "tapAsync" | "tapPromise" | "name">>} */
  833. (
  834. createProcessAssetsHook(
  835. "additionalChunkAssets",
  836. Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
  837. () => [this.chunks],
  838. "DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS"
  839. )
  840. ),
  841. // TODO webpack 6 deprecate
  842. /** @deprecated */
  843. additionalAssets:
  844. /** @type {FakeHook<Pick<AsyncSeriesHook<[]>, "tap" | "tapAsync" | "tapPromise" | "name">>} */
  845. (
  846. createProcessAssetsHook(
  847. "additionalAssets",
  848. Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
  849. () => []
  850. )
  851. ),
  852. // TODO webpack 6 remove
  853. /** @deprecated */
  854. optimizeChunkAssets:
  855. /** @type {FakeHook<Pick<AsyncSeriesHook<[Chunks]>, "tap" | "tapAsync" | "tapPromise" | "name">>} */
  856. (
  857. createProcessAssetsHook(
  858. "optimizeChunkAssets",
  859. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,
  860. () => [this.chunks],
  861. "DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS"
  862. )
  863. ),
  864. // TODO webpack 6 remove
  865. /** @deprecated */
  866. afterOptimizeChunkAssets:
  867. /** @type {FakeHook<Pick<AsyncSeriesHook<[Chunks]>, "tap" | "tapAsync" | "tapPromise" | "name">>} */
  868. (
  869. createProcessAssetsHook(
  870. "afterOptimizeChunkAssets",
  871. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1,
  872. () => [this.chunks],
  873. "DEP_WEBPACK_COMPILATION_AFTER_OPTIMIZE_CHUNK_ASSETS"
  874. )
  875. ),
  876. // TODO webpack 6 deprecate
  877. /** @deprecated */
  878. optimizeAssets: processAssetsHook,
  879. // TODO webpack 6 deprecate
  880. /** @deprecated */
  881. afterOptimizeAssets: afterProcessAssetsHook,
  882. processAssets: processAssetsHook,
  883. afterProcessAssets: afterProcessAssetsHook,
  884. /** @type {AsyncSeriesHook<[CompilationAssets]>} */
  885. processAdditionalAssets: new AsyncSeriesHook(["assets"]),
  886. /** @type {SyncBailHook<[], boolean | void>} */
  887. needAdditionalSeal: new SyncBailHook([]),
  888. /** @type {AsyncSeriesHook<[]>} */
  889. afterSeal: new AsyncSeriesHook([]),
  890. /** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */
  891. renderManifest: new SyncWaterfallHook(["result", "options"]),
  892. /** @type {SyncHook<[Hash]>} */
  893. fullHash: new SyncHook(["hash"]),
  894. /** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */
  895. chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]),
  896. /** @type {SyncHook<[Module, string]>} */
  897. moduleAsset: new SyncHook(["module", "filename"]),
  898. /** @type {SyncHook<[Chunk, string]>} */
  899. chunkAsset: new SyncHook(["chunk", "filename"]),
  900. /** @type {SyncWaterfallHook<[string, PathData, AssetInfo | undefined]>} */
  901. assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]),
  902. /** @type {SyncBailHook<[], boolean | void>} */
  903. needAdditionalPass: new SyncBailHook([]),
  904. /** @type {SyncHook<[Compiler, string, number]>} */
  905. childCompiler: new SyncHook([
  906. "childCompiler",
  907. "compilerName",
  908. "compilerIndex"
  909. ]),
  910. /** @type {SyncBailHook<[string, LogEntry], boolean | void>} */
  911. log: new SyncBailHook(["origin", "logEntry"]),
  912. /** @type {SyncWaterfallHook<[Error[]]>} */
  913. processWarnings: new SyncWaterfallHook(["warnings"]),
  914. /** @type {SyncWaterfallHook<[Error[]]>} */
  915. processErrors: new SyncWaterfallHook(["errors"]),
  916. /** @type {HookMap<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>} */
  917. statsPreset: new HookMap(() => new SyncHook(["options", "context"])),
  918. /** @type {SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>} */
  919. statsNormalize: new SyncHook(["options", "context"]),
  920. /** @type {SyncHook<[StatsFactory, NormalizedStatsOptions]>} */
  921. statsFactory: new SyncHook(["statsFactory", "options"]),
  922. /** @type {SyncHook<[StatsPrinter, NormalizedStatsOptions]>} */
  923. statsPrinter: new SyncHook(["statsPrinter", "options"]),
  924. get normalModuleLoader() {
  925. return getNormalModuleLoader();
  926. }
  927. });
  928. /** @type {string=} */
  929. this.name = undefined;
  930. /** @type {number | undefined} */
  931. this.startTime = undefined;
  932. /** @type {number | undefined} */
  933. this.endTime = undefined;
  934. /** @type {Compiler} */
  935. this.compiler = compiler;
  936. this.resolverFactory = compiler.resolverFactory;
  937. /** @type {InputFileSystem} */
  938. this.inputFileSystem =
  939. /** @type {InputFileSystem} */
  940. (compiler.inputFileSystem);
  941. this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, {
  942. unmanagedPaths: compiler.unmanagedPaths,
  943. managedPaths: compiler.managedPaths,
  944. immutablePaths: compiler.immutablePaths,
  945. logger: this.getLogger("webpack.FileSystemInfo"),
  946. hashFunction: compiler.options.output.hashFunction
  947. });
  948. if (compiler.fileTimestamps) {
  949. this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
  950. }
  951. if (compiler.contextTimestamps) {
  952. this.fileSystemInfo.addContextTimestamps(
  953. compiler.contextTimestamps,
  954. true
  955. );
  956. }
  957. /** @type {ValueCacheVersions} */
  958. this.valueCacheVersions = new Map();
  959. this.requestShortener = compiler.requestShortener;
  960. this.compilerPath = compiler.compilerPath;
  961. this.logger = this.getLogger("webpack.Compilation");
  962. const options = /** @type {WebpackOptions} */ (compiler.options);
  963. this.options = options;
  964. this.outputOptions =
  965. /** @type {OutputOptionsWithDefaults} */
  966. (options && options.output);
  967. /** @type {boolean} */
  968. this.bail = (options && options.bail) || false;
  969. /** @type {boolean} */
  970. this.profile = (options && options.profile) || false;
  971. this.params = params;
  972. this.mainTemplate = new MainTemplate(this.outputOptions, this);
  973. this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
  974. this.runtimeTemplate = new RuntimeTemplate(
  975. this,
  976. this.outputOptions,
  977. this.requestShortener
  978. );
  979. /** @type {ModuleTemplates} */
  980. this.moduleTemplates = {
  981. javascript: new ModuleTemplate(this.runtimeTemplate, this)
  982. };
  983. defineRemovedModuleTemplates(this.moduleTemplates);
  984. // We need to think how implement types here
  985. /** @type {ModuleMemCaches | undefined} */
  986. this.moduleMemCaches = undefined;
  987. /** @type {ModuleMemCaches | undefined} */
  988. this.moduleMemCaches2 = undefined;
  989. /** @type {ModuleGraph} */
  990. this.moduleGraph = new ModuleGraph();
  991. /** @type {ChunkGraph} */
  992. this.chunkGraph = new ChunkGraph(
  993. this.moduleGraph,
  994. this.outputOptions.hashFunction
  995. );
  996. /** @type {CodeGenerationResults | undefined} */
  997. this.codeGenerationResults = undefined;
  998. /** @type {AsyncQueue<Module, Module, Module>} */
  999. this.processDependenciesQueue = new AsyncQueue({
  1000. name: "processDependencies",
  1001. parallelism: options.parallelism || 100,
  1002. processor: this._processModuleDependencies.bind(this)
  1003. });
  1004. /** @type {AsyncQueue<Module, string, Module>} */
  1005. this.addModuleQueue = new AsyncQueue({
  1006. name: "addModule",
  1007. parent: this.processDependenciesQueue,
  1008. getKey: (module) => module.identifier(),
  1009. processor: this._addModule.bind(this)
  1010. });
  1011. /** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */
  1012. this.factorizeQueue = new AsyncQueue({
  1013. name: "factorize",
  1014. parent: this.addModuleQueue,
  1015. processor: this._factorizeModule.bind(this)
  1016. });
  1017. /** @type {AsyncQueue<Module, Module, Module>} */
  1018. this.buildQueue = new AsyncQueue({
  1019. name: "build",
  1020. parent: this.factorizeQueue,
  1021. processor: this._buildModule.bind(this)
  1022. });
  1023. /** @type {AsyncQueue<Module, Module, Module>} */
  1024. this.rebuildQueue = new AsyncQueue({
  1025. name: "rebuild",
  1026. parallelism: options.parallelism || 100,
  1027. processor: this._rebuildModule.bind(this)
  1028. });
  1029. /**
  1030. * Modules in value are building during the build of Module in key.
  1031. * Means value blocking key from finishing.
  1032. * Needed to detect build cycles.
  1033. * @type {WeakMap<Module, Set<Module>>}
  1034. */
  1035. this.creatingModuleDuringBuild = new WeakMap();
  1036. /** @type {Map<Exclude<ChunkName, null>, EntryData>} */
  1037. this.entries = new Map();
  1038. /** @type {EntryData} */
  1039. this.globalEntry = {
  1040. dependencies: [],
  1041. includeDependencies: [],
  1042. options: {
  1043. name: undefined
  1044. }
  1045. };
  1046. /** @type {Map<string, Entrypoint>} */
  1047. this.entrypoints = new Map();
  1048. /** @type {Entrypoint[]} */
  1049. this.asyncEntrypoints = [];
  1050. /** @type {Chunks} */
  1051. this.chunks = new Set();
  1052. /** @type {ChunkGroup[]} */
  1053. this.chunkGroups = [];
  1054. /** @type {Map<string, ChunkGroup>} */
  1055. this.namedChunkGroups = new Map();
  1056. /** @type {Map<string, Chunk>} */
  1057. this.namedChunks = new Map();
  1058. /** @type {Set<Module>} */
  1059. this.modules = new Set();
  1060. if (this._backCompat) {
  1061. arrayToSetDeprecation(this.chunks, "Compilation.chunks");
  1062. arrayToSetDeprecation(this.modules, "Compilation.modules");
  1063. }
  1064. /**
  1065. * @private
  1066. * @type {Map<string, Module>}
  1067. */
  1068. this._modules = new Map();
  1069. /** @type {Records | null} */
  1070. this.records = null;
  1071. /** @type {string[]} */
  1072. this.additionalChunkAssets = [];
  1073. /** @type {CompilationAssets} */
  1074. this.assets = {};
  1075. /** @type {Map<string, AssetInfo>} */
  1076. this.assetsInfo = new Map();
  1077. /** @type {Map<string, Map<string, Set<string>>>} */
  1078. this._assetsRelatedIn = new Map();
  1079. /** @type {Error[]} */
  1080. this.errors = [];
  1081. /** @type {Error[]} */
  1082. this.warnings = [];
  1083. /** @type {Compilation[]} */
  1084. this.children = [];
  1085. /** @type {Map<string, LogEntry[]>} */
  1086. this.logging = new Map();
  1087. /** @type {Map<DependencyConstructor, ModuleFactory>} */
  1088. this.dependencyFactories = new Map();
  1089. /** @type {DependencyTemplates} */
  1090. this.dependencyTemplates = new DependencyTemplates(
  1091. this.outputOptions.hashFunction
  1092. );
  1093. /** @type {Record<string, number>} */
  1094. this.childrenCounters = {};
  1095. /** @type {Set<number> | null} */
  1096. this.usedChunkIds = null;
  1097. /** @type {Set<number> | null} */
  1098. this.usedModuleIds = null;
  1099. /** @type {boolean} */
  1100. this.needAdditionalPass = false;
  1101. /** @type {Set<ModuleWithRestoreFromUnsafeCache>} */
  1102. this._restoredUnsafeCacheModuleEntries = new Set();
  1103. /** @type {Map<string, ModuleWithRestoreFromUnsafeCache>} */
  1104. this._restoredUnsafeCacheEntries = new Map();
  1105. /** @type {WeakSet<Module>} */
  1106. this.builtModules = new WeakSet();
  1107. /** @type {WeakSet<Module>} */
  1108. this.codeGeneratedModules = new WeakSet();
  1109. /** @type {WeakSet<Module>} */
  1110. this.buildTimeExecutedModules = new WeakSet();
  1111. /** @type {Set<string>} */
  1112. this.emittedAssets = new Set();
  1113. /** @type {Set<string>} */
  1114. this.comparedForEmitAssets = new Set();
  1115. /** @type {LazySet<string>} */
  1116. this.fileDependencies = new LazySet();
  1117. /** @type {LazySet<string>} */
  1118. this.contextDependencies = new LazySet();
  1119. /** @type {LazySet<string>} */
  1120. this.missingDependencies = new LazySet();
  1121. /** @type {LazySet<string>} */
  1122. this.buildDependencies = new LazySet();
  1123. // TODO webpack 6 remove
  1124. this.compilationDependencies = {
  1125. add: util.deprecate(
  1126. /**
  1127. * @param {string} item item
  1128. * @returns {LazySet<string>} file dependencies
  1129. */
  1130. (item) => this.fileDependencies.add(item),
  1131. "Compilation.compilationDependencies is deprecated (used Compilation.fileDependencies instead)",
  1132. "DEP_WEBPACK_COMPILATION_COMPILATION_DEPENDENCIES"
  1133. )
  1134. };
  1135. this._modulesCache = this.getCache("Compilation/modules");
  1136. this._assetsCache = this.getCache("Compilation/assets");
  1137. this._codeGenerationCache = this.getCache("Compilation/codeGeneration");
  1138. const unsafeCache = options.module.unsafeCache;
  1139. this._unsafeCache = Boolean(unsafeCache);
  1140. this._unsafeCachePredicate =
  1141. typeof unsafeCache === "function" ? unsafeCache : () => true;
  1142. }
  1143. getStats() {
  1144. return new Stats(this);
  1145. }
  1146. /**
  1147. * @param {string | boolean | StatsOptions | undefined} optionsOrPreset stats option value
  1148. * @param {CreateStatsOptionsContext=} context context
  1149. * @returns {NormalizedStatsOptions} normalized options
  1150. */
  1151. createStatsOptions(optionsOrPreset, context = {}) {
  1152. if (typeof optionsOrPreset === "boolean") {
  1153. optionsOrPreset = {
  1154. preset: optionsOrPreset === false ? "none" : "normal"
  1155. };
  1156. } else if (typeof optionsOrPreset === "string") {
  1157. optionsOrPreset = { preset: optionsOrPreset };
  1158. }
  1159. if (typeof optionsOrPreset === "object" && optionsOrPreset !== null) {
  1160. // We use this method of shallow cloning this object to include
  1161. // properties in the prototype chain
  1162. /** @type {Partial<NormalizedStatsOptions>} */
  1163. const options = {};
  1164. for (const key in optionsOrPreset) {
  1165. options[key] = optionsOrPreset[/** @type {keyof StatsOptions} */ (key)];
  1166. }
  1167. if (options.preset !== undefined) {
  1168. this.hooks.statsPreset.for(options.preset).call(options, context);
  1169. }
  1170. this.hooks.statsNormalize.call(options, context);
  1171. return /** @type {NormalizedStatsOptions} */ (options);
  1172. }
  1173. /** @type {Partial<NormalizedStatsOptions>} */
  1174. const options = {};
  1175. this.hooks.statsNormalize.call(options, context);
  1176. return /** @type {NormalizedStatsOptions} */ (options);
  1177. }
  1178. /**
  1179. * @param {NormalizedStatsOptions} options options
  1180. * @returns {StatsFactory} the stats factory
  1181. */
  1182. createStatsFactory(options) {
  1183. const statsFactory = new StatsFactory();
  1184. this.hooks.statsFactory.call(statsFactory, options);
  1185. return statsFactory;
  1186. }
  1187. /**
  1188. * @param {NormalizedStatsOptions} options options
  1189. * @returns {StatsPrinter} the stats printer
  1190. */
  1191. createStatsPrinter(options) {
  1192. const statsPrinter = new StatsPrinter();
  1193. this.hooks.statsPrinter.call(statsPrinter, options);
  1194. return statsPrinter;
  1195. }
  1196. /**
  1197. * @param {string} name cache name
  1198. * @returns {CacheFacade} the cache facade instance
  1199. */
  1200. getCache(name) {
  1201. return this.compiler.getCache(name);
  1202. }
  1203. /**
  1204. * @param {string | (() => string)} name name of the logger, or function called once to get the logger name
  1205. * @returns {Logger} a logger with that name
  1206. */
  1207. getLogger(name) {
  1208. if (!name) {
  1209. throw new TypeError("Compilation.getLogger(name) called without a name");
  1210. }
  1211. /** @type {LogEntry[] | undefined} */
  1212. let logEntries;
  1213. return new Logger(
  1214. (type, args) => {
  1215. if (typeof name === "function") {
  1216. name = name();
  1217. if (!name) {
  1218. throw new TypeError(
  1219. "Compilation.getLogger(name) called with a function not returning a name"
  1220. );
  1221. }
  1222. }
  1223. let trace;
  1224. switch (type) {
  1225. case LogType.warn:
  1226. case LogType.error:
  1227. case LogType.trace:
  1228. trace = ErrorHelpers.cutOffLoaderExecution(
  1229. /** @type {string} */ (new Error("Trace").stack)
  1230. )
  1231. .split("\n")
  1232. .slice(3);
  1233. break;
  1234. }
  1235. /** @type {LogEntry} */
  1236. const logEntry = {
  1237. time: Date.now(),
  1238. type,
  1239. args,
  1240. trace
  1241. };
  1242. /* eslint-disable no-console */
  1243. if (this.hooks.log.call(name, logEntry) === undefined) {
  1244. if (
  1245. logEntry.type === LogType.profileEnd &&
  1246. typeof console.profileEnd === "function"
  1247. ) {
  1248. console.profileEnd(
  1249. `[${name}] ${/** @type {NonNullable<LogEntry["args"]>} */ (logEntry.args)[0]}`
  1250. );
  1251. }
  1252. if (logEntries === undefined) {
  1253. logEntries = this.logging.get(name);
  1254. if (logEntries === undefined) {
  1255. logEntries = [];
  1256. this.logging.set(name, logEntries);
  1257. }
  1258. }
  1259. logEntries.push(logEntry);
  1260. if (
  1261. logEntry.type === LogType.profile &&
  1262. typeof console.profile === "function"
  1263. ) {
  1264. console.profile(
  1265. `[${name}] ${
  1266. /** @type {NonNullable<LogEntry["args"]>} */
  1267. (logEntry.args)[0]
  1268. }`
  1269. );
  1270. }
  1271. /* eslint-enable no-console */
  1272. }
  1273. },
  1274. (childName) => {
  1275. if (typeof name === "function") {
  1276. if (typeof childName === "function") {
  1277. return this.getLogger(() => {
  1278. if (typeof name === "function") {
  1279. name = name();
  1280. if (!name) {
  1281. throw new TypeError(
  1282. "Compilation.getLogger(name) called with a function not returning a name"
  1283. );
  1284. }
  1285. }
  1286. if (typeof childName === "function") {
  1287. childName = childName();
  1288. if (!childName) {
  1289. throw new TypeError(
  1290. "Logger.getChildLogger(name) called with a function not returning a name"
  1291. );
  1292. }
  1293. }
  1294. return `${name}/${childName}`;
  1295. });
  1296. }
  1297. return this.getLogger(() => {
  1298. if (typeof name === "function") {
  1299. name = name();
  1300. if (!name) {
  1301. throw new TypeError(
  1302. "Compilation.getLogger(name) called with a function not returning a name"
  1303. );
  1304. }
  1305. }
  1306. return `${name}/${childName}`;
  1307. });
  1308. }
  1309. if (typeof childName === "function") {
  1310. return this.getLogger(() => {
  1311. if (typeof childName === "function") {
  1312. childName = childName();
  1313. if (!childName) {
  1314. throw new TypeError(
  1315. "Logger.getChildLogger(name) called with a function not returning a name"
  1316. );
  1317. }
  1318. }
  1319. return `${name}/${childName}`;
  1320. });
  1321. }
  1322. return this.getLogger(`${name}/${childName}`);
  1323. }
  1324. );
  1325. }
  1326. /**
  1327. * @param {Module} module module to be added that was created
  1328. * @param {ModuleCallback} callback returns the module in the compilation,
  1329. * it could be the passed one (if new), or an already existing in the compilation
  1330. * @returns {void}
  1331. */
  1332. addModule(module, callback) {
  1333. this.addModuleQueue.add(module, callback);
  1334. }
  1335. /**
  1336. * @param {Module} module module to be added that was created
  1337. * @param {ModuleCallback} callback returns the module in the compilation,
  1338. * it could be the passed one (if new), or an already existing in the compilation
  1339. * @returns {void}
  1340. */
  1341. _addModule(module, callback) {
  1342. const identifier = module.identifier();
  1343. const alreadyAddedModule = this._modules.get(identifier);
  1344. if (alreadyAddedModule) {
  1345. return callback(null, alreadyAddedModule);
  1346. }
  1347. const currentProfile = this.profile
  1348. ? this.moduleGraph.getProfile(module)
  1349. : undefined;
  1350. if (currentProfile !== undefined) {
  1351. currentProfile.markRestoringStart();
  1352. }
  1353. this._modulesCache.get(identifier, null, (err, cacheModule) => {
  1354. if (err) return callback(new ModuleRestoreError(module, err));
  1355. if (currentProfile !== undefined) {
  1356. currentProfile.markRestoringEnd();
  1357. currentProfile.markIntegrationStart();
  1358. }
  1359. if (cacheModule) {
  1360. cacheModule.updateCacheModule(module);
  1361. module = cacheModule;
  1362. }
  1363. this._modules.set(identifier, module);
  1364. this.modules.add(module);
  1365. if (this._backCompat) {
  1366. ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
  1367. }
  1368. if (currentProfile !== undefined) {
  1369. currentProfile.markIntegrationEnd();
  1370. }
  1371. callback(null, module);
  1372. });
  1373. }
  1374. /**
  1375. * Fetches a module from a compilation by its identifier
  1376. * @param {Module} module the module provided
  1377. * @returns {Module} the module requested
  1378. */
  1379. getModule(module) {
  1380. const identifier = module.identifier();
  1381. return /** @type {Module} */ (this._modules.get(identifier));
  1382. }
  1383. /**
  1384. * Attempts to search for a module by its identifier
  1385. * @param {string} identifier identifier (usually path) for module
  1386. * @returns {Module|undefined} attempt to search for module and return it, else undefined
  1387. */
  1388. findModule(identifier) {
  1389. return this._modules.get(identifier);
  1390. }
  1391. /**
  1392. * Schedules a build of the module object
  1393. * @param {Module} module module to be built
  1394. * @param {ModuleCallback} callback the callback
  1395. * @returns {void}
  1396. */
  1397. buildModule(module, callback) {
  1398. this.buildQueue.add(module, callback);
  1399. }
  1400. /**
  1401. * Builds the module object
  1402. * @param {Module} module module to be built
  1403. * @param {ModuleCallback} callback the callback
  1404. * @returns {void}
  1405. */
  1406. _buildModule(module, callback) {
  1407. const currentProfile = this.profile
  1408. ? this.moduleGraph.getProfile(module)
  1409. : undefined;
  1410. if (currentProfile !== undefined) {
  1411. currentProfile.markBuildingStart();
  1412. }
  1413. module.needBuild(
  1414. {
  1415. compilation: this,
  1416. fileSystemInfo: this.fileSystemInfo,
  1417. valueCacheVersions: this.valueCacheVersions
  1418. },
  1419. (err, needBuild) => {
  1420. if (err) return callback(err);
  1421. if (!needBuild) {
  1422. if (currentProfile !== undefined) {
  1423. currentProfile.markBuildingEnd();
  1424. }
  1425. this.hooks.stillValidModule.call(module);
  1426. return callback();
  1427. }
  1428. this.hooks.buildModule.call(module);
  1429. this.builtModules.add(module);
  1430. module.build(
  1431. this.options,
  1432. this,
  1433. this.resolverFactory.get("normal", module.resolveOptions),
  1434. /** @type {InputFileSystem} */
  1435. (this.inputFileSystem),
  1436. (err) => {
  1437. if (currentProfile !== undefined) {
  1438. currentProfile.markBuildingEnd();
  1439. }
  1440. if (err) {
  1441. this.hooks.failedModule.call(module, err);
  1442. return callback(err);
  1443. }
  1444. if (currentProfile !== undefined) {
  1445. currentProfile.markStoringStart();
  1446. }
  1447. this._modulesCache.store(
  1448. module.identifier(),
  1449. null,
  1450. module,
  1451. (err) => {
  1452. if (currentProfile !== undefined) {
  1453. currentProfile.markStoringEnd();
  1454. }
  1455. if (err) {
  1456. this.hooks.failedModule.call(
  1457. module,
  1458. /** @type {WebpackError} */ (err)
  1459. );
  1460. return callback(new ModuleStoreError(module, err));
  1461. }
  1462. this.hooks.succeedModule.call(module);
  1463. return callback();
  1464. }
  1465. );
  1466. }
  1467. );
  1468. }
  1469. );
  1470. }
  1471. /**
  1472. * @param {Module} module to be processed for deps
  1473. * @param {ModuleCallback} callback callback to be triggered
  1474. * @returns {void}
  1475. */
  1476. processModuleDependencies(module, callback) {
  1477. this.processDependenciesQueue.add(module, callback);
  1478. }
  1479. /**
  1480. * @param {Module} module to be processed for deps
  1481. * @returns {void}
  1482. */
  1483. processModuleDependenciesNonRecursive(module) {
  1484. /**
  1485. * @param {DependenciesBlock} block block
  1486. */
  1487. const processDependenciesBlock = (block) => {
  1488. if (block.dependencies) {
  1489. let i = 0;
  1490. for (const dep of block.dependencies) {
  1491. this.moduleGraph.setParents(dep, block, module, i++);
  1492. }
  1493. }
  1494. if (block.blocks) {
  1495. for (const b of block.blocks) processDependenciesBlock(b);
  1496. }
  1497. };
  1498. processDependenciesBlock(module);
  1499. }
  1500. /**
  1501. * @param {Module} module to be processed for deps
  1502. * @param {ModuleCallback} callback callback to be triggered
  1503. * @returns {void}
  1504. */
  1505. _processModuleDependencies(module, callback) {
  1506. /** @type {{ factory: ModuleFactory, dependencies: Dependency[], context: string | undefined, originModule: Module | null }[]} */
  1507. const sortedDependencies = [];
  1508. /** @type {DependenciesBlock} */
  1509. let currentBlock;
  1510. /** @type {Map<ModuleFactory, Map<string, Dependency[]>>} */
  1511. let dependencies;
  1512. /** @type {DependencyConstructor} */
  1513. let factoryCacheKey;
  1514. /** @type {ModuleFactory} */
  1515. let factoryCacheKey2;
  1516. /** @typedef {Map<string, Dependency[]>} FactoryCacheValue */
  1517. /** @type {FactoryCacheValue | undefined} */
  1518. let factoryCacheValue;
  1519. /** @type {string} */
  1520. let listCacheKey1;
  1521. /** @type {string} */
  1522. let listCacheKey2;
  1523. /** @type {Dependency[]} */
  1524. let listCacheValue;
  1525. let inProgressSorting = 1;
  1526. let inProgressTransitive = 1;
  1527. /**
  1528. * @param {WebpackError=} err error
  1529. * @returns {void}
  1530. */
  1531. const onDependenciesSorted = (err) => {
  1532. if (err) return callback(err);
  1533. // early exit without changing parallelism back and forth
  1534. if (sortedDependencies.length === 0 && inProgressTransitive === 1) {
  1535. return callback();
  1536. }
  1537. // This is nested so we need to allow one additional task
  1538. this.processDependenciesQueue.increaseParallelism();
  1539. for (const item of sortedDependencies) {
  1540. inProgressTransitive++;
  1541. // eslint-disable-next-line no-loop-func
  1542. this.handleModuleCreation(item, (err) => {
  1543. // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
  1544. // errors are created inside closures that keep a reference to the Compilation, so errors are
  1545. // leaking the Compilation object.
  1546. if (err && this.bail) {
  1547. if (inProgressTransitive <= 0) return;
  1548. inProgressTransitive = -1;
  1549. // eslint-disable-next-line no-self-assign
  1550. err.stack = err.stack;
  1551. onTransitiveTasksFinished(err);
  1552. return;
  1553. }
  1554. if (--inProgressTransitive === 0) onTransitiveTasksFinished();
  1555. });
  1556. }
  1557. if (--inProgressTransitive === 0) onTransitiveTasksFinished();
  1558. };
  1559. /**
  1560. * @param {WebpackError=} err error
  1561. * @returns {void}
  1562. */
  1563. const onTransitiveTasksFinished = (err) => {
  1564. if (err) return callback(err);
  1565. this.processDependenciesQueue.decreaseParallelism();
  1566. return callback();
  1567. };
  1568. /**
  1569. * @param {Dependency} dep dependency
  1570. * @param {number} index index in block
  1571. * @returns {void}
  1572. */
  1573. const processDependency = (dep, index) => {
  1574. this.moduleGraph.setParents(dep, currentBlock, module, index);
  1575. if (this._unsafeCache) {
  1576. try {
  1577. const unsafeCachedModule = unsafeCacheDependencies.get(dep);
  1578. if (unsafeCachedModule === null) return;
  1579. if (unsafeCachedModule !== undefined) {
  1580. if (
  1581. this._restoredUnsafeCacheModuleEntries.has(unsafeCachedModule)
  1582. ) {
  1583. this._handleExistingModuleFromUnsafeCache(
  1584. module,
  1585. dep,
  1586. unsafeCachedModule
  1587. );
  1588. return;
  1589. }
  1590. const identifier = unsafeCachedModule.identifier();
  1591. const cachedModule =
  1592. this._restoredUnsafeCacheEntries.get(identifier);
  1593. if (cachedModule !== undefined) {
  1594. // update unsafe cache to new module
  1595. unsafeCacheDependencies.set(dep, cachedModule);
  1596. this._handleExistingModuleFromUnsafeCache(
  1597. module,
  1598. dep,
  1599. cachedModule
  1600. );
  1601. return;
  1602. }
  1603. inProgressSorting++;
  1604. this._modulesCache.get(identifier, null, (err, cachedModule) => {
  1605. if (err) {
  1606. if (inProgressSorting <= 0) return;
  1607. inProgressSorting = -1;
  1608. onDependenciesSorted(/** @type {WebpackError} */ (err));
  1609. return;
  1610. }
  1611. try {
  1612. if (!this._restoredUnsafeCacheEntries.has(identifier)) {
  1613. const data = unsafeCacheData.get(cachedModule);
  1614. if (data === undefined) {
  1615. processDependencyForResolving(dep);
  1616. if (--inProgressSorting === 0) onDependenciesSorted();
  1617. return;
  1618. }
  1619. if (cachedModule !== unsafeCachedModule) {
  1620. unsafeCacheDependencies.set(dep, cachedModule);
  1621. }
  1622. cachedModule.restoreFromUnsafeCache(
  1623. data,
  1624. this.params.normalModuleFactory,
  1625. this.params
  1626. );
  1627. this._restoredUnsafeCacheEntries.set(
  1628. identifier,
  1629. cachedModule
  1630. );
  1631. this._restoredUnsafeCacheModuleEntries.add(cachedModule);
  1632. if (!this.modules.has(cachedModule)) {
  1633. inProgressTransitive++;
  1634. this._handleNewModuleFromUnsafeCache(
  1635. module,
  1636. dep,
  1637. cachedModule,
  1638. (err) => {
  1639. if (err) {
  1640. if (inProgressTransitive <= 0) return;
  1641. inProgressTransitive = -1;
  1642. onTransitiveTasksFinished(err);
  1643. }
  1644. if (--inProgressTransitive === 0) {
  1645. return onTransitiveTasksFinished();
  1646. }
  1647. }
  1648. );
  1649. if (--inProgressSorting === 0) onDependenciesSorted();
  1650. return;
  1651. }
  1652. }
  1653. if (unsafeCachedModule !== cachedModule) {
  1654. unsafeCacheDependencies.set(dep, cachedModule);
  1655. }
  1656. this._handleExistingModuleFromUnsafeCache(
  1657. module,
  1658. dep,
  1659. cachedModule
  1660. ); // a3
  1661. } catch (err) {
  1662. if (inProgressSorting <= 0) return;
  1663. inProgressSorting = -1;
  1664. onDependenciesSorted(/** @type {WebpackError} */ (err));
  1665. return;
  1666. }
  1667. if (--inProgressSorting === 0) onDependenciesSorted();
  1668. });
  1669. return;
  1670. }
  1671. } catch (err) {
  1672. // eslint-disable-next-line no-console
  1673. console.error(err);
  1674. }
  1675. }
  1676. processDependencyForResolving(dep);
  1677. };
  1678. /**
  1679. * @param {Dependency} dep dependency
  1680. * @returns {void}
  1681. */
  1682. const processDependencyForResolving = (dep) => {
  1683. const resourceIdent = dep.getResourceIdentifier();
  1684. if (resourceIdent !== undefined && resourceIdent !== null) {
  1685. const category = dep.category;
  1686. const constructor =
  1687. /** @type {DependencyConstructor} */
  1688. (dep.constructor);
  1689. if (factoryCacheKey === constructor) {
  1690. // Fast path 1: same constructor as prev item
  1691. if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
  1692. // Super fast path 1: also same resource
  1693. listCacheValue.push(dep);
  1694. return;
  1695. }
  1696. } else {
  1697. const factory = this.dependencyFactories.get(constructor);
  1698. if (factory === undefined) {
  1699. throw new Error(
  1700. `No module factory available for dependency type: ${constructor.name}`
  1701. );
  1702. }
  1703. if (factoryCacheKey2 === factory) {
  1704. // Fast path 2: same factory as prev item
  1705. factoryCacheKey = constructor;
  1706. if (listCacheKey1 === category && listCacheKey2 === resourceIdent) {
  1707. // Super fast path 2: also same resource
  1708. listCacheValue.push(dep);
  1709. return;
  1710. }
  1711. } else {
  1712. // Slow path
  1713. if (factoryCacheKey2 !== undefined) {
  1714. // Archive last cache entry
  1715. if (dependencies === undefined) dependencies = new Map();
  1716. dependencies.set(
  1717. factoryCacheKey2,
  1718. /** @type {FactoryCacheValue} */ (factoryCacheValue)
  1719. );
  1720. factoryCacheValue = dependencies.get(factory);
  1721. if (factoryCacheValue === undefined) {
  1722. factoryCacheValue = new Map();
  1723. }
  1724. } else {
  1725. factoryCacheValue = new Map();
  1726. }
  1727. factoryCacheKey = constructor;
  1728. factoryCacheKey2 = factory;
  1729. }
  1730. }
  1731. // Here webpack is using heuristic that assumes
  1732. // mostly esm dependencies would be used
  1733. // so we don't allocate extra string for them
  1734. const cacheKey =
  1735. category === esmDependencyCategory
  1736. ? resourceIdent
  1737. : `${category}${resourceIdent}`;
  1738. let list = /** @type {FactoryCacheValue} */ (factoryCacheValue).get(
  1739. cacheKey
  1740. );
  1741. if (list === undefined) {
  1742. /** @type {FactoryCacheValue} */
  1743. (factoryCacheValue).set(cacheKey, (list = []));
  1744. sortedDependencies.push({
  1745. factory: factoryCacheKey2,
  1746. dependencies: list,
  1747. context: dep.getContext(),
  1748. originModule: module
  1749. });
  1750. }
  1751. list.push(dep);
  1752. listCacheKey1 = category;
  1753. listCacheKey2 = resourceIdent;
  1754. listCacheValue = list;
  1755. }
  1756. };
  1757. try {
  1758. /** @type {DependenciesBlock[]} */
  1759. const queue = [module];
  1760. do {
  1761. const block = /** @type {DependenciesBlock} */ (queue.pop());
  1762. if (block.dependencies) {
  1763. currentBlock = block;
  1764. let i = 0;
  1765. for (const dep of block.dependencies) processDependency(dep, i++);
  1766. }
  1767. if (block.blocks) {
  1768. for (const b of block.blocks) queue.push(b);
  1769. }
  1770. } while (queue.length !== 0);
  1771. } catch (err) {
  1772. return callback(/** @type {WebpackError} */ (err));
  1773. }
  1774. if (--inProgressSorting === 0) onDependenciesSorted();
  1775. }
  1776. /**
  1777. * @private
  1778. * @param {Module} originModule original module
  1779. * @param {Dependency} dependency dependency
  1780. * @param {Module} module cached module
  1781. * @param {Callback} callback callback
  1782. */
  1783. _handleNewModuleFromUnsafeCache(originModule, dependency, module, callback) {
  1784. const moduleGraph = this.moduleGraph;
  1785. moduleGraph.setResolvedModule(originModule, dependency, module);
  1786. moduleGraph.setIssuerIfUnset(
  1787. module,
  1788. originModule !== undefined ? originModule : null
  1789. );
  1790. this._modules.set(module.identifier(), module);
  1791. this.modules.add(module);
  1792. if (this._backCompat) {
  1793. ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
  1794. }
  1795. this._handleModuleBuildAndDependencies(
  1796. originModule,
  1797. module,
  1798. true,
  1799. false,
  1800. callback
  1801. );
  1802. }
  1803. /**
  1804. * @private
  1805. * @param {Module} originModule original modules
  1806. * @param {Dependency} dependency dependency
  1807. * @param {Module} module cached module
  1808. */
  1809. _handleExistingModuleFromUnsafeCache(originModule, dependency, module) {
  1810. const moduleGraph = this.moduleGraph;
  1811. moduleGraph.setResolvedModule(originModule, dependency, module);
  1812. }
  1813. /**
  1814. * @param {FactorizeModuleOptions} options options
  1815. * @param {ModuleOrModuleFactoryResultCallback} callback callback
  1816. * @returns {void}
  1817. */
  1818. _factorizeModule(
  1819. {
  1820. currentProfile,
  1821. factory,
  1822. dependencies,
  1823. originModule,
  1824. factoryResult,
  1825. contextInfo,
  1826. context
  1827. },
  1828. callback
  1829. ) {
  1830. if (currentProfile !== undefined) {
  1831. currentProfile.markFactoryStart();
  1832. }
  1833. factory.create(
  1834. {
  1835. contextInfo: {
  1836. issuer: originModule
  1837. ? /** @type {NameForCondition} */ (originModule.nameForCondition())
  1838. : "",
  1839. issuerLayer: originModule ? originModule.layer : null,
  1840. compiler: this.compiler.name,
  1841. ...contextInfo
  1842. },
  1843. resolveOptions: originModule ? originModule.resolveOptions : undefined,
  1844. context:
  1845. context ||
  1846. (originModule
  1847. ? /** @type {string} */ (originModule.context)
  1848. : this.compiler.context),
  1849. dependencies
  1850. },
  1851. (err, result) => {
  1852. if (result) {
  1853. // TODO webpack 6: remove
  1854. // For backward-compat
  1855. if (result.module === undefined && result instanceof Module) {
  1856. result = {
  1857. module: result
  1858. };
  1859. }
  1860. if (!factoryResult) {
  1861. const {
  1862. fileDependencies,
  1863. contextDependencies,
  1864. missingDependencies
  1865. } = result;
  1866. if (fileDependencies) {
  1867. this.fileDependencies.addAll(fileDependencies);
  1868. }
  1869. if (contextDependencies) {
  1870. this.contextDependencies.addAll(contextDependencies);
  1871. }
  1872. if (missingDependencies) {
  1873. this.missingDependencies.addAll(missingDependencies);
  1874. }
  1875. }
  1876. }
  1877. if (err) {
  1878. const notFoundError = new ModuleNotFoundError(
  1879. originModule,
  1880. err,
  1881. /** @type {DependencyLocation} */
  1882. (dependencies.map((d) => d.loc).find(Boolean))
  1883. );
  1884. return callback(notFoundError, factoryResult ? result : undefined);
  1885. }
  1886. if (!result) {
  1887. return callback();
  1888. }
  1889. if (currentProfile !== undefined) {
  1890. currentProfile.markFactoryEnd();
  1891. }
  1892. callback(null, factoryResult ? result : result.module);
  1893. }
  1894. );
  1895. }
  1896. /**
  1897. * @overload
  1898. * @param {FactorizeModuleOptions & { factoryResult?: false }} options options
  1899. * @param {ModuleCallback} callback callback
  1900. * @returns {void}
  1901. */
  1902. /**
  1903. * @overload
  1904. * @param {FactorizeModuleOptions & { factoryResult: true }} options options
  1905. * @param {ModuleFactoryResultCallback} callback callback
  1906. * @returns {void}
  1907. */
  1908. /**
  1909. * @param {FactorizeModuleOptions & { factoryResult?: false } | FactorizeModuleOptions & { factoryResult: true }} options options
  1910. * @param {ModuleCallback | ModuleFactoryResultCallback} callback callback
  1911. */
  1912. factorizeModule(options, callback) {
  1913. this.factorizeQueue.add(
  1914. options,
  1915. /** @type {ModuleOrModuleFactoryResultCallback} */
  1916. (callback)
  1917. );
  1918. }
  1919. /**
  1920. * @typedef {object} HandleModuleCreationOptions
  1921. * @property {ModuleFactory} factory
  1922. * @property {Dependency[]} dependencies
  1923. * @property {Module | null} originModule
  1924. * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
  1925. * @property {string=} context
  1926. * @property {boolean=} recursive recurse into dependencies of the created module
  1927. * @property {boolean=} connectOrigin connect the resolved module with the origin module
  1928. * @property {boolean=} checkCycle check the cycle dependencies of the created module
  1929. */
  1930. /**
  1931. * @param {HandleModuleCreationOptions} options options object
  1932. * @param {ModuleCallback} callback callback
  1933. * @returns {void}
  1934. */
  1935. handleModuleCreation(
  1936. {
  1937. factory,
  1938. dependencies,
  1939. originModule,
  1940. contextInfo,
  1941. context,
  1942. recursive = true,
  1943. connectOrigin = recursive,
  1944. checkCycle = !recursive
  1945. },
  1946. callback
  1947. ) {
  1948. const moduleGraph = this.moduleGraph;
  1949. const currentProfile = this.profile ? new ModuleProfile() : undefined;
  1950. this.factorizeModule(
  1951. {
  1952. currentProfile,
  1953. factory,
  1954. dependencies,
  1955. factoryResult: true,
  1956. originModule,
  1957. contextInfo,
  1958. context
  1959. },
  1960. (err, factoryResult) => {
  1961. const applyFactoryResultDependencies = () => {
  1962. const { fileDependencies, contextDependencies, missingDependencies } =
  1963. /** @type {ModuleFactoryResult} */ (factoryResult);
  1964. if (fileDependencies) {
  1965. this.fileDependencies.addAll(fileDependencies);
  1966. }
  1967. if (contextDependencies) {
  1968. this.contextDependencies.addAll(contextDependencies);
  1969. }
  1970. if (missingDependencies) {
  1971. this.missingDependencies.addAll(missingDependencies);
  1972. }
  1973. };
  1974. if (err) {
  1975. if (factoryResult) applyFactoryResultDependencies();
  1976. if (dependencies.every((d) => d.optional)) {
  1977. this.warnings.push(err);
  1978. return callback();
  1979. }
  1980. this.errors.push(err);
  1981. return callback(err);
  1982. }
  1983. const newModule =
  1984. /** @type {ModuleFactoryResult} */
  1985. (factoryResult).module;
  1986. if (!newModule) {
  1987. applyFactoryResultDependencies();
  1988. return callback();
  1989. }
  1990. if (currentProfile !== undefined) {
  1991. moduleGraph.setProfile(newModule, currentProfile);
  1992. }
  1993. this.addModule(newModule, (err, _module) => {
  1994. if (err) {
  1995. applyFactoryResultDependencies();
  1996. if (!err.module) {
  1997. err.module = _module;
  1998. }
  1999. this.errors.push(err);
  2000. return callback(err);
  2001. }
  2002. const module =
  2003. /** @type {ModuleWithRestoreFromUnsafeCache} */
  2004. (_module);
  2005. if (
  2006. this._unsafeCache &&
  2007. /** @type {ModuleFactoryResult} */
  2008. (factoryResult).cacheable !== false &&
  2009. module.restoreFromUnsafeCache &&
  2010. this._unsafeCachePredicate(module)
  2011. ) {
  2012. const unsafeCacheableModule =
  2013. /** @type {ModuleWithRestoreFromUnsafeCache} */
  2014. (module);
  2015. for (const dependency of dependencies) {
  2016. moduleGraph.setResolvedModule(
  2017. connectOrigin ? originModule : null,
  2018. dependency,
  2019. unsafeCacheableModule
  2020. );
  2021. unsafeCacheDependencies.set(dependency, unsafeCacheableModule);
  2022. }
  2023. if (!unsafeCacheData.has(unsafeCacheableModule)) {
  2024. unsafeCacheData.set(
  2025. unsafeCacheableModule,
  2026. unsafeCacheableModule.getUnsafeCacheData()
  2027. );
  2028. }
  2029. } else {
  2030. applyFactoryResultDependencies();
  2031. for (const dependency of dependencies) {
  2032. moduleGraph.setResolvedModule(
  2033. connectOrigin ? originModule : null,
  2034. dependency,
  2035. module
  2036. );
  2037. }
  2038. }
  2039. moduleGraph.setIssuerIfUnset(
  2040. module,
  2041. originModule !== undefined ? originModule : null
  2042. );
  2043. if (module !== newModule && currentProfile !== undefined) {
  2044. const otherProfile = moduleGraph.getProfile(module);
  2045. if (otherProfile !== undefined) {
  2046. currentProfile.mergeInto(otherProfile);
  2047. } else {
  2048. moduleGraph.setProfile(module, currentProfile);
  2049. }
  2050. }
  2051. this._handleModuleBuildAndDependencies(
  2052. originModule,
  2053. module,
  2054. recursive,
  2055. checkCycle,
  2056. callback
  2057. );
  2058. });
  2059. }
  2060. );
  2061. }
  2062. /**
  2063. * @private
  2064. * @param {Module | null} originModule original module
  2065. * @param {Module} module module
  2066. * @param {boolean} recursive true if make it recursive, otherwise false
  2067. * @param {boolean} checkCycle true if need to check cycle, otherwise false
  2068. * @param {ModuleCallback} callback callback
  2069. * @returns {void}
  2070. */
  2071. _handleModuleBuildAndDependencies(
  2072. originModule,
  2073. module,
  2074. recursive,
  2075. checkCycle,
  2076. callback
  2077. ) {
  2078. // Check for cycles when build is trigger inside another build
  2079. /** @type {Set<Module> | undefined} */
  2080. let creatingModuleDuringBuildSet;
  2081. if (
  2082. checkCycle &&
  2083. this.buildQueue.isProcessing(/** @type {Module} */ (originModule))
  2084. ) {
  2085. // Track build dependency
  2086. creatingModuleDuringBuildSet = this.creatingModuleDuringBuild.get(
  2087. /** @type {Module} */
  2088. (originModule)
  2089. );
  2090. if (creatingModuleDuringBuildSet === undefined) {
  2091. creatingModuleDuringBuildSet = new Set();
  2092. this.creatingModuleDuringBuild.set(
  2093. /** @type {Module} */
  2094. (originModule),
  2095. creatingModuleDuringBuildSet
  2096. );
  2097. }
  2098. creatingModuleDuringBuildSet.add(module);
  2099. // When building is blocked by another module
  2100. // search for a cycle, cancel the cycle by throwing
  2101. // an error (otherwise this would deadlock)
  2102. const blockReasons = this.creatingModuleDuringBuild.get(module);
  2103. if (blockReasons !== undefined) {
  2104. const set = new Set(blockReasons);
  2105. for (const item of set) {
  2106. const blockReasons = this.creatingModuleDuringBuild.get(item);
  2107. if (blockReasons !== undefined) {
  2108. for (const m of blockReasons) {
  2109. if (m === module) {
  2110. return callback(new BuildCycleError(module));
  2111. }
  2112. set.add(m);
  2113. }
  2114. }
  2115. }
  2116. }
  2117. }
  2118. this.buildModule(module, (err) => {
  2119. if (creatingModuleDuringBuildSet !== undefined) {
  2120. creatingModuleDuringBuildSet.delete(module);
  2121. }
  2122. if (err) {
  2123. if (!err.module) {
  2124. err.module = module;
  2125. }
  2126. this.errors.push(err);
  2127. return callback(err);
  2128. }
  2129. if (!recursive) {
  2130. this.processModuleDependenciesNonRecursive(module);
  2131. callback(null, module);
  2132. return;
  2133. }
  2134. // This avoids deadlocks for circular dependencies
  2135. if (this.processDependenciesQueue.isProcessing(module)) {
  2136. return callback(null, module);
  2137. }
  2138. this.processModuleDependencies(module, (err) => {
  2139. if (err) {
  2140. return callback(err);
  2141. }
  2142. callback(null, module);
  2143. });
  2144. });
  2145. }
  2146. /**
  2147. * @param {string} context context string path
  2148. * @param {Dependency} dependency dependency used to create Module chain
  2149. * @param {ModuleCallback} callback callback for when module chain is complete
  2150. * @returns {void} will throw if dependency instance is not a valid Dependency
  2151. */
  2152. addModuleChain(context, dependency, callback) {
  2153. return this.addModuleTree({ context, dependency }, callback);
  2154. }
  2155. /**
  2156. * @param {object} options options
  2157. * @param {string} options.context context string path
  2158. * @param {Dependency} options.dependency dependency used to create Module chain
  2159. * @param {Partial<ModuleFactoryCreateDataContextInfo>=} options.contextInfo additional context info for the root module
  2160. * @param {ModuleCallback} callback callback for when module chain is complete
  2161. * @returns {void} will throw if dependency instance is not a valid Dependency
  2162. */
  2163. addModuleTree({ context, dependency, contextInfo }, callback) {
  2164. if (
  2165. typeof dependency !== "object" ||
  2166. dependency === null ||
  2167. !dependency.constructor
  2168. ) {
  2169. return callback(
  2170. new WebpackError("Parameter 'dependency' must be a Dependency")
  2171. );
  2172. }
  2173. const Dep =
  2174. /** @type {DependencyConstructor} */
  2175. (dependency.constructor);
  2176. const moduleFactory = this.dependencyFactories.get(Dep);
  2177. if (!moduleFactory) {
  2178. return callback(
  2179. new WebpackError(
  2180. `No dependency factory available for this dependency type: ${dependency.constructor.name}`
  2181. )
  2182. );
  2183. }
  2184. this.handleModuleCreation(
  2185. {
  2186. factory: moduleFactory,
  2187. dependencies: [dependency],
  2188. originModule: null,
  2189. contextInfo,
  2190. context
  2191. },
  2192. (err, result) => {
  2193. if (err && this.bail) {
  2194. callback(err);
  2195. this.buildQueue.stop();
  2196. this.rebuildQueue.stop();
  2197. this.processDependenciesQueue.stop();
  2198. this.factorizeQueue.stop();
  2199. } else if (!err && result) {
  2200. callback(null, result);
  2201. } else {
  2202. callback();
  2203. }
  2204. }
  2205. );
  2206. }
  2207. /**
  2208. * @param {string} context context path for entry
  2209. * @param {Dependency} entry entry dependency that should be followed
  2210. * @param {string | EntryOptions} optionsOrName options or deprecated name of entry
  2211. * @param {ModuleCallback} callback callback function
  2212. * @returns {void} returns
  2213. */
  2214. addEntry(context, entry, optionsOrName, callback) {
  2215. // TODO webpack 6 remove
  2216. const options =
  2217. typeof optionsOrName === "object"
  2218. ? optionsOrName
  2219. : { name: optionsOrName };
  2220. this._addEntryItem(context, entry, "dependencies", options, callback);
  2221. }
  2222. /**
  2223. * @param {string} context context path for entry
  2224. * @param {Dependency} dependency dependency that should be followed
  2225. * @param {EntryOptions} options options
  2226. * @param {ModuleCallback} callback callback function
  2227. * @returns {void} returns
  2228. */
  2229. addInclude(context, dependency, options, callback) {
  2230. this._addEntryItem(
  2231. context,
  2232. dependency,
  2233. "includeDependencies",
  2234. options,
  2235. callback
  2236. );
  2237. }
  2238. /**
  2239. * @param {string} context context path for entry
  2240. * @param {Dependency} entry entry dependency that should be followed
  2241. * @param {"dependencies" | "includeDependencies"} target type of entry
  2242. * @param {EntryOptions} options options
  2243. * @param {ModuleCallback} callback callback function
  2244. * @returns {void} returns
  2245. */
  2246. _addEntryItem(context, entry, target, options, callback) {
  2247. const { name } = options;
  2248. /** @type {EntryData | undefined} */
  2249. let entryData =
  2250. name !== undefined ? this.entries.get(name) : this.globalEntry;
  2251. if (entryData === undefined) {
  2252. entryData = {
  2253. dependencies: [],
  2254. includeDependencies: [],
  2255. options: {
  2256. name: undefined,
  2257. ...options
  2258. }
  2259. };
  2260. entryData[target].push(entry);
  2261. this.entries.set(
  2262. /** @type {NonNullable<EntryOptions["name"]>} */
  2263. (name),
  2264. entryData
  2265. );
  2266. } else {
  2267. entryData[target].push(entry);
  2268. for (const key_ of Object.keys(options)) {
  2269. const key = /** @type {keyof EntryOptions} */ (key_);
  2270. if (options[key] === undefined) continue;
  2271. if (entryData.options[key] === options[key]) continue;
  2272. if (
  2273. Array.isArray(entryData.options[key]) &&
  2274. Array.isArray(options[key]) &&
  2275. arrayEquals(entryData.options[key], options[key])
  2276. ) {
  2277. continue;
  2278. }
  2279. if (entryData.options[key] === undefined) {
  2280. /** @type {EntryOptions[keyof EntryOptions]} */
  2281. (entryData.options[key]) = options[key];
  2282. } else {
  2283. return callback(
  2284. new WebpackError(
  2285. `Conflicting entry option ${key} = ${entryData.options[key]} vs ${options[key]}`
  2286. )
  2287. );
  2288. }
  2289. }
  2290. }
  2291. this.hooks.addEntry.call(entry, options);
  2292. this.addModuleTree(
  2293. {
  2294. context,
  2295. dependency: entry,
  2296. contextInfo: entryData.options.layer
  2297. ? { issuerLayer: entryData.options.layer }
  2298. : undefined
  2299. },
  2300. (err, module) => {
  2301. if (err) {
  2302. this.hooks.failedEntry.call(entry, options, err);
  2303. return callback(err);
  2304. }
  2305. this.hooks.succeedEntry.call(
  2306. entry,
  2307. options,
  2308. /** @type {Module} */
  2309. (module)
  2310. );
  2311. return callback(null, module);
  2312. }
  2313. );
  2314. }
  2315. /**
  2316. * @param {Module} module module to be rebuilt
  2317. * @param {ModuleCallback} callback callback when module finishes rebuilding
  2318. * @returns {void}
  2319. */
  2320. rebuildModule(module, callback) {
  2321. this.rebuildQueue.add(module, callback);
  2322. }
  2323. /**
  2324. * @param {Module} module module to be rebuilt
  2325. * @param {ModuleCallback} callback callback when module finishes rebuilding
  2326. * @returns {void}
  2327. */
  2328. _rebuildModule(module, callback) {
  2329. this.hooks.rebuildModule.call(module);
  2330. const oldDependencies = [...module.dependencies];
  2331. const oldBlocks = [...module.blocks];
  2332. module.invalidateBuild();
  2333. this.buildQueue.invalidate(module);
  2334. this.buildModule(module, (err) => {
  2335. if (err) {
  2336. return this.hooks.finishRebuildingModule.callAsync(module, (err2) => {
  2337. if (err2) {
  2338. callback(
  2339. makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule")
  2340. );
  2341. return;
  2342. }
  2343. callback(err);
  2344. });
  2345. }
  2346. this.processDependenciesQueue.invalidate(module);
  2347. this.moduleGraph.unfreeze();
  2348. this.processModuleDependencies(module, (err) => {
  2349. if (err) return callback(err);
  2350. this.removeReasonsOfDependencyBlock(module, {
  2351. dependencies: oldDependencies,
  2352. blocks: oldBlocks
  2353. });
  2354. this.hooks.finishRebuildingModule.callAsync(module, (err2) => {
  2355. if (err2) {
  2356. callback(
  2357. makeWebpackError(err2, "Compilation.hooks.finishRebuildingModule")
  2358. );
  2359. return;
  2360. }
  2361. callback(null, module);
  2362. });
  2363. });
  2364. });
  2365. }
  2366. /**
  2367. * @private
  2368. * @param {Set<Module>} modules modules
  2369. */
  2370. _computeAffectedModules(modules) {
  2371. const moduleMemCacheCache = this.compiler.moduleMemCaches;
  2372. if (!moduleMemCacheCache) return;
  2373. if (!this.moduleMemCaches) {
  2374. this.moduleMemCaches = new Map();
  2375. this.moduleGraph.setModuleMemCaches(this.moduleMemCaches);
  2376. }
  2377. const { moduleGraph, moduleMemCaches } = this;
  2378. const affectedModules = new Set();
  2379. const infectedModules = new Set();
  2380. let statNew = 0;
  2381. let statChanged = 0;
  2382. let statUnchanged = 0;
  2383. let statReferencesChanged = 0;
  2384. let statWithoutBuild = 0;
  2385. /**
  2386. * @param {Module} module module
  2387. * @returns {WeakReferences | undefined} references
  2388. */
  2389. const computeReferences = (module) => {
  2390. /** @type {WeakReferences | undefined} */
  2391. let references;
  2392. for (const connection of moduleGraph.getOutgoingConnections(module)) {
  2393. const d = connection.dependency;
  2394. const m = connection.module;
  2395. if (!d || !m || unsafeCacheDependencies.has(d)) continue;
  2396. if (references === undefined) references = new WeakMap();
  2397. references.set(d, m);
  2398. }
  2399. return references;
  2400. };
  2401. /**
  2402. * @param {Module} module the module
  2403. * @param {WeakReferences | undefined} references references
  2404. * @returns {boolean} true, when the references differ
  2405. */
  2406. const compareReferences = (module, references) => {
  2407. if (references === undefined) return true;
  2408. for (const connection of moduleGraph.getOutgoingConnections(module)) {
  2409. const d = connection.dependency;
  2410. if (!d) continue;
  2411. const entry = references.get(d);
  2412. if (entry === undefined) continue;
  2413. if (entry !== connection.module) return false;
  2414. }
  2415. return true;
  2416. };
  2417. const modulesWithoutCache = new Set(modules);
  2418. for (const [module, cachedMemCache] of moduleMemCacheCache) {
  2419. if (modulesWithoutCache.has(module)) {
  2420. const buildInfo = module.buildInfo;
  2421. if (buildInfo) {
  2422. if (cachedMemCache.buildInfo !== buildInfo) {
  2423. // use a new one
  2424. /** @type {MemCache} */
  2425. const memCache = new WeakTupleMap();
  2426. moduleMemCaches.set(module, memCache);
  2427. affectedModules.add(module);
  2428. cachedMemCache.buildInfo = buildInfo;
  2429. cachedMemCache.references = computeReferences(module);
  2430. cachedMemCache.memCache = memCache;
  2431. statChanged++;
  2432. } else if (!compareReferences(module, cachedMemCache.references)) {
  2433. // use a new one
  2434. /** @type {MemCache} */
  2435. const memCache = new WeakTupleMap();
  2436. moduleMemCaches.set(module, memCache);
  2437. affectedModules.add(module);
  2438. cachedMemCache.references = computeReferences(module);
  2439. cachedMemCache.memCache = memCache;
  2440. statReferencesChanged++;
  2441. } else {
  2442. // keep the old mem cache
  2443. moduleMemCaches.set(module, cachedMemCache.memCache);
  2444. statUnchanged++;
  2445. }
  2446. } else {
  2447. infectedModules.add(module);
  2448. moduleMemCacheCache.delete(module);
  2449. statWithoutBuild++;
  2450. }
  2451. modulesWithoutCache.delete(module);
  2452. } else {
  2453. moduleMemCacheCache.delete(module);
  2454. }
  2455. }
  2456. for (const module of modulesWithoutCache) {
  2457. const buildInfo = module.buildInfo;
  2458. if (buildInfo) {
  2459. // create a new entry
  2460. const memCache = new WeakTupleMap();
  2461. moduleMemCacheCache.set(module, {
  2462. buildInfo,
  2463. references: computeReferences(module),
  2464. memCache
  2465. });
  2466. moduleMemCaches.set(module, memCache);
  2467. affectedModules.add(module);
  2468. statNew++;
  2469. } else {
  2470. infectedModules.add(module);
  2471. statWithoutBuild++;
  2472. }
  2473. }
  2474. /**
  2475. * @param {Readonly<ModuleGraphConnection[]>} connections connections
  2476. * @returns {symbol | boolean} result
  2477. */
  2478. const reduceAffectType = (connections) => {
  2479. let affected = false;
  2480. for (const { dependency } of connections) {
  2481. if (!dependency) continue;
  2482. const type = dependency.couldAffectReferencingModule();
  2483. if (type === Dependency.TRANSITIVE) return Dependency.TRANSITIVE;
  2484. if (type === false) continue;
  2485. affected = true;
  2486. }
  2487. return affected;
  2488. };
  2489. const directOnlyInfectedModules = new Set();
  2490. for (const module of infectedModules) {
  2491. for (const [
  2492. referencingModule,
  2493. connections
  2494. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  2495. if (!referencingModule) continue;
  2496. if (infectedModules.has(referencingModule)) continue;
  2497. const type = reduceAffectType(connections);
  2498. if (!type) continue;
  2499. if (type === true) {
  2500. directOnlyInfectedModules.add(referencingModule);
  2501. } else {
  2502. infectedModules.add(referencingModule);
  2503. }
  2504. }
  2505. }
  2506. for (const module of directOnlyInfectedModules) infectedModules.add(module);
  2507. const directOnlyAffectModules = new Set();
  2508. for (const module of affectedModules) {
  2509. for (const [
  2510. referencingModule,
  2511. connections
  2512. ] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
  2513. if (!referencingModule) continue;
  2514. if (infectedModules.has(referencingModule)) continue;
  2515. if (affectedModules.has(referencingModule)) continue;
  2516. const type = reduceAffectType(connections);
  2517. if (!type) continue;
  2518. if (type === true) {
  2519. directOnlyAffectModules.add(referencingModule);
  2520. } else {
  2521. affectedModules.add(referencingModule);
  2522. }
  2523. /** @type {MemCache} */
  2524. const memCache = new WeakTupleMap();
  2525. const cache =
  2526. /** @type {ModuleMemCachesItem} */
  2527. (moduleMemCacheCache.get(referencingModule));
  2528. cache.memCache = memCache;
  2529. moduleMemCaches.set(referencingModule, memCache);
  2530. }
  2531. }
  2532. for (const module of directOnlyAffectModules) affectedModules.add(module);
  2533. this.logger.log(
  2534. `${Math.round(
  2535. (100 * (affectedModules.size + infectedModules.size)) /
  2536. this.modules.size
  2537. )}% (${affectedModules.size} affected + ${
  2538. infectedModules.size
  2539. } infected of ${
  2540. this.modules.size
  2541. }) modules flagged as affected (${statNew} new modules, ${statChanged} changed, ${statReferencesChanged} references changed, ${statUnchanged} unchanged, ${statWithoutBuild} were not built)`
  2542. );
  2543. }
  2544. _computeAffectedModulesWithChunkGraph() {
  2545. const { moduleMemCaches } = this;
  2546. if (!moduleMemCaches) return;
  2547. const moduleMemCaches2 = (this.moduleMemCaches2 = new Map());
  2548. const { moduleGraph, chunkGraph } = this;
  2549. const key = "memCache2";
  2550. let statUnchanged = 0;
  2551. let statChanged = 0;
  2552. let statNew = 0;
  2553. /**
  2554. * @param {Module} module module
  2555. * @returns {References} references
  2556. */
  2557. const computeReferences = (module) => {
  2558. const id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
  2559. /** @type {Map<Module, ModuleId> | undefined} */
  2560. let modules;
  2561. /** @type {(ChunkId | null)[] | undefined} */
  2562. let blocks;
  2563. const outgoing = moduleGraph.getOutgoingConnectionsByModule(module);
  2564. if (outgoing !== undefined) {
  2565. for (const m of outgoing.keys()) {
  2566. if (!m) continue;
  2567. if (modules === undefined) modules = new Map();
  2568. modules.set(m, /** @type {ModuleId} */ (chunkGraph.getModuleId(m)));
  2569. }
  2570. }
  2571. if (module.blocks.length > 0) {
  2572. blocks = [];
  2573. const queue = [...module.blocks];
  2574. for (const block of queue) {
  2575. const chunkGroup = chunkGraph.getBlockChunkGroup(block);
  2576. if (chunkGroup) {
  2577. for (const chunk of chunkGroup.chunks) {
  2578. blocks.push(chunk.id);
  2579. }
  2580. } else {
  2581. blocks.push(null);
  2582. }
  2583. // eslint-disable-next-line prefer-spread
  2584. queue.push.apply(queue, block.blocks);
  2585. }
  2586. }
  2587. return { id, modules, blocks };
  2588. };
  2589. /**
  2590. * @param {Module} module module
  2591. * @param {object} references references
  2592. * @param {string | number} references.id id
  2593. * @param {Map<Module, string | number | undefined>=} references.modules modules
  2594. * @param {(string | number | null)[]=} references.blocks blocks
  2595. * @returns {boolean} ok?
  2596. */
  2597. const compareReferences = (module, { id, modules, blocks }) => {
  2598. if (id !== chunkGraph.getModuleId(module)) return false;
  2599. if (modules !== undefined) {
  2600. for (const [module, id] of modules) {
  2601. if (chunkGraph.getModuleId(module) !== id) return false;
  2602. }
  2603. }
  2604. if (blocks !== undefined) {
  2605. const queue = [...module.blocks];
  2606. let i = 0;
  2607. for (const block of queue) {
  2608. const chunkGroup = chunkGraph.getBlockChunkGroup(block);
  2609. if (chunkGroup) {
  2610. for (const chunk of chunkGroup.chunks) {
  2611. if (i >= blocks.length || blocks[i++] !== chunk.id) return false;
  2612. }
  2613. } else if (i >= blocks.length || blocks[i++] !== null) {
  2614. return false;
  2615. }
  2616. // eslint-disable-next-line prefer-spread
  2617. queue.push.apply(queue, block.blocks);
  2618. }
  2619. if (i !== blocks.length) return false;
  2620. }
  2621. return true;
  2622. };
  2623. for (const [module, memCache] of moduleMemCaches) {
  2624. /** @type {{ references: References, memCache: MemCache } | undefined} */
  2625. const cache = memCache.get(key);
  2626. if (cache === undefined) {
  2627. /** @type {WeakTupleMap<Module[], RuntimeRequirements | null> | undefined} */
  2628. const memCache2 = new WeakTupleMap();
  2629. memCache.set(key, {
  2630. references: computeReferences(module),
  2631. memCache: memCache2
  2632. });
  2633. moduleMemCaches2.set(module, memCache2);
  2634. statNew++;
  2635. } else if (!compareReferences(module, cache.references)) {
  2636. /** @type {WeakTupleMap<Module[], RuntimeRequirements | null> | undefined} */
  2637. const memCache = new WeakTupleMap();
  2638. cache.references = computeReferences(module);
  2639. cache.memCache = memCache;
  2640. moduleMemCaches2.set(module, memCache);
  2641. statChanged++;
  2642. } else {
  2643. moduleMemCaches2.set(module, cache.memCache);
  2644. statUnchanged++;
  2645. }
  2646. }
  2647. this.logger.log(
  2648. `${Math.round(
  2649. (100 * statChanged) / (statNew + statChanged + statUnchanged)
  2650. )}% modules flagged as affected by chunk graph (${statNew} new modules, ${statChanged} changed, ${statUnchanged} unchanged)`
  2651. );
  2652. }
  2653. /**
  2654. * @param {Callback} callback callback
  2655. */
  2656. finish(callback) {
  2657. this.factorizeQueue.clear();
  2658. if (this.profile) {
  2659. this.logger.time("finish module profiles");
  2660. const ParallelismFactorCalculator = require("./util/ParallelismFactorCalculator");
  2661. const p = new ParallelismFactorCalculator();
  2662. const moduleGraph = this.moduleGraph;
  2663. /** @type {Map<Module, ModuleProfile>} */
  2664. const modulesWithProfiles = new Map();
  2665. for (const module of this.modules) {
  2666. const profile = moduleGraph.getProfile(module);
  2667. if (!profile) continue;
  2668. modulesWithProfiles.set(module, profile);
  2669. p.range(
  2670. profile.buildingStartTime,
  2671. profile.buildingEndTime,
  2672. (f) => (profile.buildingParallelismFactor = f)
  2673. );
  2674. p.range(
  2675. profile.factoryStartTime,
  2676. profile.factoryEndTime,
  2677. (f) => (profile.factoryParallelismFactor = f)
  2678. );
  2679. p.range(
  2680. profile.integrationStartTime,
  2681. profile.integrationEndTime,
  2682. (f) => (profile.integrationParallelismFactor = f)
  2683. );
  2684. p.range(
  2685. profile.storingStartTime,
  2686. profile.storingEndTime,
  2687. (f) => (profile.storingParallelismFactor = f)
  2688. );
  2689. p.range(
  2690. profile.restoringStartTime,
  2691. profile.restoringEndTime,
  2692. (f) => (profile.restoringParallelismFactor = f)
  2693. );
  2694. if (profile.additionalFactoryTimes) {
  2695. for (const { start, end } of profile.additionalFactoryTimes) {
  2696. const influence = (end - start) / profile.additionalFactories;
  2697. p.range(
  2698. start,
  2699. end,
  2700. (f) =>
  2701. (profile.additionalFactoriesParallelismFactor += f * influence)
  2702. );
  2703. }
  2704. }
  2705. }
  2706. p.calculate();
  2707. const logger = this.getLogger("webpack.Compilation.ModuleProfile");
  2708. // Avoid coverage problems due indirect changes
  2709. /**
  2710. * @param {number} value value
  2711. * @param {string} msg message
  2712. */
  2713. /* istanbul ignore next */
  2714. const logByValue = (value, msg) => {
  2715. if (value > 1000) {
  2716. logger.error(msg);
  2717. } else if (value > 500) {
  2718. logger.warn(msg);
  2719. } else if (value > 200) {
  2720. logger.info(msg);
  2721. } else if (value > 30) {
  2722. logger.log(msg);
  2723. } else {
  2724. logger.debug(msg);
  2725. }
  2726. };
  2727. /**
  2728. * @param {string} category a category
  2729. * @param {(profile: ModuleProfile) => number} getDuration get duration callback
  2730. * @param {(profile: ModuleProfile) => number} getParallelism get parallelism callback
  2731. */
  2732. const logNormalSummary = (category, getDuration, getParallelism) => {
  2733. let sum = 0;
  2734. let max = 0;
  2735. for (const [module, profile] of modulesWithProfiles) {
  2736. const p = getParallelism(profile);
  2737. const d = getDuration(profile);
  2738. if (d === 0 || p === 0) continue;
  2739. const t = d / p;
  2740. sum += t;
  2741. if (t <= 10) continue;
  2742. logByValue(
  2743. t,
  2744. ` | ${Math.round(t)} ms${
  2745. p >= 1.1 ? ` (parallelism ${Math.round(p * 10) / 10})` : ""
  2746. } ${category} > ${module.readableIdentifier(this.requestShortener)}`
  2747. );
  2748. max = Math.max(max, t);
  2749. }
  2750. if (sum <= 10) return;
  2751. logByValue(
  2752. Math.max(sum / 10, max),
  2753. `${Math.round(sum)} ms ${category}`
  2754. );
  2755. };
  2756. /**
  2757. * @param {string} category a category
  2758. * @param {(profile: ModuleProfile) => number} getDuration get duration callback
  2759. * @param {(profile: ModuleProfile) => number} getParallelism get parallelism callback
  2760. */
  2761. const logByLoadersSummary = (category, getDuration, getParallelism) => {
  2762. const map = new Map();
  2763. for (const [module, profile] of modulesWithProfiles) {
  2764. const list = getOrInsert(
  2765. map,
  2766. `${module.type}!${module.identifier().replace(/(!|^)[^!]*$/, "")}`,
  2767. () => []
  2768. );
  2769. list.push({ module, profile });
  2770. }
  2771. let sum = 0;
  2772. let max = 0;
  2773. for (const [key, modules] of map) {
  2774. let innerSum = 0;
  2775. let innerMax = 0;
  2776. for (const { module, profile } of modules) {
  2777. const p = getParallelism(profile);
  2778. const d = getDuration(profile);
  2779. if (d === 0 || p === 0) continue;
  2780. const t = d / p;
  2781. innerSum += t;
  2782. if (t <= 10) continue;
  2783. logByValue(
  2784. t,
  2785. ` | | ${Math.round(t)} ms${
  2786. p >= 1.1 ? ` (parallelism ${Math.round(p * 10) / 10})` : ""
  2787. } ${category} > ${module.readableIdentifier(
  2788. this.requestShortener
  2789. )}`
  2790. );
  2791. innerMax = Math.max(innerMax, t);
  2792. }
  2793. sum += innerSum;
  2794. if (innerSum <= 10) continue;
  2795. const idx = key.indexOf("!");
  2796. const loaders = key.slice(idx + 1);
  2797. const moduleType = key.slice(0, idx);
  2798. const t = Math.max(innerSum / 10, innerMax);
  2799. logByValue(
  2800. t,
  2801. ` | ${Math.round(innerSum)} ms ${category} > ${
  2802. loaders
  2803. ? `${
  2804. modules.length
  2805. } x ${moduleType} with ${this.requestShortener.shorten(
  2806. loaders
  2807. )}`
  2808. : `${modules.length} x ${moduleType}`
  2809. }`
  2810. );
  2811. max = Math.max(max, t);
  2812. }
  2813. if (sum <= 10) return;
  2814. logByValue(
  2815. Math.max(sum / 10, max),
  2816. `${Math.round(sum)} ms ${category}`
  2817. );
  2818. };
  2819. logNormalSummary(
  2820. "resolve to new modules",
  2821. (p) => p.factory,
  2822. (p) => p.factoryParallelismFactor
  2823. );
  2824. logNormalSummary(
  2825. "resolve to existing modules",
  2826. (p) => p.additionalFactories,
  2827. (p) => p.additionalFactoriesParallelismFactor
  2828. );
  2829. logNormalSummary(
  2830. "integrate modules",
  2831. (p) => p.restoring,
  2832. (p) => p.restoringParallelismFactor
  2833. );
  2834. logByLoadersSummary(
  2835. "build modules",
  2836. (p) => p.building,
  2837. (p) => p.buildingParallelismFactor
  2838. );
  2839. logNormalSummary(
  2840. "store modules",
  2841. (p) => p.storing,
  2842. (p) => p.storingParallelismFactor
  2843. );
  2844. logNormalSummary(
  2845. "restore modules",
  2846. (p) => p.restoring,
  2847. (p) => p.restoringParallelismFactor
  2848. );
  2849. this.logger.timeEnd("finish module profiles");
  2850. }
  2851. this.logger.time("compute affected modules");
  2852. this._computeAffectedModules(this.modules);
  2853. this.logger.timeEnd("compute affected modules");
  2854. this.logger.time("finish modules");
  2855. const { modules, moduleMemCaches } = this;
  2856. this.hooks.finishModules.callAsync(modules, (err) => {
  2857. this.logger.timeEnd("finish modules");
  2858. if (err) return callback(/** @type {WebpackError} */ (err));
  2859. // extract warnings and errors from modules
  2860. this.moduleGraph.freeze("dependency errors");
  2861. // TODO keep a cacheToken (= {}) for each module in the graph
  2862. // create a new one per compilation and flag all updated files
  2863. // and parents with it
  2864. this.logger.time("report dependency errors and warnings");
  2865. for (const module of modules) {
  2866. // TODO only run for modules with changed cacheToken
  2867. // global WeakMap<CacheToken, WeakSet<Module>> to keep modules without errors/warnings
  2868. const memCache = moduleMemCaches && moduleMemCaches.get(module);
  2869. if (memCache && memCache.get("noWarningsOrErrors")) continue;
  2870. let hasProblems = this.reportDependencyErrorsAndWarnings(module, [
  2871. module
  2872. ]);
  2873. const errors = module.getErrors();
  2874. if (errors !== undefined) {
  2875. for (const error of errors) {
  2876. if (!error.module) {
  2877. error.module = module;
  2878. }
  2879. this.errors.push(error);
  2880. hasProblems = true;
  2881. }
  2882. }
  2883. const warnings = module.getWarnings();
  2884. if (warnings !== undefined) {
  2885. for (const warning of warnings) {
  2886. if (!warning.module) {
  2887. warning.module = module;
  2888. }
  2889. this.warnings.push(warning);
  2890. hasProblems = true;
  2891. }
  2892. }
  2893. if (!hasProblems && memCache) memCache.set("noWarningsOrErrors", true);
  2894. }
  2895. this.moduleGraph.unfreeze();
  2896. this.logger.timeEnd("report dependency errors and warnings");
  2897. callback();
  2898. });
  2899. }
  2900. unseal() {
  2901. this.hooks.unseal.call();
  2902. this.chunks.clear();
  2903. this.chunkGroups.length = 0;
  2904. this.namedChunks.clear();
  2905. this.namedChunkGroups.clear();
  2906. this.entrypoints.clear();
  2907. this.additionalChunkAssets.length = 0;
  2908. this.assets = {};
  2909. this.assetsInfo.clear();
  2910. this.moduleGraph.removeAllModuleAttributes();
  2911. this.moduleGraph.unfreeze();
  2912. this.moduleMemCaches2 = undefined;
  2913. }
  2914. /**
  2915. * @param {Callback} callback signals when the call finishes
  2916. * @returns {void}
  2917. */
  2918. seal(callback) {
  2919. /**
  2920. * @param {WebpackError=} err err
  2921. * @returns {void}
  2922. */
  2923. const finalCallback = (err) => {
  2924. this.factorizeQueue.clear();
  2925. this.buildQueue.clear();
  2926. this.rebuildQueue.clear();
  2927. this.processDependenciesQueue.clear();
  2928. this.addModuleQueue.clear();
  2929. return callback(err);
  2930. };
  2931. if (this._backCompat) {
  2932. for (const module of this.modules) {
  2933. ChunkGraph.setChunkGraphForModule(module, this.chunkGraph);
  2934. }
  2935. }
  2936. this.hooks.seal.call();
  2937. this.logger.time("optimize dependencies");
  2938. while (this.hooks.optimizeDependencies.call(this.modules)) {
  2939. /* empty */
  2940. }
  2941. this.hooks.afterOptimizeDependencies.call(this.modules);
  2942. this.logger.timeEnd("optimize dependencies");
  2943. this.logger.time("create chunks");
  2944. this.hooks.beforeChunks.call();
  2945. this.moduleGraph.freeze("seal");
  2946. /** @type {Map<Entrypoint, Module[]>} */
  2947. const chunkGraphInit = new Map();
  2948. for (const [name, { dependencies, includeDependencies, options }] of this
  2949. .entries) {
  2950. const chunk = this.addChunk(name);
  2951. if (options.filename) {
  2952. chunk.filenameTemplate = options.filename;
  2953. }
  2954. const entrypoint = new Entrypoint(options);
  2955. if (!options.dependOn && !options.runtime) {
  2956. entrypoint.setRuntimeChunk(chunk);
  2957. }
  2958. entrypoint.setEntrypointChunk(chunk);
  2959. this.namedChunkGroups.set(name, entrypoint);
  2960. this.entrypoints.set(name, entrypoint);
  2961. this.chunkGroups.push(entrypoint);
  2962. connectChunkGroupAndChunk(entrypoint, chunk);
  2963. const entryModules = new Set();
  2964. for (const dep of [...this.globalEntry.dependencies, ...dependencies]) {
  2965. entrypoint.addOrigin(
  2966. null,
  2967. { name },
  2968. /** @type {Dependency & { request: string }} */
  2969. (dep).request
  2970. );
  2971. const module = this.moduleGraph.getModule(dep);
  2972. if (module) {
  2973. this.chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
  2974. entryModules.add(module);
  2975. const modulesList = chunkGraphInit.get(entrypoint);
  2976. if (modulesList === undefined) {
  2977. chunkGraphInit.set(entrypoint, [module]);
  2978. } else {
  2979. modulesList.push(module);
  2980. }
  2981. }
  2982. }
  2983. this.assignDepths(entryModules);
  2984. /**
  2985. * @param {Dependency[]} deps deps
  2986. * @returns {Module[]} sorted deps
  2987. */
  2988. const mapAndSort = (deps) =>
  2989. /** @type {Module[]} */
  2990. (
  2991. deps.map((dep) => this.moduleGraph.getModule(dep)).filter(Boolean)
  2992. ).sort(compareModulesByIdentifier);
  2993. const includedModules = [
  2994. ...mapAndSort(this.globalEntry.includeDependencies),
  2995. ...mapAndSort(includeDependencies)
  2996. ];
  2997. let modulesList = chunkGraphInit.get(entrypoint);
  2998. if (modulesList === undefined) {
  2999. chunkGraphInit.set(entrypoint, (modulesList = []));
  3000. }
  3001. for (const module of includedModules) {
  3002. this.assignDepth(module);
  3003. modulesList.push(module);
  3004. }
  3005. }
  3006. const runtimeChunks = new Set();
  3007. outer: for (const [
  3008. name,
  3009. {
  3010. options: { dependOn, runtime }
  3011. }
  3012. ] of this.entries) {
  3013. if (dependOn && runtime) {
  3014. const err =
  3015. new WebpackError(`Entrypoint '${name}' has 'dependOn' and 'runtime' specified. This is not valid.
  3016. Entrypoints that depend on other entrypoints do not have their own runtime.
  3017. They will use the runtime(s) from referenced entrypoints instead.
  3018. Remove the 'runtime' option from the entrypoint.`);
  3019. const entry = /** @type {Entrypoint} */ (this.entrypoints.get(name));
  3020. err.chunk = entry.getEntrypointChunk();
  3021. this.errors.push(err);
  3022. }
  3023. if (dependOn) {
  3024. const entry = /** @type {Entrypoint} */ (this.entrypoints.get(name));
  3025. const referencedChunks = entry
  3026. .getEntrypointChunk()
  3027. .getAllReferencedChunks();
  3028. for (const dep of dependOn) {
  3029. const dependency = this.entrypoints.get(dep);
  3030. if (!dependency) {
  3031. throw new Error(
  3032. `Entry ${name} depends on ${dep}, but this entry was not found`
  3033. );
  3034. }
  3035. if (referencedChunks.has(dependency.getEntrypointChunk())) {
  3036. const err = new WebpackError(
  3037. `Entrypoints '${name}' and '${dep}' use 'dependOn' to depend on each other in a circular way.`
  3038. );
  3039. const entryChunk = entry.getEntrypointChunk();
  3040. err.chunk = entryChunk;
  3041. this.errors.push(err);
  3042. entry.setRuntimeChunk(entryChunk);
  3043. continue outer;
  3044. }
  3045. connectEntrypointAndDependOn(entry, dependency);
  3046. connectChunkGroupParentAndChild(dependency, entry);
  3047. }
  3048. } else if (runtime) {
  3049. const entry = /** @type {Entrypoint} */ (this.entrypoints.get(name));
  3050. let chunk = this.namedChunks.get(runtime);
  3051. if (chunk) {
  3052. if (!runtimeChunks.has(chunk)) {
  3053. const err =
  3054. new WebpackError(`Entrypoint '${name}' has a 'runtime' option which points to another entrypoint named '${runtime}'.
  3055. It's not valid to use other entrypoints as runtime chunk.
  3056. Did you mean to use 'dependOn: ${JSON.stringify(
  3057. runtime
  3058. )}' instead to allow using entrypoint '${name}' within the runtime of entrypoint '${runtime}'? For this '${runtime}' must always be loaded when '${name}' is used.
  3059. Or do you want to use the entrypoints '${name}' and '${runtime}' independently on the same page with a shared runtime? In this case give them both the same value for the 'runtime' option. It must be a name not already used by an entrypoint.`);
  3060. const entryChunk =
  3061. /** @type {Chunk} */
  3062. (entry.getEntrypointChunk());
  3063. err.chunk = entryChunk;
  3064. this.errors.push(err);
  3065. entry.setRuntimeChunk(entryChunk);
  3066. continue;
  3067. }
  3068. } else {
  3069. chunk = this.addChunk(runtime);
  3070. chunk.preventIntegration = true;
  3071. runtimeChunks.add(chunk);
  3072. }
  3073. entry.unshiftChunk(chunk);
  3074. chunk.addGroup(entry);
  3075. entry.setRuntimeChunk(chunk);
  3076. }
  3077. }
  3078. buildChunkGraph(this, chunkGraphInit);
  3079. this.hooks.afterChunks.call(this.chunks);
  3080. this.logger.timeEnd("create chunks");
  3081. this.logger.time("optimize");
  3082. this.hooks.optimize.call();
  3083. while (this.hooks.optimizeModules.call(this.modules)) {
  3084. /* empty */
  3085. }
  3086. this.hooks.afterOptimizeModules.call(this.modules);
  3087. while (this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups)) {
  3088. /* empty */
  3089. }
  3090. this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
  3091. this.hooks.optimizeTree.callAsync(this.chunks, this.modules, (err) => {
  3092. if (err) {
  3093. return finalCallback(
  3094. makeWebpackError(err, "Compilation.hooks.optimizeTree")
  3095. );
  3096. }
  3097. this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
  3098. this.hooks.optimizeChunkModules.callAsync(
  3099. this.chunks,
  3100. this.modules,
  3101. (err) => {
  3102. if (err) {
  3103. return finalCallback(
  3104. makeWebpackError(err, "Compilation.hooks.optimizeChunkModules")
  3105. );
  3106. }
  3107. this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
  3108. const shouldRecord = this.hooks.shouldRecord.call() !== false;
  3109. this.hooks.reviveModules.call(
  3110. this.modules,
  3111. /** @type {Records} */
  3112. (this.records)
  3113. );
  3114. this.hooks.beforeModuleIds.call(this.modules);
  3115. this.hooks.moduleIds.call(this.modules);
  3116. this.hooks.optimizeModuleIds.call(this.modules);
  3117. this.hooks.afterOptimizeModuleIds.call(this.modules);
  3118. this.hooks.reviveChunks.call(
  3119. this.chunks,
  3120. /** @type {Records} */
  3121. (this.records)
  3122. );
  3123. this.hooks.beforeChunkIds.call(this.chunks);
  3124. this.hooks.chunkIds.call(this.chunks);
  3125. this.hooks.optimizeChunkIds.call(this.chunks);
  3126. this.hooks.afterOptimizeChunkIds.call(this.chunks);
  3127. this.assignRuntimeIds();
  3128. this.logger.time("compute affected modules with chunk graph");
  3129. this._computeAffectedModulesWithChunkGraph();
  3130. this.logger.timeEnd("compute affected modules with chunk graph");
  3131. this.sortItemsWithChunkIds();
  3132. if (shouldRecord) {
  3133. this.hooks.recordModules.call(
  3134. this.modules,
  3135. /** @type {Records} */
  3136. (this.records)
  3137. );
  3138. this.hooks.recordChunks.call(
  3139. this.chunks,
  3140. /** @type {Records} */
  3141. (this.records)
  3142. );
  3143. }
  3144. this.hooks.optimizeCodeGeneration.call(this.modules);
  3145. this.logger.timeEnd("optimize");
  3146. this.logger.time("module hashing");
  3147. this.hooks.beforeModuleHash.call();
  3148. this.createModuleHashes();
  3149. this.hooks.afterModuleHash.call();
  3150. this.logger.timeEnd("module hashing");
  3151. this.logger.time("code generation");
  3152. this.hooks.beforeCodeGeneration.call();
  3153. this.codeGeneration((err) => {
  3154. if (err) {
  3155. return finalCallback(err);
  3156. }
  3157. this.hooks.afterCodeGeneration.call();
  3158. this.logger.timeEnd("code generation");
  3159. this.logger.time("runtime requirements");
  3160. this.hooks.beforeRuntimeRequirements.call();
  3161. this.processRuntimeRequirements();
  3162. this.hooks.afterRuntimeRequirements.call();
  3163. this.logger.timeEnd("runtime requirements");
  3164. this.logger.time("hashing");
  3165. this.hooks.beforeHash.call();
  3166. const codeGenerationJobs = this.createHash();
  3167. this.hooks.afterHash.call();
  3168. this.logger.timeEnd("hashing");
  3169. this._runCodeGenerationJobs(codeGenerationJobs, (err) => {
  3170. if (err) {
  3171. return finalCallback(err);
  3172. }
  3173. if (shouldRecord) {
  3174. this.logger.time("record hash");
  3175. this.hooks.recordHash.call(
  3176. /** @type {Records} */
  3177. (this.records)
  3178. );
  3179. this.logger.timeEnd("record hash");
  3180. }
  3181. this.logger.time("module assets");
  3182. this.clearAssets();
  3183. this.hooks.beforeModuleAssets.call();
  3184. this.createModuleAssets();
  3185. this.logger.timeEnd("module assets");
  3186. const cont = () => {
  3187. this.logger.time("process assets");
  3188. this.hooks.processAssets.callAsync(this.assets, (err) => {
  3189. if (err) {
  3190. return finalCallback(
  3191. makeWebpackError(err, "Compilation.hooks.processAssets")
  3192. );
  3193. }
  3194. this.hooks.afterProcessAssets.call(this.assets);
  3195. this.logger.timeEnd("process assets");
  3196. this.assets =
  3197. /** @type {CompilationAssets} */
  3198. (
  3199. this._backCompat
  3200. ? soonFrozenObjectDeprecation(
  3201. this.assets,
  3202. "Compilation.assets",
  3203. "DEP_WEBPACK_COMPILATION_ASSETS",
  3204. `BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation.
  3205. Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
  3206. Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.`
  3207. )
  3208. : Object.freeze(this.assets)
  3209. );
  3210. this.summarizeDependencies();
  3211. if (shouldRecord) {
  3212. this.hooks.record.call(
  3213. this,
  3214. /** @type {Records} */
  3215. (this.records)
  3216. );
  3217. }
  3218. if (this.hooks.needAdditionalSeal.call()) {
  3219. this.unseal();
  3220. return this.seal(callback);
  3221. }
  3222. return this.hooks.afterSeal.callAsync((err) => {
  3223. if (err) {
  3224. return finalCallback(
  3225. makeWebpackError(err, "Compilation.hooks.afterSeal")
  3226. );
  3227. }
  3228. this.fileSystemInfo.logStatistics();
  3229. finalCallback();
  3230. });
  3231. });
  3232. };
  3233. this.logger.time("create chunk assets");
  3234. if (this.hooks.shouldGenerateChunkAssets.call() !== false) {
  3235. this.hooks.beforeChunkAssets.call();
  3236. this.createChunkAssets((err) => {
  3237. this.logger.timeEnd("create chunk assets");
  3238. if (err) {
  3239. return finalCallback(err);
  3240. }
  3241. cont();
  3242. });
  3243. } else {
  3244. this.logger.timeEnd("create chunk assets");
  3245. cont();
  3246. }
  3247. });
  3248. });
  3249. }
  3250. );
  3251. });
  3252. }
  3253. /**
  3254. * @param {Module} module module to report from
  3255. * @param {DependenciesBlock[]} blocks blocks to report from
  3256. * @returns {boolean} true, when it has warnings or errors
  3257. */
  3258. reportDependencyErrorsAndWarnings(module, blocks) {
  3259. let hasProblems = false;
  3260. for (const block of blocks) {
  3261. const dependencies = block.dependencies;
  3262. for (const d of dependencies) {
  3263. const warnings = d.getWarnings(this.moduleGraph);
  3264. if (warnings) {
  3265. for (const w of warnings) {
  3266. const warning = new ModuleDependencyWarning(module, w, d.loc);
  3267. this.warnings.push(warning);
  3268. hasProblems = true;
  3269. }
  3270. }
  3271. const errors = d.getErrors(this.moduleGraph);
  3272. if (errors) {
  3273. for (const e of errors) {
  3274. const error = new ModuleDependencyError(module, e, d.loc);
  3275. this.errors.push(error);
  3276. hasProblems = true;
  3277. }
  3278. }
  3279. }
  3280. if (this.reportDependencyErrorsAndWarnings(module, block.blocks)) {
  3281. hasProblems = true;
  3282. }
  3283. }
  3284. return hasProblems;
  3285. }
  3286. /**
  3287. * @param {Callback} callback callback
  3288. */
  3289. codeGeneration(callback) {
  3290. const { chunkGraph } = this;
  3291. this.codeGenerationResults = new CodeGenerationResults(
  3292. this.outputOptions.hashFunction
  3293. );
  3294. /** @type {CodeGenerationJobs} */
  3295. const jobs = [];
  3296. for (const module of this.modules) {
  3297. const runtimes = chunkGraph.getModuleRuntimes(module);
  3298. if (runtimes.size === 1) {
  3299. for (const runtime of runtimes) {
  3300. const hash = chunkGraph.getModuleHash(module, runtime);
  3301. jobs.push({ module, hash, runtime, runtimes: [runtime] });
  3302. }
  3303. } else if (runtimes.size > 1) {
  3304. /** @type {Map<string, { runtimes: RuntimeSpec[] }>} */
  3305. const map = new Map();
  3306. for (const runtime of runtimes) {
  3307. const hash = chunkGraph.getModuleHash(module, runtime);
  3308. const job = map.get(hash);
  3309. if (job === undefined) {
  3310. const newJob = { module, hash, runtime, runtimes: [runtime] };
  3311. jobs.push(newJob);
  3312. map.set(hash, newJob);
  3313. } else {
  3314. job.runtimes.push(runtime);
  3315. }
  3316. }
  3317. }
  3318. }
  3319. this._runCodeGenerationJobs(jobs, callback);
  3320. }
  3321. /**
  3322. * @private
  3323. * @param {CodeGenerationJobs} jobs code generation jobs
  3324. * @param {Callback} callback callback
  3325. * @returns {void}
  3326. */
  3327. _runCodeGenerationJobs(jobs, callback) {
  3328. if (jobs.length === 0) {
  3329. return callback();
  3330. }
  3331. let statModulesFromCache = 0;
  3332. let statModulesGenerated = 0;
  3333. const { chunkGraph, moduleGraph, dependencyTemplates, runtimeTemplate } =
  3334. this;
  3335. const results =
  3336. /** @type {CodeGenerationResults} */
  3337. (this.codeGenerationResults);
  3338. /** @type {WebpackError[]} */
  3339. const errors = [];
  3340. /** @type {NotCodeGeneratedModules | undefined} */
  3341. let notCodeGeneratedModules;
  3342. const runIteration = () => {
  3343. /** @type {CodeGenerationJobs} */
  3344. let delayedJobs = [];
  3345. let delayedModules = new Set();
  3346. asyncLib.eachLimit(
  3347. jobs,
  3348. this.options.parallelism,
  3349. (job, callback) => {
  3350. const { module } = job;
  3351. const { codeGenerationDependencies } = module;
  3352. if (
  3353. codeGenerationDependencies !== undefined &&
  3354. (notCodeGeneratedModules === undefined ||
  3355. codeGenerationDependencies.some((dep) => {
  3356. const referencedModule = /** @type {Module} */ (
  3357. moduleGraph.getModule(dep)
  3358. );
  3359. return /** @type {NotCodeGeneratedModules} */ (
  3360. notCodeGeneratedModules
  3361. ).has(referencedModule);
  3362. }))
  3363. ) {
  3364. delayedJobs.push(job);
  3365. delayedModules.add(module);
  3366. return callback();
  3367. }
  3368. const { hash, runtime, runtimes } = job;
  3369. this._codeGenerationModule(
  3370. module,
  3371. runtime,
  3372. runtimes,
  3373. hash,
  3374. dependencyTemplates,
  3375. chunkGraph,
  3376. moduleGraph,
  3377. runtimeTemplate,
  3378. errors,
  3379. results,
  3380. (err, codeGenerated) => {
  3381. if (codeGenerated) statModulesGenerated++;
  3382. else statModulesFromCache++;
  3383. callback(err);
  3384. }
  3385. );
  3386. },
  3387. (err) => {
  3388. if (err) return callback(err);
  3389. if (delayedJobs.length > 0) {
  3390. if (delayedJobs.length === jobs.length) {
  3391. return callback(
  3392. /** @type {WebpackError} */ (
  3393. new Error(
  3394. `Unable to make progress during code generation because of circular code generation dependency: ${Array.from(
  3395. delayedModules,
  3396. (m) => m.identifier()
  3397. ).join(", ")}`
  3398. )
  3399. )
  3400. );
  3401. }
  3402. jobs = delayedJobs;
  3403. delayedJobs = [];
  3404. notCodeGeneratedModules = delayedModules;
  3405. delayedModules = new Set();
  3406. return runIteration();
  3407. }
  3408. if (errors.length > 0) {
  3409. errors.sort(
  3410. compareSelect((err) => err.module, compareModulesByIdentifier)
  3411. );
  3412. for (const error of errors) {
  3413. this.errors.push(error);
  3414. }
  3415. }
  3416. this.logger.log(
  3417. `${Math.round(
  3418. (100 * statModulesGenerated) /
  3419. (statModulesGenerated + statModulesFromCache)
  3420. )}% code generated (${statModulesGenerated} generated, ${statModulesFromCache} from cache)`
  3421. );
  3422. callback();
  3423. }
  3424. );
  3425. };
  3426. runIteration();
  3427. }
  3428. /**
  3429. * @param {Module} module module
  3430. * @param {RuntimeSpec} runtime runtime
  3431. * @param {RuntimeSpec[]} runtimes runtimes
  3432. * @param {string} hash hash
  3433. * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
  3434. * @param {ChunkGraph} chunkGraph chunkGraph
  3435. * @param {ModuleGraph} moduleGraph moduleGraph
  3436. * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
  3437. * @param {WebpackError[]} errors errors
  3438. * @param {CodeGenerationResults} results results
  3439. * @param {(err?: WebpackError | null, result?: boolean) => void} callback callback
  3440. */
  3441. _codeGenerationModule(
  3442. module,
  3443. runtime,
  3444. runtimes,
  3445. hash,
  3446. dependencyTemplates,
  3447. chunkGraph,
  3448. moduleGraph,
  3449. runtimeTemplate,
  3450. errors,
  3451. results,
  3452. callback
  3453. ) {
  3454. let codeGenerated = false;
  3455. const cache = new MultiItemCache(
  3456. runtimes.map((runtime) =>
  3457. this._codeGenerationCache.getItemCache(
  3458. `${module.identifier()}|${getRuntimeKey(runtime)}`,
  3459. `${hash}|${dependencyTemplates.getHash()}`
  3460. )
  3461. )
  3462. );
  3463. cache.get((err, cachedResult) => {
  3464. if (err) return callback(/** @type {WebpackError} */ (err));
  3465. let result;
  3466. if (!cachedResult) {
  3467. try {
  3468. codeGenerated = true;
  3469. this.codeGeneratedModules.add(module);
  3470. result = module.codeGeneration({
  3471. chunkGraph,
  3472. moduleGraph,
  3473. dependencyTemplates,
  3474. runtimeTemplate,
  3475. runtime,
  3476. codeGenerationResults: results,
  3477. compilation: this
  3478. });
  3479. } catch (err) {
  3480. errors.push(
  3481. new CodeGenerationError(module, /** @type {Error} */ (err))
  3482. );
  3483. result = cachedResult = {
  3484. sources: new Map(),
  3485. runtimeRequirements: null
  3486. };
  3487. }
  3488. } else {
  3489. result = cachedResult;
  3490. }
  3491. for (const runtime of runtimes) {
  3492. results.add(module, runtime, result);
  3493. }
  3494. if (!cachedResult) {
  3495. cache.store(result, (err) =>
  3496. callback(/** @type {WebpackError} */ (err), codeGenerated)
  3497. );
  3498. } else {
  3499. callback(null, codeGenerated);
  3500. }
  3501. });
  3502. }
  3503. _getChunkGraphEntries() {
  3504. /** @type {Set<Chunk>} */
  3505. const treeEntries = new Set();
  3506. for (const ep of this.entrypoints.values()) {
  3507. const chunk = ep.getRuntimeChunk();
  3508. if (chunk) treeEntries.add(chunk);
  3509. }
  3510. for (const ep of this.asyncEntrypoints) {
  3511. const chunk = ep.getRuntimeChunk();
  3512. if (chunk) treeEntries.add(chunk);
  3513. }
  3514. return treeEntries;
  3515. }
  3516. /**
  3517. * @param {object} options options
  3518. * @param {ChunkGraph=} options.chunkGraph the chunk graph
  3519. * @param {Iterable<Module>=} options.modules modules
  3520. * @param {Iterable<Chunk>=} options.chunks chunks
  3521. * @param {CodeGenerationResults=} options.codeGenerationResults codeGenerationResults
  3522. * @param {Iterable<Chunk>=} options.chunkGraphEntries chunkGraphEntries
  3523. * @returns {void}
  3524. */
  3525. processRuntimeRequirements({
  3526. chunkGraph = this.chunkGraph,
  3527. modules = this.modules,
  3528. chunks = this.chunks,
  3529. codeGenerationResults = /** @type {CodeGenerationResults} */ (
  3530. this.codeGenerationResults
  3531. ),
  3532. chunkGraphEntries = this._getChunkGraphEntries()
  3533. } = {}) {
  3534. const context = { chunkGraph, codeGenerationResults };
  3535. const { moduleMemCaches2 } = this;
  3536. this.logger.time("runtime requirements.modules");
  3537. const additionalModuleRuntimeRequirements =
  3538. this.hooks.additionalModuleRuntimeRequirements;
  3539. const runtimeRequirementInModule = this.hooks.runtimeRequirementInModule;
  3540. for (const module of modules) {
  3541. if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
  3542. const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
  3543. for (const runtime of chunkGraph.getModuleRuntimes(module)) {
  3544. if (memCache) {
  3545. const cached = memCache.get(
  3546. `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`
  3547. );
  3548. if (cached !== undefined) {
  3549. if (cached !== null) {
  3550. chunkGraph.addModuleRuntimeRequirements(
  3551. module,
  3552. runtime,
  3553. /** @type {RuntimeRequirements} */
  3554. (cached),
  3555. false
  3556. );
  3557. }
  3558. continue;
  3559. }
  3560. }
  3561. let set;
  3562. const runtimeRequirements =
  3563. codeGenerationResults.getRuntimeRequirements(module, runtime);
  3564. if (runtimeRequirements && runtimeRequirements.size > 0) {
  3565. set = new Set(runtimeRequirements);
  3566. } else if (additionalModuleRuntimeRequirements.isUsed()) {
  3567. set = new Set();
  3568. } else {
  3569. if (memCache) {
  3570. memCache.set(
  3571. `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
  3572. null
  3573. );
  3574. }
  3575. continue;
  3576. }
  3577. additionalModuleRuntimeRequirements.call(module, set, context);
  3578. for (const r of set) {
  3579. const hook = runtimeRequirementInModule.get(r);
  3580. if (hook !== undefined) hook.call(module, set, context);
  3581. }
  3582. if (set.size === 0) {
  3583. if (memCache) {
  3584. memCache.set(
  3585. `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
  3586. null
  3587. );
  3588. }
  3589. } else if (memCache) {
  3590. memCache.set(
  3591. `moduleRuntimeRequirements-${getRuntimeKey(runtime)}`,
  3592. set
  3593. );
  3594. chunkGraph.addModuleRuntimeRequirements(
  3595. module,
  3596. runtime,
  3597. set,
  3598. false
  3599. );
  3600. } else {
  3601. chunkGraph.addModuleRuntimeRequirements(module, runtime, set);
  3602. }
  3603. }
  3604. }
  3605. }
  3606. this.logger.timeEnd("runtime requirements.modules");
  3607. this.logger.time("runtime requirements.chunks");
  3608. for (const chunk of chunks) {
  3609. /** @type {RuntimeRequirements} */
  3610. const set = new Set();
  3611. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  3612. const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
  3613. module,
  3614. chunk.runtime
  3615. );
  3616. for (const r of runtimeRequirements) set.add(r);
  3617. }
  3618. this.hooks.additionalChunkRuntimeRequirements.call(chunk, set, context);
  3619. for (const r of set) {
  3620. this.hooks.runtimeRequirementInChunk.for(r).call(chunk, set, context);
  3621. }
  3622. chunkGraph.addChunkRuntimeRequirements(chunk, set);
  3623. }
  3624. this.logger.timeEnd("runtime requirements.chunks");
  3625. this.logger.time("runtime requirements.entries");
  3626. for (const treeEntry of chunkGraphEntries) {
  3627. /** @type {RuntimeRequirements} */
  3628. const set = new Set();
  3629. for (const chunk of treeEntry.getAllReferencedChunks()) {
  3630. const runtimeRequirements =
  3631. chunkGraph.getChunkRuntimeRequirements(chunk);
  3632. for (const r of runtimeRequirements) set.add(r);
  3633. }
  3634. this.hooks.additionalTreeRuntimeRequirements.call(
  3635. treeEntry,
  3636. set,
  3637. context
  3638. );
  3639. for (const r of set) {
  3640. this.hooks.runtimeRequirementInTree
  3641. .for(r)
  3642. .call(treeEntry, set, context);
  3643. }
  3644. chunkGraph.addTreeRuntimeRequirements(treeEntry, set);
  3645. }
  3646. this.logger.timeEnd("runtime requirements.entries");
  3647. }
  3648. // TODO webpack 6 make chunkGraph argument non-optional
  3649. /**
  3650. * @param {Chunk} chunk target chunk
  3651. * @param {RuntimeModule} module runtime module
  3652. * @param {ChunkGraph} chunkGraph the chunk graph
  3653. * @returns {void}
  3654. */
  3655. addRuntimeModule(chunk, module, chunkGraph = this.chunkGraph) {
  3656. // Deprecated ModuleGraph association
  3657. if (this._backCompat) {
  3658. ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
  3659. }
  3660. // add it to the list
  3661. this.modules.add(module);
  3662. this._modules.set(module.identifier(), module);
  3663. // connect to the chunk graph
  3664. chunkGraph.connectChunkAndModule(chunk, module);
  3665. chunkGraph.connectChunkAndRuntimeModule(chunk, module);
  3666. if (module.fullHash) {
  3667. chunkGraph.addFullHashModuleToChunk(chunk, module);
  3668. } else if (module.dependentHash) {
  3669. chunkGraph.addDependentHashModuleToChunk(chunk, module);
  3670. }
  3671. // attach runtime module
  3672. module.attach(this, chunk, chunkGraph);
  3673. // Setup internals
  3674. const exportsInfo = this.moduleGraph.getExportsInfo(module);
  3675. exportsInfo.setHasProvideInfo();
  3676. if (typeof chunk.runtime === "string") {
  3677. exportsInfo.setUsedForSideEffectsOnly(chunk.runtime);
  3678. } else if (chunk.runtime === undefined) {
  3679. exportsInfo.setUsedForSideEffectsOnly(undefined);
  3680. } else {
  3681. for (const runtime of chunk.runtime) {
  3682. exportsInfo.setUsedForSideEffectsOnly(runtime);
  3683. }
  3684. }
  3685. chunkGraph.addModuleRuntimeRequirements(
  3686. module,
  3687. chunk.runtime,
  3688. new Set([RuntimeGlobals.requireScope])
  3689. );
  3690. // runtime modules don't need ids
  3691. chunkGraph.setModuleId(module, "");
  3692. // Call hook
  3693. this.hooks.runtimeModule.call(module, chunk);
  3694. }
  3695. /**
  3696. * If `module` is passed, `loc` and `request` must also be passed.
  3697. * @param {string | ChunkGroupOptions} groupOptions options for the chunk group
  3698. * @param {Module=} module the module the references the chunk group
  3699. * @param {DependencyLocation=} loc the location from with the chunk group is referenced (inside of module)
  3700. * @param {string=} request the request from which the the chunk group is referenced
  3701. * @returns {ChunkGroup} the new or existing chunk group
  3702. */
  3703. addChunkInGroup(groupOptions, module, loc, request) {
  3704. if (typeof groupOptions === "string") {
  3705. groupOptions = { name: groupOptions };
  3706. }
  3707. const name = groupOptions.name;
  3708. if (name) {
  3709. const chunkGroup = this.namedChunkGroups.get(name);
  3710. if (chunkGroup !== undefined) {
  3711. if (module) {
  3712. chunkGroup.addOrigin(
  3713. module,
  3714. /** @type {DependencyLocation} */
  3715. (loc),
  3716. /** @type {string} */
  3717. (request)
  3718. );
  3719. }
  3720. return chunkGroup;
  3721. }
  3722. }
  3723. const chunkGroup = new ChunkGroup(groupOptions);
  3724. if (module) {
  3725. chunkGroup.addOrigin(
  3726. module,
  3727. /** @type {DependencyLocation} */
  3728. (loc),
  3729. /** @type {string} */
  3730. (request)
  3731. );
  3732. }
  3733. const chunk = this.addChunk(name);
  3734. connectChunkGroupAndChunk(chunkGroup, chunk);
  3735. this.chunkGroups.push(chunkGroup);
  3736. if (name) {
  3737. this.namedChunkGroups.set(name, chunkGroup);
  3738. }
  3739. return chunkGroup;
  3740. }
  3741. /**
  3742. * @param {EntryOptions} options options for the entrypoint
  3743. * @param {Module} module the module the references the chunk group
  3744. * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
  3745. * @param {string} request the request from which the the chunk group is referenced
  3746. * @returns {Entrypoint} the new or existing entrypoint
  3747. */
  3748. addAsyncEntrypoint(options, module, loc, request) {
  3749. const name = options.name;
  3750. if (name) {
  3751. const entrypoint = this.namedChunkGroups.get(name);
  3752. if (entrypoint instanceof Entrypoint) {
  3753. if (module) {
  3754. entrypoint.addOrigin(module, loc, request);
  3755. }
  3756. return entrypoint;
  3757. } else if (entrypoint) {
  3758. throw new Error(
  3759. `Cannot add an async entrypoint with the name '${name}', because there is already an chunk group with this name`
  3760. );
  3761. }
  3762. }
  3763. const chunk = this.addChunk(name);
  3764. if (options.filename) {
  3765. chunk.filenameTemplate = options.filename;
  3766. }
  3767. const entrypoint = new Entrypoint(options, false);
  3768. entrypoint.setRuntimeChunk(chunk);
  3769. entrypoint.setEntrypointChunk(chunk);
  3770. if (name) {
  3771. this.namedChunkGroups.set(name, entrypoint);
  3772. }
  3773. this.chunkGroups.push(entrypoint);
  3774. this.asyncEntrypoints.push(entrypoint);
  3775. connectChunkGroupAndChunk(entrypoint, chunk);
  3776. if (module) {
  3777. entrypoint.addOrigin(module, loc, request);
  3778. }
  3779. return entrypoint;
  3780. }
  3781. /**
  3782. * This method first looks to see if a name is provided for a new chunk,
  3783. * and first looks to see if any named chunks already exist and reuse that chunk instead.
  3784. * @param {ChunkName=} name optional chunk name to be provided
  3785. * @returns {Chunk} create a chunk (invoked during seal event)
  3786. */
  3787. addChunk(name) {
  3788. if (name) {
  3789. const chunk = this.namedChunks.get(name);
  3790. if (chunk !== undefined) {
  3791. return chunk;
  3792. }
  3793. }
  3794. const chunk = new Chunk(name, this._backCompat);
  3795. this.chunks.add(chunk);
  3796. if (this._backCompat) {
  3797. ChunkGraph.setChunkGraphForChunk(chunk, this.chunkGraph);
  3798. }
  3799. if (name) {
  3800. this.namedChunks.set(name, chunk);
  3801. }
  3802. return chunk;
  3803. }
  3804. /**
  3805. * @deprecated
  3806. * @param {Module} module module to assign depth
  3807. * @returns {void}
  3808. */
  3809. assignDepth(module) {
  3810. const moduleGraph = this.moduleGraph;
  3811. const queue = new Set([module]);
  3812. /** @type {number} */
  3813. let depth;
  3814. moduleGraph.setDepth(module, 0);
  3815. /**
  3816. * @param {Module} module module for processing
  3817. * @returns {void}
  3818. */
  3819. const processModule = (module) => {
  3820. if (!moduleGraph.setDepthIfLower(module, depth)) return;
  3821. queue.add(module);
  3822. };
  3823. for (module of queue) {
  3824. queue.delete(module);
  3825. depth = /** @type {number} */ (moduleGraph.getDepth(module)) + 1;
  3826. for (const connection of moduleGraph.getOutgoingConnections(module)) {
  3827. const refModule = connection.module;
  3828. if (refModule) {
  3829. processModule(refModule);
  3830. }
  3831. }
  3832. }
  3833. }
  3834. /**
  3835. * @param {Set<Module>} modules module to assign depth
  3836. * @returns {void}
  3837. */
  3838. assignDepths(modules) {
  3839. const moduleGraph = this.moduleGraph;
  3840. /** @type {Set<Module>} */
  3841. const queue = new Set(modules);
  3842. // Track these in local variables so that queue only has one data type
  3843. let nextDepthAt = queue.size;
  3844. let depth = 0;
  3845. let i = 0;
  3846. for (const module of queue) {
  3847. moduleGraph.setDepth(module, depth);
  3848. // Some of these results come from cache, which speeds this up
  3849. const connections = moduleGraph.getOutgoingConnectionsByModule(module);
  3850. // connections will be undefined if there are no outgoing connections
  3851. if (connections) {
  3852. for (const refModule of connections.keys()) {
  3853. if (refModule) queue.add(refModule);
  3854. }
  3855. }
  3856. i++;
  3857. // Since this is a breadth-first search, all modules added to the queue
  3858. // while at depth N will be depth N+1
  3859. if (i >= nextDepthAt) {
  3860. depth++;
  3861. nextDepthAt = queue.size;
  3862. }
  3863. }
  3864. }
  3865. /**
  3866. * @param {Dependency} dependency the dependency
  3867. * @param {RuntimeSpec} runtime the runtime
  3868. * @returns {ReferencedExports} referenced exports
  3869. */
  3870. getDependencyReferencedExports(dependency, runtime) {
  3871. const referencedExports = dependency.getReferencedExports(
  3872. this.moduleGraph,
  3873. runtime
  3874. );
  3875. return this.hooks.dependencyReferencedExports.call(
  3876. referencedExports,
  3877. dependency,
  3878. runtime
  3879. );
  3880. }
  3881. /**
  3882. * @param {Module} module module relationship for removal
  3883. * @param {DependenciesBlockLike} block dependencies block
  3884. * @returns {void}
  3885. */
  3886. removeReasonsOfDependencyBlock(module, block) {
  3887. if (block.blocks) {
  3888. for (const b of block.blocks) {
  3889. this.removeReasonsOfDependencyBlock(module, b);
  3890. }
  3891. }
  3892. if (block.dependencies) {
  3893. for (const dep of block.dependencies) {
  3894. const originalModule = this.moduleGraph.getModule(dep);
  3895. if (originalModule) {
  3896. this.moduleGraph.removeConnection(dep);
  3897. if (this.chunkGraph) {
  3898. for (const chunk of this.chunkGraph.getModuleChunks(
  3899. originalModule
  3900. )) {
  3901. this.patchChunksAfterReasonRemoval(originalModule, chunk);
  3902. }
  3903. }
  3904. }
  3905. }
  3906. }
  3907. }
  3908. /**
  3909. * @param {Module} module module to patch tie
  3910. * @param {Chunk} chunk chunk to patch tie
  3911. * @returns {void}
  3912. */
  3913. patchChunksAfterReasonRemoval(module, chunk) {
  3914. if (!module.hasReasons(this.moduleGraph, chunk.runtime)) {
  3915. this.removeReasonsOfDependencyBlock(module, module);
  3916. }
  3917. if (
  3918. !module.hasReasonForChunk(chunk, this.moduleGraph, this.chunkGraph) &&
  3919. this.chunkGraph.isModuleInChunk(module, chunk)
  3920. ) {
  3921. this.chunkGraph.disconnectChunkAndModule(chunk, module);
  3922. this.removeChunkFromDependencies(module, chunk);
  3923. }
  3924. }
  3925. /**
  3926. * @param {DependenciesBlock} block block tie for Chunk
  3927. * @param {Chunk} chunk chunk to remove from dep
  3928. * @returns {void}
  3929. */
  3930. removeChunkFromDependencies(block, chunk) {
  3931. /**
  3932. * @param {Dependency} d dependency to (maybe) patch up
  3933. */
  3934. const iteratorDependency = (d) => {
  3935. const depModule = this.moduleGraph.getModule(d);
  3936. if (!depModule) {
  3937. return;
  3938. }
  3939. this.patchChunksAfterReasonRemoval(depModule, chunk);
  3940. };
  3941. const blocks = block.blocks;
  3942. for (const asyncBlock of blocks) {
  3943. const chunkGroup =
  3944. /** @type {ChunkGroup} */
  3945. (this.chunkGraph.getBlockChunkGroup(asyncBlock));
  3946. // Grab all chunks from the first Block's AsyncDepBlock
  3947. const chunks = chunkGroup.chunks;
  3948. // For each chunk in chunkGroup
  3949. for (const iteratedChunk of chunks) {
  3950. chunkGroup.removeChunk(iteratedChunk);
  3951. // Recurse
  3952. this.removeChunkFromDependencies(block, iteratedChunk);
  3953. }
  3954. }
  3955. if (block.dependencies) {
  3956. for (const dep of block.dependencies) iteratorDependency(dep);
  3957. }
  3958. }
  3959. assignRuntimeIds() {
  3960. const { chunkGraph } = this;
  3961. /**
  3962. * @param {Entrypoint} ep an entrypoint
  3963. */
  3964. const processEntrypoint = (ep) => {
  3965. const runtime = /** @type {string} */ (ep.options.runtime || ep.name);
  3966. const chunk = /** @type {Chunk} */ (ep.getRuntimeChunk());
  3967. chunkGraph.setRuntimeId(runtime, /** @type {ChunkId} */ (chunk.id));
  3968. };
  3969. for (const ep of this.entrypoints.values()) {
  3970. processEntrypoint(ep);
  3971. }
  3972. for (const ep of this.asyncEntrypoints) {
  3973. processEntrypoint(ep);
  3974. }
  3975. }
  3976. sortItemsWithChunkIds() {
  3977. for (const chunkGroup of this.chunkGroups) {
  3978. chunkGroup.sortItems();
  3979. }
  3980. this.errors.sort(compareErrors);
  3981. this.warnings.sort(compareErrors);
  3982. this.children.sort(byNameOrHash);
  3983. }
  3984. summarizeDependencies() {
  3985. for (const child of this.children) {
  3986. this.fileDependencies.addAll(child.fileDependencies);
  3987. this.contextDependencies.addAll(child.contextDependencies);
  3988. this.missingDependencies.addAll(child.missingDependencies);
  3989. this.buildDependencies.addAll(child.buildDependencies);
  3990. }
  3991. for (const module of this.modules) {
  3992. module.addCacheDependencies(
  3993. this.fileDependencies,
  3994. this.contextDependencies,
  3995. this.missingDependencies,
  3996. this.buildDependencies
  3997. );
  3998. }
  3999. }
  4000. createModuleHashes() {
  4001. let statModulesHashed = 0;
  4002. let statModulesFromCache = 0;
  4003. const { chunkGraph, runtimeTemplate, moduleMemCaches2 } = this;
  4004. const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
  4005. /** @type {WebpackError[]} */
  4006. const errors = [];
  4007. for (const module of this.modules) {
  4008. const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
  4009. for (const runtime of chunkGraph.getModuleRuntimes(module)) {
  4010. if (memCache) {
  4011. const digest =
  4012. /** @type {string} */
  4013. (memCache.get(`moduleHash-${getRuntimeKey(runtime)}`));
  4014. if (digest !== undefined) {
  4015. chunkGraph.setModuleHashes(
  4016. module,
  4017. runtime,
  4018. digest,
  4019. digest.slice(0, hashDigestLength)
  4020. );
  4021. statModulesFromCache++;
  4022. continue;
  4023. }
  4024. }
  4025. statModulesHashed++;
  4026. const digest = this._createModuleHash(
  4027. module,
  4028. chunkGraph,
  4029. runtime,
  4030. hashFunction,
  4031. runtimeTemplate,
  4032. hashDigest,
  4033. hashDigestLength,
  4034. errors
  4035. );
  4036. if (memCache) {
  4037. memCache.set(`moduleHash-${getRuntimeKey(runtime)}`, digest);
  4038. }
  4039. }
  4040. }
  4041. if (errors.length > 0) {
  4042. errors.sort(
  4043. compareSelect((err) => err.module, compareModulesByIdentifier)
  4044. );
  4045. for (const error of errors) {
  4046. this.errors.push(error);
  4047. }
  4048. }
  4049. this.logger.log(
  4050. `${statModulesHashed} modules hashed, ${statModulesFromCache} from cache (${
  4051. Math.round(
  4052. (100 * (statModulesHashed + statModulesFromCache)) / this.modules.size
  4053. ) / 100
  4054. } variants per module in average)`
  4055. );
  4056. }
  4057. /**
  4058. * @private
  4059. * @param {Module} module module
  4060. * @param {ChunkGraph} chunkGraph the chunk graph
  4061. * @param {RuntimeSpec} runtime runtime
  4062. * @param {HashFunction} hashFunction hash function
  4063. * @param {RuntimeTemplate} runtimeTemplate runtime template
  4064. * @param {HashDigest} hashDigest hash digest
  4065. * @param {HashDigestLength} hashDigestLength hash digest length
  4066. * @param {WebpackError[]} errors errors
  4067. * @returns {string} module hash digest
  4068. */
  4069. _createModuleHash(
  4070. module,
  4071. chunkGraph,
  4072. runtime,
  4073. hashFunction,
  4074. runtimeTemplate,
  4075. hashDigest,
  4076. hashDigestLength,
  4077. errors
  4078. ) {
  4079. let moduleHashDigest;
  4080. try {
  4081. const moduleHash = createHash(hashFunction);
  4082. module.updateHash(moduleHash, {
  4083. chunkGraph,
  4084. runtime,
  4085. runtimeTemplate
  4086. });
  4087. moduleHashDigest = moduleHash.digest(hashDigest);
  4088. } catch (err) {
  4089. errors.push(new ModuleHashingError(module, /** @type {Error} */ (err)));
  4090. moduleHashDigest = "XXXXXX";
  4091. }
  4092. chunkGraph.setModuleHashes(
  4093. module,
  4094. runtime,
  4095. moduleHashDigest,
  4096. moduleHashDigest.slice(0, hashDigestLength)
  4097. );
  4098. return moduleHashDigest;
  4099. }
  4100. createHash() {
  4101. this.logger.time("hashing: initialize hash");
  4102. const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
  4103. const runtimeTemplate = this.runtimeTemplate;
  4104. const outputOptions = this.outputOptions;
  4105. const hashFunction = outputOptions.hashFunction;
  4106. const hashDigest = outputOptions.hashDigest;
  4107. const hashDigestLength = outputOptions.hashDigestLength;
  4108. const hash = createHash(hashFunction);
  4109. if (outputOptions.hashSalt) {
  4110. hash.update(outputOptions.hashSalt);
  4111. }
  4112. this.logger.timeEnd("hashing: initialize hash");
  4113. if (this.children.length > 0) {
  4114. this.logger.time("hashing: hash child compilations");
  4115. for (const child of this.children) {
  4116. hash.update(/** @type {string} */ (child.hash));
  4117. }
  4118. this.logger.timeEnd("hashing: hash child compilations");
  4119. }
  4120. if (this.warnings.length > 0) {
  4121. this.logger.time("hashing: hash warnings");
  4122. for (const warning of this.warnings) {
  4123. hash.update(`${warning.message}`);
  4124. }
  4125. this.logger.timeEnd("hashing: hash warnings");
  4126. }
  4127. if (this.errors.length > 0) {
  4128. this.logger.time("hashing: hash errors");
  4129. for (const error of this.errors) {
  4130. hash.update(`${error.message}`);
  4131. }
  4132. this.logger.timeEnd("hashing: hash errors");
  4133. }
  4134. this.logger.time("hashing: sort chunks");
  4135. /*
  4136. * all non-runtime chunks need to be hashes first,
  4137. * since runtime chunk might use their hashes.
  4138. * runtime chunks need to be hashed in the correct order
  4139. * since they may depend on each other (for async entrypoints).
  4140. * So we put all non-runtime chunks first and hash them in any order.
  4141. * And order runtime chunks according to referenced between each other.
  4142. * Chunks need to be in deterministic order since we add hashes to full chunk
  4143. * during these hashing.
  4144. */
  4145. /** @type {Chunk[]} */
  4146. const unorderedRuntimeChunks = [];
  4147. /** @type {Chunk[]} */
  4148. const initialChunks = [];
  4149. /** @type {Chunk[]} */
  4150. const asyncChunks = [];
  4151. for (const c of this.chunks) {
  4152. if (c.hasRuntime()) {
  4153. unorderedRuntimeChunks.push(c);
  4154. } else if (c.canBeInitial()) {
  4155. initialChunks.push(c);
  4156. } else {
  4157. asyncChunks.push(c);
  4158. }
  4159. }
  4160. unorderedRuntimeChunks.sort(byId);
  4161. initialChunks.sort(byId);
  4162. asyncChunks.sort(byId);
  4163. /** @typedef {{ chunk: Chunk, referencedBy: RuntimeChunkInfo[], remaining: number }} RuntimeChunkInfo */
  4164. /** @type {Map<Chunk, RuntimeChunkInfo>} */
  4165. const runtimeChunksMap = new Map();
  4166. for (const chunk of unorderedRuntimeChunks) {
  4167. runtimeChunksMap.set(chunk, {
  4168. chunk,
  4169. referencedBy: [],
  4170. remaining: 0
  4171. });
  4172. }
  4173. let remaining = 0;
  4174. for (const info of runtimeChunksMap.values()) {
  4175. for (const other of new Set(
  4176. [...info.chunk.getAllReferencedAsyncEntrypoints()].map(
  4177. (e) => e.chunks[e.chunks.length - 1]
  4178. )
  4179. )) {
  4180. const otherInfo =
  4181. /** @type {RuntimeChunkInfo} */
  4182. (runtimeChunksMap.get(other));
  4183. otherInfo.referencedBy.push(info);
  4184. info.remaining++;
  4185. remaining++;
  4186. }
  4187. }
  4188. /** @type {Chunk[]} */
  4189. const runtimeChunks = [];
  4190. for (const info of runtimeChunksMap.values()) {
  4191. if (info.remaining === 0) {
  4192. runtimeChunks.push(info.chunk);
  4193. }
  4194. }
  4195. // If there are any references between chunks
  4196. // make sure to follow these chains
  4197. if (remaining > 0) {
  4198. const readyChunks = [];
  4199. for (const chunk of runtimeChunks) {
  4200. const hasFullHashModules =
  4201. chunkGraph.getNumberOfChunkFullHashModules(chunk) !== 0;
  4202. const info =
  4203. /** @type {RuntimeChunkInfo} */
  4204. (runtimeChunksMap.get(chunk));
  4205. for (const otherInfo of info.referencedBy) {
  4206. if (hasFullHashModules) {
  4207. chunkGraph.upgradeDependentToFullHashModules(otherInfo.chunk);
  4208. }
  4209. remaining--;
  4210. if (--otherInfo.remaining === 0) {
  4211. readyChunks.push(otherInfo.chunk);
  4212. }
  4213. }
  4214. if (readyChunks.length > 0) {
  4215. // This ensures deterministic ordering, since referencedBy is non-deterministic
  4216. readyChunks.sort(byId);
  4217. for (const c of readyChunks) runtimeChunks.push(c);
  4218. readyChunks.length = 0;
  4219. }
  4220. }
  4221. }
  4222. // If there are still remaining references we have cycles and want to create a warning
  4223. if (remaining > 0) {
  4224. const circularRuntimeChunkInfo = [];
  4225. for (const info of runtimeChunksMap.values()) {
  4226. if (info.remaining !== 0) {
  4227. circularRuntimeChunkInfo.push(info);
  4228. }
  4229. }
  4230. circularRuntimeChunkInfo.sort(compareSelect((i) => i.chunk, byId));
  4231. const err =
  4232. new WebpackError(`Circular dependency between chunks with runtime (${Array.from(
  4233. circularRuntimeChunkInfo,
  4234. (c) => c.chunk.name || c.chunk.id
  4235. ).join(", ")})
  4236. This prevents using hashes of each other and should be avoided.`);
  4237. err.chunk = circularRuntimeChunkInfo[0].chunk;
  4238. this.warnings.push(err);
  4239. for (const i of circularRuntimeChunkInfo) runtimeChunks.push(i.chunk);
  4240. }
  4241. this.logger.timeEnd("hashing: sort chunks");
  4242. const fullHashChunks = new Set();
  4243. /** @type {CodeGenerationJobs} */
  4244. const codeGenerationJobs = [];
  4245. /** @type {Map<string, Map<Module, CodeGenerationJob>>} */
  4246. const codeGenerationJobsMap = new Map();
  4247. /** @type {WebpackError[]} */
  4248. const errors = [];
  4249. /**
  4250. * @param {Chunk} chunk chunk
  4251. */
  4252. const processChunk = (chunk) => {
  4253. // Last minute module hash generation for modules that depend on chunk hashes
  4254. this.logger.time("hashing: hash runtime modules");
  4255. const runtime = chunk.runtime;
  4256. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  4257. if (!chunkGraph.hasModuleHashes(module, runtime)) {
  4258. const hash = this._createModuleHash(
  4259. module,
  4260. chunkGraph,
  4261. runtime,
  4262. hashFunction,
  4263. runtimeTemplate,
  4264. hashDigest,
  4265. hashDigestLength,
  4266. errors
  4267. );
  4268. let hashMap = codeGenerationJobsMap.get(hash);
  4269. if (hashMap) {
  4270. const moduleJob = hashMap.get(module);
  4271. if (moduleJob) {
  4272. moduleJob.runtimes.push(runtime);
  4273. continue;
  4274. }
  4275. } else {
  4276. hashMap = new Map();
  4277. codeGenerationJobsMap.set(hash, hashMap);
  4278. }
  4279. const job = {
  4280. module,
  4281. hash,
  4282. runtime,
  4283. runtimes: [runtime]
  4284. };
  4285. hashMap.set(module, job);
  4286. codeGenerationJobs.push(job);
  4287. }
  4288. }
  4289. this.logger.timeAggregate("hashing: hash runtime modules");
  4290. try {
  4291. this.logger.time("hashing: hash chunks");
  4292. const chunkHash = createHash(hashFunction);
  4293. if (outputOptions.hashSalt) {
  4294. chunkHash.update(outputOptions.hashSalt);
  4295. }
  4296. chunk.updateHash(chunkHash, chunkGraph);
  4297. this.hooks.chunkHash.call(chunk, chunkHash, {
  4298. chunkGraph,
  4299. codeGenerationResults:
  4300. /** @type {CodeGenerationResults} */
  4301. (this.codeGenerationResults),
  4302. moduleGraph: this.moduleGraph,
  4303. runtimeTemplate: this.runtimeTemplate
  4304. });
  4305. const chunkHashDigest = chunkHash.digest(hashDigest);
  4306. hash.update(chunkHashDigest);
  4307. chunk.hash = chunkHashDigest;
  4308. chunk.renderedHash = chunk.hash.slice(0, hashDigestLength);
  4309. const fullHashModules =
  4310. chunkGraph.getChunkFullHashModulesIterable(chunk);
  4311. if (fullHashModules) {
  4312. fullHashChunks.add(chunk);
  4313. } else {
  4314. this.hooks.contentHash.call(chunk);
  4315. }
  4316. } catch (err) {
  4317. this.errors.push(
  4318. new ChunkRenderError(chunk, "", /** @type {Error} */ (err))
  4319. );
  4320. }
  4321. this.logger.timeAggregate("hashing: hash chunks");
  4322. };
  4323. for (const chunk of asyncChunks) processChunk(chunk);
  4324. for (const chunk of runtimeChunks) processChunk(chunk);
  4325. for (const chunk of initialChunks) processChunk(chunk);
  4326. if (errors.length > 0) {
  4327. errors.sort(
  4328. compareSelect((err) => err.module, compareModulesByIdentifier)
  4329. );
  4330. for (const error of errors) {
  4331. this.errors.push(error);
  4332. }
  4333. }
  4334. this.logger.timeAggregateEnd("hashing: hash runtime modules");
  4335. this.logger.timeAggregateEnd("hashing: hash chunks");
  4336. this.logger.time("hashing: hash digest");
  4337. this.hooks.fullHash.call(hash);
  4338. this.fullHash = hash.digest(hashDigest);
  4339. this.hash = this.fullHash.slice(0, hashDigestLength);
  4340. this.logger.timeEnd("hashing: hash digest");
  4341. this.logger.time("hashing: process full hash modules");
  4342. for (const chunk of fullHashChunks) {
  4343. for (const module of /** @type {Iterable<RuntimeModule>} */ (
  4344. chunkGraph.getChunkFullHashModulesIterable(chunk)
  4345. )) {
  4346. const moduleHash = createHash(hashFunction);
  4347. module.updateHash(moduleHash, {
  4348. chunkGraph,
  4349. runtime: chunk.runtime,
  4350. runtimeTemplate
  4351. });
  4352. const moduleHashDigest = moduleHash.digest(hashDigest);
  4353. const oldHash = chunkGraph.getModuleHash(module, chunk.runtime);
  4354. chunkGraph.setModuleHashes(
  4355. module,
  4356. chunk.runtime,
  4357. moduleHashDigest,
  4358. moduleHashDigest.slice(0, hashDigestLength)
  4359. );
  4360. /** @type {CodeGenerationJob} */
  4361. (
  4362. /** @type {Map<Module, CodeGenerationJob>} */
  4363. (codeGenerationJobsMap.get(oldHash)).get(module)
  4364. ).hash = moduleHashDigest;
  4365. }
  4366. const chunkHash = createHash(hashFunction);
  4367. chunkHash.update(chunk.hash);
  4368. chunkHash.update(this.hash);
  4369. const chunkHashDigest = chunkHash.digest(hashDigest);
  4370. chunk.hash = chunkHashDigest;
  4371. chunk.renderedHash = chunk.hash.slice(0, hashDigestLength);
  4372. this.hooks.contentHash.call(chunk);
  4373. }
  4374. this.logger.timeEnd("hashing: process full hash modules");
  4375. return codeGenerationJobs;
  4376. }
  4377. /**
  4378. * @param {string} file file name
  4379. * @param {Source} source asset source
  4380. * @param {AssetInfo} assetInfo extra asset information
  4381. * @returns {void}
  4382. */
  4383. emitAsset(file, source, assetInfo = {}) {
  4384. if (this.assets[file]) {
  4385. if (!isSourceEqual(this.assets[file], source)) {
  4386. this.errors.push(
  4387. new WebpackError(
  4388. `Conflict: Multiple assets emit different content to the same filename ${file}${
  4389. assetInfo.sourceFilename
  4390. ? `. Original source ${assetInfo.sourceFilename}`
  4391. : ""
  4392. }`
  4393. )
  4394. );
  4395. this.assets[file] = source;
  4396. this._setAssetInfo(file, assetInfo);
  4397. return;
  4398. }
  4399. const oldInfo = this.assetsInfo.get(file);
  4400. const newInfo = { ...oldInfo, ...assetInfo };
  4401. this._setAssetInfo(file, newInfo, oldInfo);
  4402. return;
  4403. }
  4404. this.assets[file] = source;
  4405. this._setAssetInfo(file, assetInfo, undefined);
  4406. }
  4407. /**
  4408. * @private
  4409. * @param {string} file file name
  4410. * @param {AssetInfo=} newInfo new asset information
  4411. * @param {AssetInfo=} oldInfo old asset information
  4412. */
  4413. _setAssetInfo(file, newInfo, oldInfo = this.assetsInfo.get(file)) {
  4414. if (newInfo === undefined) {
  4415. this.assetsInfo.delete(file);
  4416. } else {
  4417. this.assetsInfo.set(file, newInfo);
  4418. }
  4419. const oldRelated = oldInfo && oldInfo.related;
  4420. const newRelated = newInfo && newInfo.related;
  4421. if (oldRelated) {
  4422. for (const key of Object.keys(oldRelated)) {
  4423. /**
  4424. * @param {string} name name
  4425. */
  4426. const remove = (name) => {
  4427. const relatedIn = this._assetsRelatedIn.get(name);
  4428. if (relatedIn === undefined) return;
  4429. const entry = relatedIn.get(key);
  4430. if (entry === undefined) return;
  4431. entry.delete(file);
  4432. if (entry.size !== 0) return;
  4433. relatedIn.delete(key);
  4434. if (relatedIn.size === 0) this._assetsRelatedIn.delete(name);
  4435. };
  4436. const entry = oldRelated[key];
  4437. if (Array.isArray(entry)) {
  4438. for (const name of entry) {
  4439. remove(name);
  4440. }
  4441. } else if (entry) {
  4442. remove(entry);
  4443. }
  4444. }
  4445. }
  4446. if (newRelated) {
  4447. for (const key of Object.keys(newRelated)) {
  4448. /**
  4449. * @param {string} name name
  4450. */
  4451. const add = (name) => {
  4452. let relatedIn = this._assetsRelatedIn.get(name);
  4453. if (relatedIn === undefined) {
  4454. this._assetsRelatedIn.set(name, (relatedIn = new Map()));
  4455. }
  4456. let entry = relatedIn.get(key);
  4457. if (entry === undefined) {
  4458. relatedIn.set(key, (entry = new Set()));
  4459. }
  4460. entry.add(file);
  4461. };
  4462. const entry = newRelated[key];
  4463. if (Array.isArray(entry)) {
  4464. for (const name of entry) {
  4465. add(name);
  4466. }
  4467. } else if (entry) {
  4468. add(entry);
  4469. }
  4470. }
  4471. }
  4472. }
  4473. /**
  4474. * @param {string} file file name
  4475. * @param {Source | ((source: Source) => Source)} newSourceOrFunction new asset source or function converting old to new
  4476. * @param {(AssetInfo | ((assetInfo?: AssetInfo) => AssetInfo | undefined)) | undefined} assetInfoUpdateOrFunction new asset info or function converting old to new
  4477. */
  4478. updateAsset(
  4479. file,
  4480. newSourceOrFunction,
  4481. assetInfoUpdateOrFunction = undefined
  4482. ) {
  4483. if (!this.assets[file]) {
  4484. throw new Error(
  4485. `Called Compilation.updateAsset for not existing filename ${file}`
  4486. );
  4487. }
  4488. this.assets[file] =
  4489. typeof newSourceOrFunction === "function"
  4490. ? newSourceOrFunction(this.assets[file])
  4491. : newSourceOrFunction;
  4492. if (assetInfoUpdateOrFunction !== undefined) {
  4493. const oldInfo = this.assetsInfo.get(file) || EMPTY_ASSET_INFO;
  4494. if (typeof assetInfoUpdateOrFunction === "function") {
  4495. this._setAssetInfo(file, assetInfoUpdateOrFunction(oldInfo), oldInfo);
  4496. } else {
  4497. this._setAssetInfo(
  4498. file,
  4499. cachedCleverMerge(oldInfo, assetInfoUpdateOrFunction),
  4500. oldInfo
  4501. );
  4502. }
  4503. }
  4504. }
  4505. /**
  4506. * @param {string} file file name
  4507. * @param {string} newFile the new name of file
  4508. */
  4509. renameAsset(file, newFile) {
  4510. const source = this.assets[file];
  4511. if (!source) {
  4512. throw new Error(
  4513. `Called Compilation.renameAsset for not existing filename ${file}`
  4514. );
  4515. }
  4516. if (this.assets[newFile] && !isSourceEqual(this.assets[file], source)) {
  4517. this.errors.push(
  4518. new WebpackError(
  4519. `Conflict: Called Compilation.renameAsset for already existing filename ${newFile} with different content`
  4520. )
  4521. );
  4522. }
  4523. const assetInfo = this.assetsInfo.get(file);
  4524. // Update related in all other assets
  4525. const relatedInInfo = this._assetsRelatedIn.get(file);
  4526. if (relatedInInfo) {
  4527. for (const [key, assets] of relatedInInfo) {
  4528. for (const name of assets) {
  4529. const info = this.assetsInfo.get(name);
  4530. if (!info) continue;
  4531. const related = info.related;
  4532. if (!related) continue;
  4533. const entry = related[key];
  4534. let newEntry;
  4535. if (Array.isArray(entry)) {
  4536. newEntry = entry.map((x) => (x === file ? newFile : x));
  4537. } else if (entry === file) {
  4538. newEntry = newFile;
  4539. } else {
  4540. continue;
  4541. }
  4542. this.assetsInfo.set(name, {
  4543. ...info,
  4544. related: {
  4545. ...related,
  4546. [key]: newEntry
  4547. }
  4548. });
  4549. }
  4550. }
  4551. }
  4552. this._setAssetInfo(file, undefined, assetInfo);
  4553. this._setAssetInfo(newFile, assetInfo);
  4554. delete this.assets[file];
  4555. this.assets[newFile] = source;
  4556. for (const chunk of this.chunks) {
  4557. {
  4558. const size = chunk.files.size;
  4559. chunk.files.delete(file);
  4560. if (size !== chunk.files.size) {
  4561. chunk.files.add(newFile);
  4562. }
  4563. }
  4564. {
  4565. const size = chunk.auxiliaryFiles.size;
  4566. chunk.auxiliaryFiles.delete(file);
  4567. if (size !== chunk.auxiliaryFiles.size) {
  4568. chunk.auxiliaryFiles.add(newFile);
  4569. }
  4570. }
  4571. }
  4572. }
  4573. /**
  4574. * @param {string} file file name
  4575. */
  4576. deleteAsset(file) {
  4577. if (!this.assets[file]) {
  4578. return;
  4579. }
  4580. delete this.assets[file];
  4581. const assetInfo = this.assetsInfo.get(file);
  4582. this._setAssetInfo(file, undefined, assetInfo);
  4583. const related = assetInfo && assetInfo.related;
  4584. if (related) {
  4585. for (const key of Object.keys(related)) {
  4586. /**
  4587. * @param {string} file file
  4588. */
  4589. const checkUsedAndDelete = (file) => {
  4590. if (!this._assetsRelatedIn.has(file)) {
  4591. this.deleteAsset(file);
  4592. }
  4593. };
  4594. const items = related[key];
  4595. if (Array.isArray(items)) {
  4596. for (const file of items) {
  4597. checkUsedAndDelete(file);
  4598. }
  4599. } else if (items) {
  4600. checkUsedAndDelete(items);
  4601. }
  4602. }
  4603. }
  4604. // TODO If this becomes a performance problem
  4605. // store a reverse mapping from asset to chunk
  4606. for (const chunk of this.chunks) {
  4607. chunk.files.delete(file);
  4608. chunk.auxiliaryFiles.delete(file);
  4609. }
  4610. }
  4611. getAssets() {
  4612. /** @type {Readonly<Asset>[]} */
  4613. const array = [];
  4614. for (const assetName of Object.keys(this.assets)) {
  4615. if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) {
  4616. array.push({
  4617. name: assetName,
  4618. source: this.assets[assetName],
  4619. info: this.assetsInfo.get(assetName) || EMPTY_ASSET_INFO
  4620. });
  4621. }
  4622. }
  4623. return array;
  4624. }
  4625. /**
  4626. * @param {string} name the name of the asset
  4627. * @returns {Readonly<Asset> | undefined} the asset or undefined when not found
  4628. */
  4629. getAsset(name) {
  4630. if (!Object.prototype.hasOwnProperty.call(this.assets, name)) return;
  4631. return {
  4632. name,
  4633. source: this.assets[name],
  4634. info: this.assetsInfo.get(name) || EMPTY_ASSET_INFO
  4635. };
  4636. }
  4637. clearAssets() {
  4638. for (const chunk of this.chunks) {
  4639. chunk.files.clear();
  4640. chunk.auxiliaryFiles.clear();
  4641. }
  4642. }
  4643. createModuleAssets() {
  4644. const { chunkGraph } = this;
  4645. for (const module of this.modules) {
  4646. const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
  4647. if (buildInfo.assets) {
  4648. const assetsInfo = buildInfo.assetsInfo;
  4649. for (const assetName of Object.keys(buildInfo.assets)) {
  4650. const fileName = this.getPath(assetName, {
  4651. chunkGraph: this.chunkGraph,
  4652. module
  4653. });
  4654. for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
  4655. chunk.auxiliaryFiles.add(fileName);
  4656. }
  4657. this.emitAsset(
  4658. fileName,
  4659. buildInfo.assets[assetName],
  4660. assetsInfo ? assetsInfo.get(assetName) : undefined
  4661. );
  4662. this.hooks.moduleAsset.call(module, fileName);
  4663. }
  4664. }
  4665. }
  4666. }
  4667. /**
  4668. * @param {RenderManifestOptions} options options object
  4669. * @returns {RenderManifestEntry[]} manifest entries
  4670. */
  4671. getRenderManifest(options) {
  4672. return this.hooks.renderManifest.call([], options);
  4673. }
  4674. /**
  4675. * @param {Callback} callback signals when the call finishes
  4676. * @returns {void}
  4677. */
  4678. createChunkAssets(callback) {
  4679. const outputOptions = this.outputOptions;
  4680. const cachedSourceMap = new WeakMap();
  4681. /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
  4682. const alreadyWrittenFiles = new Map();
  4683. asyncLib.forEachLimit(
  4684. this.chunks,
  4685. 15,
  4686. (chunk, callback) => {
  4687. /** @type {RenderManifestEntry[]} */
  4688. let manifest;
  4689. try {
  4690. manifest = this.getRenderManifest({
  4691. chunk,
  4692. hash: /** @type {string} */ (this.hash),
  4693. fullHash: /** @type {string} */ (this.fullHash),
  4694. outputOptions,
  4695. codeGenerationResults:
  4696. /** @type {CodeGenerationResults} */
  4697. (this.codeGenerationResults),
  4698. moduleTemplates: this.moduleTemplates,
  4699. dependencyTemplates: this.dependencyTemplates,
  4700. chunkGraph: this.chunkGraph,
  4701. moduleGraph: this.moduleGraph,
  4702. runtimeTemplate: this.runtimeTemplate
  4703. });
  4704. } catch (err) {
  4705. this.errors.push(
  4706. new ChunkRenderError(chunk, "", /** @type {Error} */ (err))
  4707. );
  4708. return callback();
  4709. }
  4710. asyncLib.each(
  4711. manifest,
  4712. (fileManifest, callback) => {
  4713. const ident = fileManifest.identifier;
  4714. const usedHash = /** @type {string} */ (fileManifest.hash);
  4715. const assetCacheItem = this._assetsCache.getItemCache(
  4716. ident,
  4717. usedHash
  4718. );
  4719. assetCacheItem.get((err, sourceFromCache) => {
  4720. /** @type {TemplatePath} */
  4721. let filenameTemplate;
  4722. /** @type {string} */
  4723. let file;
  4724. /** @type {AssetInfo} */
  4725. let assetInfo;
  4726. let inTry = true;
  4727. /**
  4728. * @param {Error} err error
  4729. * @returns {void}
  4730. */
  4731. const errorAndCallback = (err) => {
  4732. const filename =
  4733. file ||
  4734. (typeof file === "string"
  4735. ? file
  4736. : typeof filenameTemplate === "string"
  4737. ? filenameTemplate
  4738. : "");
  4739. this.errors.push(new ChunkRenderError(chunk, filename, err));
  4740. inTry = false;
  4741. return callback();
  4742. };
  4743. try {
  4744. if ("filename" in fileManifest) {
  4745. file = fileManifest.filename;
  4746. assetInfo = fileManifest.info;
  4747. } else {
  4748. filenameTemplate = fileManifest.filenameTemplate;
  4749. const pathAndInfo = this.getPathWithInfo(
  4750. filenameTemplate,
  4751. fileManifest.pathOptions
  4752. );
  4753. file = pathAndInfo.path;
  4754. assetInfo = fileManifest.info
  4755. ? {
  4756. ...pathAndInfo.info,
  4757. ...fileManifest.info
  4758. }
  4759. : pathAndInfo.info;
  4760. }
  4761. if (err) {
  4762. return errorAndCallback(err);
  4763. }
  4764. let source = sourceFromCache;
  4765. // check if the same filename was already written by another chunk
  4766. const alreadyWritten = alreadyWrittenFiles.get(file);
  4767. if (alreadyWritten !== undefined) {
  4768. if (alreadyWritten.hash !== usedHash) {
  4769. inTry = false;
  4770. return callback(
  4771. new WebpackError(
  4772. `Conflict: Multiple chunks emit assets to the same filename ${file}` +
  4773. ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
  4774. )
  4775. );
  4776. }
  4777. source = alreadyWritten.source;
  4778. } else if (!source) {
  4779. // render the asset
  4780. source = fileManifest.render();
  4781. // Ensure that source is a cached source to avoid additional cost because of repeated access
  4782. if (!(source instanceof CachedSource)) {
  4783. const cacheEntry = cachedSourceMap.get(source);
  4784. if (cacheEntry) {
  4785. source = cacheEntry;
  4786. } else {
  4787. const cachedSource = new CachedSource(source);
  4788. cachedSourceMap.set(source, cachedSource);
  4789. source = cachedSource;
  4790. }
  4791. }
  4792. }
  4793. this.emitAsset(file, source, assetInfo);
  4794. if (fileManifest.auxiliary) {
  4795. chunk.auxiliaryFiles.add(file);
  4796. } else {
  4797. chunk.files.add(file);
  4798. }
  4799. this.hooks.chunkAsset.call(chunk, file);
  4800. alreadyWrittenFiles.set(file, {
  4801. hash: usedHash,
  4802. source,
  4803. chunk
  4804. });
  4805. if (source !== sourceFromCache) {
  4806. assetCacheItem.store(source, (err) => {
  4807. if (err) return errorAndCallback(err);
  4808. inTry = false;
  4809. return callback();
  4810. });
  4811. } else {
  4812. inTry = false;
  4813. callback();
  4814. }
  4815. } catch (err) {
  4816. if (!inTry) throw err;
  4817. errorAndCallback(/** @type {Error} */ (err));
  4818. }
  4819. });
  4820. },
  4821. callback
  4822. );
  4823. },
  4824. callback
  4825. );
  4826. }
  4827. /**
  4828. * @param {TemplatePath} filename used to get asset path with hash
  4829. * @param {PathData} data context data
  4830. * @returns {string} interpolated path
  4831. */
  4832. getPath(filename, data = {}) {
  4833. if (!data.hash) {
  4834. data = {
  4835. hash: this.hash,
  4836. ...data
  4837. };
  4838. }
  4839. return this.getAssetPath(filename, data);
  4840. }
  4841. /**
  4842. * @param {TemplatePath} filename used to get asset path with hash
  4843. * @param {PathData} data context data
  4844. * @returns {InterpolatedPathAndAssetInfo} interpolated path and asset info
  4845. */
  4846. getPathWithInfo(filename, data = {}) {
  4847. if (!data.hash) {
  4848. data = {
  4849. hash: this.hash,
  4850. ...data
  4851. };
  4852. }
  4853. return this.getAssetPathWithInfo(filename, data);
  4854. }
  4855. /**
  4856. * @param {TemplatePath} filename used to get asset path with hash
  4857. * @param {PathData} data context data
  4858. * @returns {string} interpolated path
  4859. */
  4860. getAssetPath(filename, data) {
  4861. return this.hooks.assetPath.call(
  4862. typeof filename === "function" ? filename(data) : filename,
  4863. data,
  4864. undefined
  4865. );
  4866. }
  4867. /**
  4868. * @param {TemplatePath} filename used to get asset path with hash
  4869. * @param {PathData} data context data
  4870. * @returns {InterpolatedPathAndAssetInfo} interpolated path and asset info
  4871. */
  4872. getAssetPathWithInfo(filename, data) {
  4873. const assetInfo = {};
  4874. // TODO webpack 5: refactor assetPath hook to receive { path, info } object
  4875. const newPath = this.hooks.assetPath.call(
  4876. typeof filename === "function" ? filename(data, assetInfo) : filename,
  4877. data,
  4878. assetInfo
  4879. );
  4880. return { path: newPath, info: assetInfo };
  4881. }
  4882. getWarnings() {
  4883. return this.hooks.processWarnings.call(this.warnings);
  4884. }
  4885. getErrors() {
  4886. return this.hooks.processErrors.call(this.errors);
  4887. }
  4888. /**
  4889. * This function allows you to run another instance of webpack inside of webpack however as
  4890. * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
  4891. * from parent (or top level compiler) and creates a child Compilation
  4892. * @param {string} name name of the child compiler
  4893. * @param {Partial<OutputOptions>=} outputOptions // Need to convert config schema to types for this
  4894. * @param {Plugins=} plugins webpack plugins that will be applied
  4895. * @returns {Compiler} creates a child Compiler instance
  4896. */
  4897. createChildCompiler(name, outputOptions, plugins) {
  4898. const idx = this.childrenCounters[name] || 0;
  4899. this.childrenCounters[name] = idx + 1;
  4900. return this.compiler.createChildCompiler(
  4901. this,
  4902. name,
  4903. idx,
  4904. outputOptions,
  4905. plugins
  4906. );
  4907. }
  4908. /**
  4909. * @param {Module} module the module
  4910. * @param {ExecuteModuleOptions} options options
  4911. * @param {ExecuteModuleCallback} callback callback
  4912. */
  4913. executeModule(module, options, callback) {
  4914. // Aggregate all referenced modules and ensure they are ready
  4915. const modules = new Set([module]);
  4916. processAsyncTree(
  4917. modules,
  4918. 10,
  4919. (module, push, callback) => {
  4920. this.buildQueue.waitFor(module, (err) => {
  4921. if (err) return callback(err);
  4922. this.processDependenciesQueue.waitFor(module, (err) => {
  4923. if (err) return callback(err);
  4924. for (const { module: m } of this.moduleGraph.getOutgoingConnections(
  4925. module
  4926. )) {
  4927. const size = modules.size;
  4928. modules.add(m);
  4929. if (modules.size !== size) push(m);
  4930. }
  4931. callback();
  4932. });
  4933. });
  4934. },
  4935. (err) => {
  4936. if (err) return callback(/** @type {WebpackError} */ (err));
  4937. // Create new chunk graph, chunk and entrypoint for the build time execution
  4938. const chunkGraph = new ChunkGraph(
  4939. this.moduleGraph,
  4940. this.outputOptions.hashFunction
  4941. );
  4942. const runtime = "build time";
  4943. const { hashFunction, hashDigest, hashDigestLength } =
  4944. this.outputOptions;
  4945. const runtimeTemplate = this.runtimeTemplate;
  4946. const chunk = new Chunk("build time chunk", this._backCompat);
  4947. chunk.id = /** @type {ChunkId} */ (chunk.name);
  4948. chunk.ids = [chunk.id];
  4949. chunk.runtime = runtime;
  4950. const entrypoint = new Entrypoint({
  4951. runtime,
  4952. chunkLoading: false,
  4953. ...options.entryOptions
  4954. });
  4955. chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
  4956. connectChunkGroupAndChunk(entrypoint, chunk);
  4957. entrypoint.setRuntimeChunk(chunk);
  4958. entrypoint.setEntrypointChunk(chunk);
  4959. const chunks = new Set([chunk]);
  4960. // Assign ids to modules and modules to the chunk
  4961. for (const module of modules) {
  4962. const id = module.identifier();
  4963. chunkGraph.setModuleId(module, id);
  4964. chunkGraph.connectChunkAndModule(chunk, module);
  4965. }
  4966. /** @type {WebpackError[]} */
  4967. const errors = [];
  4968. // Hash modules
  4969. for (const module of modules) {
  4970. this._createModuleHash(
  4971. module,
  4972. chunkGraph,
  4973. runtime,
  4974. hashFunction,
  4975. runtimeTemplate,
  4976. hashDigest,
  4977. hashDigestLength,
  4978. errors
  4979. );
  4980. }
  4981. const codeGenerationResults = new CodeGenerationResults(
  4982. this.outputOptions.hashFunction
  4983. );
  4984. /**
  4985. * @param {Module} module the module
  4986. * @param {Callback} callback callback
  4987. * @returns {void}
  4988. */
  4989. const codeGen = (module, callback) => {
  4990. this._codeGenerationModule(
  4991. module,
  4992. runtime,
  4993. [runtime],
  4994. chunkGraph.getModuleHash(module, runtime),
  4995. this.dependencyTemplates,
  4996. chunkGraph,
  4997. this.moduleGraph,
  4998. runtimeTemplate,
  4999. errors,
  5000. codeGenerationResults,
  5001. (err, _codeGenerated) => {
  5002. callback(err);
  5003. }
  5004. );
  5005. };
  5006. const reportErrors = () => {
  5007. if (errors.length > 0) {
  5008. errors.sort(
  5009. compareSelect((err) => err.module, compareModulesByIdentifier)
  5010. );
  5011. for (const error of errors) {
  5012. this.errors.push(error);
  5013. }
  5014. errors.length = 0;
  5015. }
  5016. };
  5017. // Generate code for all aggregated modules
  5018. asyncLib.eachLimit(modules, 10, codeGen, (err) => {
  5019. if (err) return callback(err);
  5020. reportErrors();
  5021. // for backward-compat temporary set the chunk graph
  5022. // TODO webpack 6
  5023. const old = this.chunkGraph;
  5024. this.chunkGraph = chunkGraph;
  5025. this.processRuntimeRequirements({
  5026. chunkGraph,
  5027. modules,
  5028. chunks,
  5029. codeGenerationResults,
  5030. chunkGraphEntries: chunks
  5031. });
  5032. this.chunkGraph = old;
  5033. const runtimeModules =
  5034. chunkGraph.getChunkRuntimeModulesIterable(chunk);
  5035. // Hash runtime modules
  5036. for (const module of runtimeModules) {
  5037. modules.add(module);
  5038. this._createModuleHash(
  5039. module,
  5040. chunkGraph,
  5041. runtime,
  5042. hashFunction,
  5043. runtimeTemplate,
  5044. hashDigest,
  5045. hashDigestLength,
  5046. errors
  5047. );
  5048. }
  5049. // Generate code for all runtime modules
  5050. asyncLib.eachLimit(runtimeModules, 10, codeGen, (err) => {
  5051. if (err) return callback(err);
  5052. reportErrors();
  5053. /** @type {Map<Module, ExecuteModuleArgument>} */
  5054. const moduleArgumentsMap = new Map();
  5055. /** @type {Map<string, ExecuteModuleArgument>} */
  5056. const moduleArgumentsById = new Map();
  5057. /** @type {ExecuteModuleResult["fileDependencies"]} */
  5058. const fileDependencies = new LazySet();
  5059. /** @type {ExecuteModuleResult["contextDependencies"]} */
  5060. const contextDependencies = new LazySet();
  5061. /** @type {ExecuteModuleResult["missingDependencies"]} */
  5062. const missingDependencies = new LazySet();
  5063. /** @type {ExecuteModuleResult["buildDependencies"]} */
  5064. const buildDependencies = new LazySet();
  5065. /** @type {ExecuteModuleResult["assets"]} */
  5066. const assets = new Map();
  5067. let cacheable = true;
  5068. /** @type {ExecuteModuleContext} */
  5069. const context = {
  5070. assets,
  5071. __webpack_require__: undefined,
  5072. chunk,
  5073. chunkGraph
  5074. };
  5075. // Prepare execution
  5076. asyncLib.eachLimit(
  5077. modules,
  5078. 10,
  5079. (module, callback) => {
  5080. const codeGenerationResult = codeGenerationResults.get(
  5081. module,
  5082. runtime
  5083. );
  5084. /** @type {ExecuteModuleArgument} */
  5085. const moduleArgument = {
  5086. module,
  5087. codeGenerationResult,
  5088. moduleObject: undefined
  5089. };
  5090. moduleArgumentsMap.set(module, moduleArgument);
  5091. moduleArgumentsById.set(module.identifier(), moduleArgument);
  5092. module.addCacheDependencies(
  5093. fileDependencies,
  5094. contextDependencies,
  5095. missingDependencies,
  5096. buildDependencies
  5097. );
  5098. if (
  5099. /** @type {BuildInfo} */ (module.buildInfo).cacheable ===
  5100. false
  5101. ) {
  5102. cacheable = false;
  5103. }
  5104. if (module.buildInfo && module.buildInfo.assets) {
  5105. const { assets: moduleAssets, assetsInfo } = module.buildInfo;
  5106. for (const assetName of Object.keys(moduleAssets)) {
  5107. assets.set(assetName, {
  5108. source: moduleAssets[assetName],
  5109. info: assetsInfo ? assetsInfo.get(assetName) : undefined
  5110. });
  5111. }
  5112. }
  5113. this.hooks.prepareModuleExecution.callAsync(
  5114. moduleArgument,
  5115. context,
  5116. callback
  5117. );
  5118. },
  5119. (err) => {
  5120. if (err) return callback(err);
  5121. /** @type {ExecuteModuleExports | undefined} */
  5122. let exports;
  5123. try {
  5124. const {
  5125. strictModuleErrorHandling,
  5126. strictModuleExceptionHandling
  5127. } = this.outputOptions;
  5128. /** @type {WebpackRequire} */
  5129. const __webpack_require__ = (id) => {
  5130. const cached = moduleCache[id];
  5131. if (cached !== undefined) {
  5132. if (cached.error) throw cached.error;
  5133. return cached.exports;
  5134. }
  5135. const moduleArgument = moduleArgumentsById.get(id);
  5136. return __webpack_require_module__(
  5137. /** @type {ExecuteModuleArgument} */
  5138. (moduleArgument),
  5139. id
  5140. );
  5141. };
  5142. const interceptModuleExecution = (__webpack_require__[
  5143. /** @type {"i"} */
  5144. (
  5145. RuntimeGlobals.interceptModuleExecution.replace(
  5146. `${RuntimeGlobals.require}.`,
  5147. ""
  5148. )
  5149. )
  5150. ] = /** @type {NonNullable<WebpackRequire["i"]>} */ ([]));
  5151. const moduleCache = (__webpack_require__[
  5152. /** @type {"c"} */ (
  5153. RuntimeGlobals.moduleCache.replace(
  5154. `${RuntimeGlobals.require}.`,
  5155. ""
  5156. )
  5157. )
  5158. ] = /** @type {NonNullable<WebpackRequire["c"]>} */ ({}));
  5159. context.__webpack_require__ = __webpack_require__;
  5160. /**
  5161. * @param {ExecuteModuleArgument} moduleArgument the module argument
  5162. * @param {string=} id id
  5163. * @returns {ExecuteModuleExports} exports
  5164. */
  5165. const __webpack_require_module__ = (moduleArgument, id) => {
  5166. /** @type {ExecuteOptions} */
  5167. const execOptions = {
  5168. id,
  5169. module: {
  5170. id,
  5171. exports: {},
  5172. loaded: false,
  5173. error: undefined
  5174. },
  5175. require: __webpack_require__
  5176. };
  5177. for (const handler of interceptModuleExecution) {
  5178. handler(execOptions);
  5179. }
  5180. const module = moduleArgument.module;
  5181. this.buildTimeExecutedModules.add(module);
  5182. const moduleObject = execOptions.module;
  5183. moduleArgument.moduleObject = moduleObject;
  5184. try {
  5185. if (id) moduleCache[id] = moduleObject;
  5186. tryRunOrWebpackError(
  5187. () =>
  5188. this.hooks.executeModule.call(
  5189. moduleArgument,
  5190. context
  5191. ),
  5192. "Compilation.hooks.executeModule"
  5193. );
  5194. moduleObject.loaded = true;
  5195. return moduleObject.exports;
  5196. } catch (execErr) {
  5197. if (strictModuleExceptionHandling) {
  5198. if (id) delete moduleCache[id];
  5199. } else if (strictModuleErrorHandling) {
  5200. moduleObject.error =
  5201. /** @type {WebpackError} */
  5202. (execErr);
  5203. }
  5204. if (!(/** @type {WebpackError} */ (execErr).module)) {
  5205. /** @type {WebpackError} */
  5206. (execErr).module = module;
  5207. }
  5208. throw execErr;
  5209. }
  5210. };
  5211. for (const runtimeModule of chunkGraph.getChunkRuntimeModulesInOrder(
  5212. chunk
  5213. )) {
  5214. __webpack_require_module__(
  5215. /** @type {ExecuteModuleArgument} */
  5216. (moduleArgumentsMap.get(runtimeModule))
  5217. );
  5218. }
  5219. exports = __webpack_require__(module.identifier());
  5220. } catch (execErr) {
  5221. const { message, stack, module } =
  5222. /** @type {WebpackError} */
  5223. (execErr);
  5224. const err = new WebpackError(
  5225. `Execution of module code from module graph (${
  5226. /** @type {Module} */
  5227. (module).readableIdentifier(this.requestShortener)
  5228. }) failed: ${message}`,
  5229. { cause: execErr }
  5230. );
  5231. err.stack = stack;
  5232. err.module = module;
  5233. return callback(err);
  5234. }
  5235. callback(null, {
  5236. exports,
  5237. assets,
  5238. cacheable,
  5239. fileDependencies,
  5240. contextDependencies,
  5241. missingDependencies,
  5242. buildDependencies
  5243. });
  5244. }
  5245. );
  5246. });
  5247. });
  5248. }
  5249. );
  5250. }
  5251. checkConstraints() {
  5252. const chunkGraph = this.chunkGraph;
  5253. /** @type {Set<ModuleId>} */
  5254. const usedIds = new Set();
  5255. for (const module of this.modules) {
  5256. if (module.type === WEBPACK_MODULE_TYPE_RUNTIME) continue;
  5257. const moduleId = chunkGraph.getModuleId(module);
  5258. if (moduleId === null) continue;
  5259. if (usedIds.has(moduleId)) {
  5260. throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
  5261. }
  5262. usedIds.add(moduleId);
  5263. }
  5264. for (const chunk of this.chunks) {
  5265. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  5266. if (!this.modules.has(module)) {
  5267. throw new Error(
  5268. "checkConstraints: module in chunk but not in compilation " +
  5269. ` ${chunk.debugId} ${module.debugId}`
  5270. );
  5271. }
  5272. }
  5273. for (const module of chunkGraph.getChunkEntryModulesIterable(chunk)) {
  5274. if (!this.modules.has(module)) {
  5275. throw new Error(
  5276. "checkConstraints: entry module in chunk but not in compilation " +
  5277. ` ${chunk.debugId} ${module.debugId}`
  5278. );
  5279. }
  5280. }
  5281. }
  5282. for (const chunkGroup of this.chunkGroups) {
  5283. chunkGroup.checkConstraints();
  5284. }
  5285. }
  5286. }
  5287. /**
  5288. * @typedef {object} FactorizeModuleOptions
  5289. * @property {ModuleProfile=} currentProfile
  5290. * @property {ModuleFactory} factory
  5291. * @property {Dependency[]} dependencies
  5292. * @property {boolean=} factoryResult return full ModuleFactoryResult instead of only module
  5293. * @property {Module | null} originModule
  5294. * @property {Partial<ModuleFactoryCreateDataContextInfo>=} contextInfo
  5295. * @property {string=} context
  5296. */
  5297. /**
  5298. * @param {FactorizeModuleOptions} options options object
  5299. * @param {ModuleCallback | ModuleFactoryResultCallback} callback callback
  5300. * @returns {void}
  5301. */
  5302. // Hide from typescript
  5303. const compilationPrototype = Compilation.prototype;
  5304. // TODO webpack 6 remove
  5305. Object.defineProperty(compilationPrototype, "modifyHash", {
  5306. writable: false,
  5307. enumerable: false,
  5308. configurable: false,
  5309. value: () => {
  5310. throw new Error(
  5311. "Compilation.modifyHash was removed in favor of Compilation.hooks.fullHash"
  5312. );
  5313. }
  5314. });
  5315. // TODO webpack 6 remove
  5316. Object.defineProperty(compilationPrototype, "cache", {
  5317. enumerable: false,
  5318. configurable: false,
  5319. get: util.deprecate(
  5320. /**
  5321. * @this {Compilation} the compilation
  5322. * @returns {Cache} the cache
  5323. */
  5324. function cache() {
  5325. return this.compiler.cache;
  5326. },
  5327. "Compilation.cache was removed in favor of Compilation.getCache()",
  5328. "DEP_WEBPACK_COMPILATION_CACHE"
  5329. ),
  5330. set: util.deprecate(
  5331. /**
  5332. * @param {EXPECTED_ANY} _v value
  5333. */
  5334. (_v) => {},
  5335. "Compilation.cache was removed in favor of Compilation.getCache()",
  5336. "DEP_WEBPACK_COMPILATION_CACHE"
  5337. )
  5338. });
  5339. /**
  5340. * Add additional assets to the compilation.
  5341. */
  5342. Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL = -2000;
  5343. /**
  5344. * Basic preprocessing of assets.
  5345. */
  5346. Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS = -1000;
  5347. /**
  5348. * Derive new assets from existing assets.
  5349. * Existing assets should not be treated as complete.
  5350. */
  5351. Compilation.PROCESS_ASSETS_STAGE_DERIVED = -200;
  5352. /**
  5353. * Add additional sections to existing assets, like a banner or initialization code.
  5354. */
  5355. Compilation.PROCESS_ASSETS_STAGE_ADDITIONS = -100;
  5356. /**
  5357. * Optimize existing assets in a general way.
  5358. */
  5359. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE = 100;
  5360. /**
  5361. * Optimize the count of existing assets, e. g. by merging them.
  5362. * Only assets of the same type should be merged.
  5363. * For assets of different types see PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE.
  5364. */
  5365. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT = 200;
  5366. /**
  5367. * Optimize the compatibility of existing assets, e. g. add polyfills or vendor-prefixes.
  5368. */
  5369. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY = 300;
  5370. /**
  5371. * Optimize the size of existing assets, e. g. by minimizing or omitting whitespace.
  5372. */
  5373. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE = 400;
  5374. /**
  5375. * Add development tooling to assets, e. g. by extracting a SourceMap.
  5376. */
  5377. Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING = 500;
  5378. /**
  5379. * Optimize the count of existing assets, e. g. by inlining assets of into other assets.
  5380. * Only assets of different types should be inlined.
  5381. * For assets of the same type see PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT.
  5382. */
  5383. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE = 700;
  5384. /**
  5385. * Summarize the list of existing assets
  5386. * e. g. creating an assets manifest of Service Workers.
  5387. */
  5388. Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE = 1000;
  5389. /**
  5390. * Optimize the hashes of the assets, e. g. by generating real hashes of the asset content.
  5391. */
  5392. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH = 2500;
  5393. /**
  5394. * Optimize the transfer of existing assets, e. g. by preparing a compressed (gzip) file as separate asset.
  5395. */
  5396. Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER = 3000;
  5397. /**
  5398. * Analyse existing assets.
  5399. */
  5400. Compilation.PROCESS_ASSETS_STAGE_ANALYSE = 4000;
  5401. /**
  5402. * Creating assets for reporting purposes.
  5403. */
  5404. Compilation.PROCESS_ASSETS_STAGE_REPORT = 5000;
  5405. module.exports = Compilation;