Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

5527 linhas
165 KiB

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