You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2327 lines
66 KiB

4 years ago
  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 util = require("util");
  8. const { CachedSource } = require("webpack-sources");
  9. const {
  10. Tapable,
  11. SyncHook,
  12. SyncBailHook,
  13. SyncWaterfallHook,
  14. AsyncSeriesHook
  15. } = require("tapable");
  16. const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
  17. const ModuleNotFoundError = require("./ModuleNotFoundError");
  18. const ModuleDependencyWarning = require("./ModuleDependencyWarning");
  19. const ModuleDependencyError = require("./ModuleDependencyError");
  20. const ChunkGroup = require("./ChunkGroup");
  21. const Chunk = require("./Chunk");
  22. const Entrypoint = require("./Entrypoint");
  23. const MainTemplate = require("./MainTemplate");
  24. const ChunkTemplate = require("./ChunkTemplate");
  25. const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
  26. const ModuleTemplate = require("./ModuleTemplate");
  27. const RuntimeTemplate = require("./RuntimeTemplate");
  28. const ChunkRenderError = require("./ChunkRenderError");
  29. const Stats = require("./Stats");
  30. const Semaphore = require("./util/Semaphore");
  31. const createHash = require("./util/createHash");
  32. const SortableSet = require("./util/SortableSet");
  33. const GraphHelpers = require("./GraphHelpers");
  34. const ModuleDependency = require("./dependencies/ModuleDependency");
  35. const compareLocations = require("./compareLocations");
  36. const { Logger, LogType } = require("./logging/Logger");
  37. const ErrorHelpers = require("./ErrorHelpers");
  38. const buildChunkGraph = require("./buildChunkGraph");
  39. const WebpackError = require("./WebpackError");
  40. /** @typedef {import("./Module")} Module */
  41. /** @typedef {import("./Compiler")} Compiler */
  42. /** @typedef {import("webpack-sources").Source} Source */
  43. /** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */
  44. /** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */
  45. /** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */
  46. /** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
  47. /** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
  48. /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
  49. /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
  50. /** @typedef {import("./Dependency")} Dependency */
  51. /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
  52. /** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
  53. /** @typedef {import("./util/createHash").Hash} Hash */
  54. // TODO use @callback
  55. /** @typedef {{[assetName: string]: Source}} CompilationAssets */
  56. /** @typedef {(err: Error|null, result?: Module) => void } ModuleCallback */
  57. /** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */
  58. /** @typedef {(module: Module) => void} OnModuleCallback */
  59. /** @typedef {(err?: Error|null) => void} Callback */
  60. /** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
  61. /** @typedef {new (...args: any[]) => Dependency} DepConstructor */
  62. /** @typedef {{apply: () => void}} Plugin */
  63. /**
  64. * @typedef {Object} ModuleFactoryCreateDataContextInfo
  65. * @property {string} issuer
  66. * @property {string} compiler
  67. */
  68. /**
  69. * @typedef {Object} ModuleFactoryCreateData
  70. * @property {ModuleFactoryCreateDataContextInfo} contextInfo
  71. * @property {any=} resolveOptions
  72. * @property {string} context
  73. * @property {Dependency[]} dependencies
  74. */
  75. /**
  76. * @typedef {Object} ModuleFactory
  77. * @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
  78. */
  79. /**
  80. * @typedef {Object} SortedDependency
  81. * @property {ModuleFactory} factory
  82. * @property {Dependency[]} dependencies
  83. */
  84. /**
  85. * @typedef {Object} DependenciesBlockLike
  86. * @property {Dependency[]} dependencies
  87. * @property {AsyncDependenciesBlock[]} blocks
  88. * @property {DependenciesBlockVariable[]} variables
  89. */
  90. /**
  91. * @typedef {Object} LogEntry
  92. * @property {string} type
  93. * @property {any[]} args
  94. * @property {number} time
  95. * @property {string[]=} trace
  96. */
  97. /**
  98. * @typedef {Object} AssetInfo
  99. * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash)
  100. * @property {number=} size size in bytes, only set after asset has been emitted
  101. * @property {boolean=} development true, when asset is only used for development and doesn't count towards user-facing assets
  102. * @property {boolean=} hotModuleReplacement true, when asset ships data for updating an existing application (HMR)
  103. */
  104. /**
  105. * @typedef {Object} Asset
  106. * @property {string} name the filename of the asset
  107. * @property {Source} source source of the asset
  108. * @property {AssetInfo} info info about the asset
  109. */
  110. /**
  111. * @param {Chunk} a first chunk to sort by id
  112. * @param {Chunk} b second chunk to sort by id
  113. * @returns {-1|0|1} sort value
  114. */
  115. const byId = (a, b) => {
  116. if (typeof a.id !== typeof b.id) {
  117. return typeof a.id < typeof b.id ? -1 : 1;
  118. }
  119. if (a.id < b.id) return -1;
  120. if (a.id > b.id) return 1;
  121. return 0;
  122. };
  123. /**
  124. * @param {Module} a first module to sort by
  125. * @param {Module} b second module to sort by
  126. * @returns {-1|0|1} sort value
  127. */
  128. const byIdOrIdentifier = (a, b) => {
  129. if (typeof a.id !== typeof b.id) {
  130. return typeof a.id < typeof b.id ? -1 : 1;
  131. }
  132. if (a.id < b.id) return -1;
  133. if (a.id > b.id) return 1;
  134. const identA = a.identifier();
  135. const identB = b.identifier();
  136. if (identA < identB) return -1;
  137. if (identA > identB) return 1;
  138. return 0;
  139. };
  140. /**
  141. * @param {Module} a first module to sort by
  142. * @param {Module} b second module to sort by
  143. * @returns {-1|0|1} sort value
  144. */
  145. const byIndexOrIdentifier = (a, b) => {
  146. if (a.index < b.index) return -1;
  147. if (a.index > b.index) return 1;
  148. const identA = a.identifier();
  149. const identB = b.identifier();
  150. if (identA < identB) return -1;
  151. if (identA > identB) return 1;
  152. return 0;
  153. };
  154. /**
  155. * @param {Compilation} a first compilation to sort by
  156. * @param {Compilation} b second compilation to sort by
  157. * @returns {-1|0|1} sort value
  158. */
  159. const byNameOrHash = (a, b) => {
  160. if (a.name < b.name) return -1;
  161. if (a.name > b.name) return 1;
  162. if (a.fullHash < b.fullHash) return -1;
  163. if (a.fullHash > b.fullHash) return 1;
  164. return 0;
  165. };
  166. /**
  167. * @param {DependenciesBlockVariable[]} variables DepBlock Variables to iterate over
  168. * @param {DepBlockVarDependenciesCallback} fn callback to apply on iterated elements
  169. * @returns {void}
  170. */
  171. const iterationBlockVariable = (variables, fn) => {
  172. for (
  173. let indexVariable = 0;
  174. indexVariable < variables.length;
  175. indexVariable++
  176. ) {
  177. const varDep = variables[indexVariable].dependencies;
  178. for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) {
  179. fn(varDep[indexVDep]);
  180. }
  181. }
  182. };
  183. /**
  184. * @template T
  185. * @param {T[]} arr array of elements to iterate over
  186. * @param {function(T): void} fn callback applied to each element
  187. * @returns {void}
  188. */
  189. const iterationOfArrayCallback = (arr, fn) => {
  190. for (let index = 0; index < arr.length; index++) {
  191. fn(arr[index]);
  192. }
  193. };
  194. /**
  195. * @template T
  196. * @param {Set<T>} set set to add items to
  197. * @param {Set<T>} otherSet set to add items from
  198. * @returns {void}
  199. */
  200. const addAllToSet = (set, otherSet) => {
  201. for (const item of otherSet) {
  202. set.add(item);
  203. }
  204. };
  205. /**
  206. * @param {Source} a a source
  207. * @param {Source} b another source
  208. * @returns {boolean} true, when both sources are equal
  209. */
  210. const isSourceEqual = (a, b) => {
  211. if (a === b) return true;
  212. // TODO webpack 5: check .buffer() instead, it's called anyway during emit
  213. /** @type {Buffer|string} */
  214. let aSource = a.source();
  215. /** @type {Buffer|string} */
  216. let bSource = b.source();
  217. if (aSource === bSource) return true;
  218. if (typeof aSource === "string" && typeof bSource === "string") return false;
  219. if (!Buffer.isBuffer(aSource)) aSource = Buffer.from(aSource, "utf-8");
  220. if (!Buffer.isBuffer(bSource)) bSource = Buffer.from(bSource, "utf-8");
  221. return aSource.equals(bSource);
  222. };
  223. class Compilation extends Tapable {
  224. /**
  225. * Creates an instance of Compilation.
  226. * @param {Compiler} compiler the compiler which created the compilation
  227. */
  228. constructor(compiler) {
  229. super();
  230. this.hooks = {
  231. /** @type {SyncHook<Module>} */
  232. buildModule: new SyncHook(["module"]),
  233. /** @type {SyncHook<Module>} */
  234. rebuildModule: new SyncHook(["module"]),
  235. /** @type {SyncHook<Module, Error>} */
  236. failedModule: new SyncHook(["module", "error"]),
  237. /** @type {SyncHook<Module>} */
  238. succeedModule: new SyncHook(["module"]),
  239. /** @type {SyncHook<Dependency, string>} */
  240. addEntry: new SyncHook(["entry", "name"]),
  241. /** @type {SyncHook<Dependency, string, Error>} */
  242. failedEntry: new SyncHook(["entry", "name", "error"]),
  243. /** @type {SyncHook<Dependency, string, Module>} */
  244. succeedEntry: new SyncHook(["entry", "name", "module"]),
  245. /** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
  246. dependencyReference: new SyncWaterfallHook([
  247. "dependencyReference",
  248. "dependency",
  249. "module"
  250. ]),
  251. /** @type {AsyncSeriesHook<Module[]>} */
  252. finishModules: new AsyncSeriesHook(["modules"]),
  253. /** @type {SyncHook<Module>} */
  254. finishRebuildingModule: new SyncHook(["module"]),
  255. /** @type {SyncHook} */
  256. unseal: new SyncHook([]),
  257. /** @type {SyncHook} */
  258. seal: new SyncHook([]),
  259. /** @type {SyncHook} */
  260. beforeChunks: new SyncHook([]),
  261. /** @type {SyncHook<Chunk[]>} */
  262. afterChunks: new SyncHook(["chunks"]),
  263. /** @type {SyncBailHook<Module[]>} */
  264. optimizeDependenciesBasic: new SyncBailHook(["modules"]),
  265. /** @type {SyncBailHook<Module[]>} */
  266. optimizeDependencies: new SyncBailHook(["modules"]),
  267. /** @type {SyncBailHook<Module[]>} */
  268. optimizeDependenciesAdvanced: new SyncBailHook(["modules"]),
  269. /** @type {SyncBailHook<Module[]>} */
  270. afterOptimizeDependencies: new SyncHook(["modules"]),
  271. /** @type {SyncHook} */
  272. optimize: new SyncHook([]),
  273. /** @type {SyncBailHook<Module[]>} */
  274. optimizeModulesBasic: new SyncBailHook(["modules"]),
  275. /** @type {SyncBailHook<Module[]>} */
  276. optimizeModules: new SyncBailHook(["modules"]),
  277. /** @type {SyncBailHook<Module[]>} */
  278. optimizeModulesAdvanced: new SyncBailHook(["modules"]),
  279. /** @type {SyncHook<Module[]>} */
  280. afterOptimizeModules: new SyncHook(["modules"]),
  281. /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
  282. optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]),
  283. /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
  284. optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
  285. /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
  286. optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]),
  287. /** @type {SyncHook<Chunk[], ChunkGroup[]>} */
  288. afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
  289. /** @type {AsyncSeriesHook<Chunk[], Module[]>} */
  290. optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
  291. /** @type {SyncHook<Chunk[], Module[]>} */
  292. afterOptimizeTree: new SyncHook(["chunks", "modules"]),
  293. /** @type {SyncBailHook<Chunk[], Module[]>} */
  294. optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]),
  295. /** @type {SyncBailHook<Chunk[], Module[]>} */
  296. optimizeChunkModules: new SyncBailHook(["chunks", "modules"]),
  297. /** @type {SyncBailHook<Chunk[], Module[]>} */
  298. optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]),
  299. /** @type {SyncHook<Chunk[], Module[]>} */
  300. afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
  301. /** @type {SyncBailHook} */
  302. shouldRecord: new SyncBailHook([]),
  303. /** @type {SyncHook<Module[], any>} */
  304. reviveModules: new SyncHook(["modules", "records"]),
  305. /** @type {SyncHook<Module[]>} */
  306. optimizeModuleOrder: new SyncHook(["modules"]),
  307. /** @type {SyncHook<Module[]>} */
  308. advancedOptimizeModuleOrder: new SyncHook(["modules"]),
  309. /** @type {SyncHook<Module[]>} */
  310. beforeModuleIds: new SyncHook(["modules"]),
  311. /** @type {SyncHook<Module[]>} */
  312. moduleIds: new SyncHook(["modules"]),
  313. /** @type {SyncHook<Module[]>} */
  314. optimizeModuleIds: new SyncHook(["modules"]),
  315. /** @type {SyncHook<Module[]>} */
  316. afterOptimizeModuleIds: new SyncHook(["modules"]),
  317. /** @type {SyncHook<Chunk[], any>} */
  318. reviveChunks: new SyncHook(["chunks", "records"]),
  319. /** @type {SyncHook<Chunk[]>} */
  320. optimizeChunkOrder: new SyncHook(["chunks"]),
  321. /** @type {SyncHook<Chunk[]>} */
  322. beforeChunkIds: new SyncHook(["chunks"]),
  323. /** @type {SyncHook<Chunk[]>} */
  324. optimizeChunkIds: new SyncHook(["chunks"]),
  325. /** @type {SyncHook<Chunk[]>} */
  326. afterOptimizeChunkIds: new SyncHook(["chunks"]),
  327. /** @type {SyncHook<Module[], any>} */
  328. recordModules: new SyncHook(["modules", "records"]),
  329. /** @type {SyncHook<Chunk[], any>} */
  330. recordChunks: new SyncHook(["chunks", "records"]),
  331. /** @type {SyncHook} */
  332. beforeHash: new SyncHook([]),
  333. /** @type {SyncHook<Chunk>} */
  334. contentHash: new SyncHook(["chunk"]),
  335. /** @type {SyncHook} */
  336. afterHash: new SyncHook([]),
  337. /** @type {SyncHook<any>} */
  338. recordHash: new SyncHook(["records"]),
  339. /** @type {SyncHook<Compilation, any>} */
  340. record: new SyncHook(["compilation", "records"]),
  341. /** @type {SyncHook} */
  342. beforeModuleAssets: new SyncHook([]),
  343. /** @type {SyncBailHook} */
  344. shouldGenerateChunkAssets: new SyncBailHook([]),
  345. /** @type {SyncHook} */
  346. beforeChunkAssets: new SyncHook([]),
  347. /** @type {SyncHook<Chunk[]>} */
  348. additionalChunkAssets: new SyncHook(["chunks"]),
  349. /** @type {AsyncSeriesHook} */
  350. additionalAssets: new AsyncSeriesHook([]),
  351. /** @type {AsyncSeriesHook<Chunk[]>} */
  352. optimizeChunkAssets: new AsyncSeriesHook(["chunks"]),
  353. /** @type {SyncHook<Chunk[]>} */
  354. afterOptimizeChunkAssets: new SyncHook(["chunks"]),
  355. /** @type {AsyncSeriesHook<CompilationAssets>} */
  356. optimizeAssets: new AsyncSeriesHook(["assets"]),
  357. /** @type {SyncHook<CompilationAssets>} */
  358. afterOptimizeAssets: new SyncHook(["assets"]),
  359. /** @type {SyncBailHook} */
  360. needAdditionalSeal: new SyncBailHook([]),
  361. /** @type {AsyncSeriesHook} */
  362. afterSeal: new AsyncSeriesHook([]),
  363. /** @type {SyncHook<Chunk, Hash>} */
  364. chunkHash: new SyncHook(["chunk", "chunkHash"]),
  365. /** @type {SyncHook<Module, string>} */
  366. moduleAsset: new SyncHook(["module", "filename"]),
  367. /** @type {SyncHook<Chunk, string>} */
  368. chunkAsset: new SyncHook(["chunk", "filename"]),
  369. /** @type {SyncWaterfallHook<string, TODO>} */
  370. assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate
  371. /** @type {SyncBailHook} */
  372. needAdditionalPass: new SyncBailHook([]),
  373. /** @type {SyncHook<Compiler, string, number>} */
  374. childCompiler: new SyncHook([
  375. "childCompiler",
  376. "compilerName",
  377. "compilerIndex"
  378. ]),
  379. /** @type {SyncBailHook<string, LogEntry>} */
  380. log: new SyncBailHook(["origin", "logEntry"]),
  381. // TODO the following hooks are weirdly located here
  382. // TODO move them for webpack 5
  383. /** @type {SyncHook<object, Module>} */
  384. normalModuleLoader: new SyncHook(["loaderContext", "module"]),
  385. /** @type {SyncBailHook<Chunk[]>} */
  386. optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]),
  387. /** @type {SyncBailHook<Chunk[]>} */
  388. optimizeExtractedChunks: new SyncBailHook(["chunks"]),
  389. /** @type {SyncBailHook<Chunk[]>} */
  390. optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]),
  391. /** @type {SyncHook<Chunk[]>} */
  392. afterOptimizeExtractedChunks: new SyncHook(["chunks"])
  393. };
  394. this._pluginCompat.tap("Compilation", options => {
  395. switch (options.name) {
  396. case "optimize-tree":
  397. case "additional-assets":
  398. case "optimize-chunk-assets":
  399. case "optimize-assets":
  400. case "after-seal":
  401. options.async = true;
  402. break;
  403. }
  404. });
  405. /** @type {string=} */
  406. this.name = undefined;
  407. /** @type {Compiler} */
  408. this.compiler = compiler;
  409. this.resolverFactory = compiler.resolverFactory;
  410. this.inputFileSystem = compiler.inputFileSystem;
  411. this.requestShortener = compiler.requestShortener;
  412. const options = compiler.options;
  413. this.options = options;
  414. this.outputOptions = options && options.output;
  415. /** @type {boolean=} */
  416. this.bail = options && options.bail;
  417. this.profile = options && options.profile;
  418. this.performance = options && options.performance;
  419. this.mainTemplate = new MainTemplate(this.outputOptions);
  420. this.chunkTemplate = new ChunkTemplate(this.outputOptions);
  421. this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(
  422. this.outputOptions
  423. );
  424. this.runtimeTemplate = new RuntimeTemplate(
  425. this.outputOptions,
  426. this.requestShortener
  427. );
  428. this.moduleTemplates = {
  429. javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
  430. webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
  431. };
  432. this.semaphore = new Semaphore(options.parallelism || 100);
  433. this.entries = [];
  434. /** @private @type {{name: string, request: string, module: Module}[]} */
  435. this._preparedEntrypoints = [];
  436. /** @type {Map<string, Entrypoint>} */
  437. this.entrypoints = new Map();
  438. /** @type {Chunk[]} */
  439. this.chunks = [];
  440. /** @type {ChunkGroup[]} */
  441. this.chunkGroups = [];
  442. /** @type {Map<string, ChunkGroup>} */
  443. this.namedChunkGroups = new Map();
  444. /** @type {Map<string, Chunk>} */
  445. this.namedChunks = new Map();
  446. /** @type {Module[]} */
  447. this.modules = [];
  448. /** @private @type {Map<string, Module>} */
  449. this._modules = new Map();
  450. this.cache = null;
  451. this.records = null;
  452. /** @type {string[]} */
  453. this.additionalChunkAssets = [];
  454. /** @type {CompilationAssets} */
  455. this.assets = {};
  456. /** @type {Map<string, AssetInfo>} */
  457. this.assetsInfo = new Map();
  458. /** @type {WebpackError[]} */
  459. this.errors = [];
  460. /** @type {WebpackError[]} */
  461. this.warnings = [];
  462. /** @type {Compilation[]} */
  463. this.children = [];
  464. /** @type {Map<string, LogEntry[]>} */
  465. this.logging = new Map();
  466. /** @type {Map<DepConstructor, ModuleFactory>} */
  467. this.dependencyFactories = new Map();
  468. /** @type {Map<DepConstructor, DependencyTemplate>} */
  469. this.dependencyTemplates = new Map();
  470. // TODO refactor this in webpack 5 to a custom DependencyTemplates class with a hash property
  471. // @ts-ignore
  472. this.dependencyTemplates.set("hash", "");
  473. this.childrenCounters = {};
  474. /** @type {Set<number|string>} */
  475. this.usedChunkIds = null;
  476. /** @type {Set<number>} */
  477. this.usedModuleIds = null;
  478. /** @type {Map<string, number>=} */
  479. this.fileTimestamps = undefined;
  480. /** @type {Map<string, number>=} */
  481. this.contextTimestamps = undefined;
  482. /** @type {Set<string>=} */
  483. this.compilationDependencies = undefined;
  484. /** @private @type {Map<Module, Callback[]>} */
  485. this._buildingModules = new Map();
  486. /** @private @type {Map<Module, Callback[]>} */
  487. this._rebuildingModules = new Map();
  488. /** @type {Set<string>} */
  489. this.emittedAssets = new Set();
  490. }
  491. getStats() {
  492. return new Stats(this);
  493. }
  494. /**
  495. * @param {string | (function(): string)} name name of the logger, or function called once to get the logger name
  496. * @returns {Logger} a logger with that name
  497. */
  498. getLogger(name) {
  499. if (!name) {
  500. throw new TypeError("Compilation.getLogger(name) called without a name");
  501. }
  502. /** @type {LogEntry[] | undefined} */
  503. let logEntries;
  504. return new Logger((type, args) => {
  505. if (typeof name === "function") {
  506. name = name();
  507. if (!name) {
  508. throw new TypeError(
  509. "Compilation.getLogger(name) called with a function not returning a name"
  510. );
  511. }
  512. }
  513. let trace;
  514. switch (type) {
  515. case LogType.warn:
  516. case LogType.error:
  517. case LogType.trace:
  518. trace = ErrorHelpers.cutOffLoaderExecution(new Error("Trace").stack)
  519. .split("\n")
  520. .slice(3);
  521. break;
  522. }
  523. /** @type {LogEntry} */
  524. const logEntry = {
  525. time: Date.now(),
  526. type,
  527. args,
  528. trace
  529. };
  530. if (this.hooks.log.call(name, logEntry) === undefined) {
  531. if (logEntry.type === LogType.profileEnd) {
  532. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  533. if (typeof console.profileEnd === "function") {
  534. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  535. console.profileEnd(`[${name}] ${logEntry.args[0]}`);
  536. }
  537. }
  538. if (logEntries === undefined) {
  539. logEntries = this.logging.get(name);
  540. if (logEntries === undefined) {
  541. logEntries = [];
  542. this.logging.set(name, logEntries);
  543. }
  544. }
  545. logEntries.push(logEntry);
  546. if (logEntry.type === LogType.profile) {
  547. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  548. if (typeof console.profile === "function") {
  549. // eslint-disable-next-line node/no-unsupported-features/node-builtins
  550. console.profile(`[${name}] ${logEntry.args[0]}`);
  551. }
  552. }
  553. }
  554. });
  555. }
  556. /**
  557. * @typedef {Object} AddModuleResult
  558. * @property {Module} module the added or existing module
  559. * @property {boolean} issuer was this the first request for this module
  560. * @property {boolean} build should the module be build
  561. * @property {boolean} dependencies should dependencies be walked
  562. */
  563. /**
  564. * @param {Module} module module to be added that was created
  565. * @param {any=} cacheGroup cacheGroup it is apart of
  566. * @returns {AddModuleResult} returns meta about whether or not the module had built
  567. * had an issuer, or any dependnecies
  568. */
  569. addModule(module, cacheGroup) {
  570. const identifier = module.identifier();
  571. const alreadyAddedModule = this._modules.get(identifier);
  572. if (alreadyAddedModule) {
  573. return {
  574. module: alreadyAddedModule,
  575. issuer: false,
  576. build: false,
  577. dependencies: false
  578. };
  579. }
  580. const cacheName = (cacheGroup || "m") + identifier;
  581. if (this.cache && this.cache[cacheName]) {
  582. const cacheModule = this.cache[cacheName];
  583. if (typeof cacheModule.updateCacheModule === "function") {
  584. cacheModule.updateCacheModule(module);
  585. }
  586. let rebuild = true;
  587. if (this.fileTimestamps && this.contextTimestamps) {
  588. rebuild = cacheModule.needRebuild(
  589. this.fileTimestamps,
  590. this.contextTimestamps
  591. );
  592. }
  593. if (!rebuild) {
  594. cacheModule.disconnect();
  595. this._modules.set(identifier, cacheModule);
  596. this.modules.push(cacheModule);
  597. for (const err of cacheModule.errors) {
  598. this.errors.push(err);
  599. }
  600. for (const err of cacheModule.warnings) {
  601. this.warnings.push(err);
  602. }
  603. return {
  604. module: cacheModule,
  605. issuer: true,
  606. build: false,
  607. dependencies: true
  608. };
  609. }
  610. cacheModule.unbuild();
  611. module = cacheModule;
  612. }
  613. this._modules.set(identifier, module);
  614. if (this.cache) {
  615. this.cache[cacheName] = module;
  616. }
  617. this.modules.push(module);
  618. return {
  619. module: module,
  620. issuer: true,
  621. build: true,
  622. dependencies: true
  623. };
  624. }
  625. /**
  626. * Fetches a module from a compilation by its identifier
  627. * @param {Module} module the module provided
  628. * @returns {Module} the module requested
  629. */
  630. getModule(module) {
  631. const identifier = module.identifier();
  632. return this._modules.get(identifier);
  633. }
  634. /**
  635. * Attempts to search for a module by its identifier
  636. * @param {string} identifier identifier (usually path) for module
  637. * @returns {Module|undefined} attempt to search for module and return it, else undefined
  638. */
  639. findModule(identifier) {
  640. return this._modules.get(identifier);
  641. }
  642. /**
  643. * @param {Module} module module with its callback list
  644. * @param {Callback} callback the callback function
  645. * @returns {void}
  646. */
  647. waitForBuildingFinished(module, callback) {
  648. let callbackList = this._buildingModules.get(module);
  649. if (callbackList) {
  650. callbackList.push(() => callback());
  651. } else {
  652. process.nextTick(callback);
  653. }
  654. }
  655. /**
  656. * Builds the module object
  657. *
  658. * @param {Module} module module to be built
  659. * @param {boolean} optional optional flag
  660. * @param {Module=} origin origin module this module build was requested from
  661. * @param {Dependency[]=} dependencies optional dependencies from the module to be built
  662. * @param {TODO} thisCallback the callback
  663. * @returns {TODO} returns the callback function with results
  664. */
  665. buildModule(module, optional, origin, dependencies, thisCallback) {
  666. let callbackList = this._buildingModules.get(module);
  667. if (callbackList) {
  668. callbackList.push(thisCallback);
  669. return;
  670. }
  671. this._buildingModules.set(module, (callbackList = [thisCallback]));
  672. const callback = err => {
  673. this._buildingModules.delete(module);
  674. for (const cb of callbackList) {
  675. cb(err);
  676. }
  677. };
  678. this.hooks.buildModule.call(module);
  679. module.build(
  680. this.options,
  681. this,
  682. this.resolverFactory.get("normal", module.resolveOptions),
  683. this.inputFileSystem,
  684. error => {
  685. const errors = module.errors;
  686. for (let indexError = 0; indexError < errors.length; indexError++) {
  687. const err = errors[indexError];
  688. err.origin = origin;
  689. err.dependencies = dependencies;
  690. if (optional) {
  691. this.warnings.push(err);
  692. } else {
  693. this.errors.push(err);
  694. }
  695. }
  696. const warnings = module.warnings;
  697. for (
  698. let indexWarning = 0;
  699. indexWarning < warnings.length;
  700. indexWarning++
  701. ) {
  702. const war = warnings[indexWarning];
  703. war.origin = origin;
  704. war.dependencies = dependencies;
  705. this.warnings.push(war);
  706. }
  707. const originalMap = module.dependencies.reduce((map, v, i) => {
  708. map.set(v, i);
  709. return map;
  710. }, new Map());
  711. module.dependencies.sort((a, b) => {
  712. const cmp = compareLocations(a.loc, b.loc);
  713. if (cmp) return cmp;
  714. return originalMap.get(a) - originalMap.get(b);
  715. });
  716. if (error) {
  717. this.hooks.failedModule.call(module, error);
  718. return callback(error);
  719. }
  720. this.hooks.succeedModule.call(module);
  721. return callback();
  722. }
  723. );
  724. }
  725. /**
  726. * @param {Module} module to be processed for deps
  727. * @param {ModuleCallback} callback callback to be triggered
  728. * @returns {void}
  729. */
  730. processModuleDependencies(module, callback) {
  731. const dependencies = new Map();
  732. const addDependency = dep => {
  733. const resourceIdent = dep.getResourceIdentifier();
  734. if (resourceIdent) {
  735. const factory = this.dependencyFactories.get(dep.constructor);
  736. if (factory === undefined) {
  737. throw new Error(
  738. `No module factory available for dependency type: ${dep.constructor.name}`
  739. );
  740. }
  741. let innerMap = dependencies.get(factory);
  742. if (innerMap === undefined) {
  743. dependencies.set(factory, (innerMap = new Map()));
  744. }
  745. let list = innerMap.get(resourceIdent);
  746. if (list === undefined) innerMap.set(resourceIdent, (list = []));
  747. list.push(dep);
  748. }
  749. };
  750. const addDependenciesBlock = block => {
  751. if (block.dependencies) {
  752. iterationOfArrayCallback(block.dependencies, addDependency);
  753. }
  754. if (block.blocks) {
  755. iterationOfArrayCallback(block.blocks, addDependenciesBlock);
  756. }
  757. if (block.variables) {
  758. iterationBlockVariable(block.variables, addDependency);
  759. }
  760. };
  761. try {
  762. addDependenciesBlock(module);
  763. } catch (e) {
  764. callback(e);
  765. }
  766. const sortedDependencies = [];
  767. for (const pair1 of dependencies) {
  768. for (const pair2 of pair1[1]) {
  769. sortedDependencies.push({
  770. factory: pair1[0],
  771. dependencies: pair2[1]
  772. });
  773. }
  774. }
  775. this.addModuleDependencies(
  776. module,
  777. sortedDependencies,
  778. this.bail,
  779. null,
  780. true,
  781. callback
  782. );
  783. }
  784. /**
  785. * @param {Module} module module to add deps to
  786. * @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through
  787. * @param {(boolean|null)=} bail whether to bail or not
  788. * @param {TODO} cacheGroup optional cacheGroup
  789. * @param {boolean} recursive whether it is recursive traversal
  790. * @param {function} callback callback for when dependencies are finished being added
  791. * @returns {void}
  792. */
  793. addModuleDependencies(
  794. module,
  795. dependencies,
  796. bail,
  797. cacheGroup,
  798. recursive,
  799. callback
  800. ) {
  801. const start = this.profile && Date.now();
  802. const currentProfile = this.profile && {};
  803. asyncLib.forEach(
  804. dependencies,
  805. (item, callback) => {
  806. const dependencies = item.dependencies;
  807. const errorAndCallback = err => {
  808. err.origin = module;
  809. err.dependencies = dependencies;
  810. this.errors.push(err);
  811. if (bail) {
  812. callback(err);
  813. } else {
  814. callback();
  815. }
  816. };
  817. const warningAndCallback = err => {
  818. err.origin = module;
  819. this.warnings.push(err);
  820. callback();
  821. };
  822. const semaphore = this.semaphore;
  823. semaphore.acquire(() => {
  824. const factory = item.factory;
  825. factory.create(
  826. {
  827. contextInfo: {
  828. issuer: module.nameForCondition && module.nameForCondition(),
  829. compiler: this.compiler.name
  830. },
  831. resolveOptions: module.resolveOptions,
  832. context: module.context,
  833. dependencies: dependencies
  834. },
  835. (err, dependentModule) => {
  836. let afterFactory;
  837. const isOptional = () => {
  838. return dependencies.every(d => d.optional);
  839. };
  840. const errorOrWarningAndCallback = err => {
  841. if (isOptional()) {
  842. return warningAndCallback(err);
  843. } else {
  844. return errorAndCallback(err);
  845. }
  846. };
  847. if (err) {
  848. semaphore.release();
  849. return errorOrWarningAndCallback(
  850. new ModuleNotFoundError(module, err)
  851. );
  852. }
  853. if (!dependentModule) {
  854. semaphore.release();
  855. return process.nextTick(callback);
  856. }
  857. if (currentProfile) {
  858. afterFactory = Date.now();
  859. currentProfile.factory = afterFactory - start;
  860. }
  861. const iterationDependencies = depend => {
  862. for (let index = 0; index < depend.length; index++) {
  863. const dep = depend[index];
  864. dep.module = dependentModule;
  865. dependentModule.addReason(module, dep);
  866. }
  867. };
  868. const addModuleResult = this.addModule(
  869. dependentModule,
  870. cacheGroup
  871. );
  872. dependentModule = addModuleResult.module;
  873. iterationDependencies(dependencies);
  874. const afterBuild = () => {
  875. if (recursive && addModuleResult.dependencies) {
  876. this.processModuleDependencies(dependentModule, callback);
  877. } else {
  878. return callback();
  879. }
  880. };
  881. if (addModuleResult.issuer) {
  882. if (currentProfile) {
  883. dependentModule.profile = currentProfile;
  884. }
  885. dependentModule.issuer = module;
  886. } else {
  887. if (this.profile) {
  888. if (module.profile) {
  889. const time = Date.now() - start;
  890. if (
  891. !module.profile.dependencies ||
  892. time > module.profile.dependencies
  893. ) {
  894. module.profile.dependencies = time;
  895. }
  896. }
  897. }
  898. }
  899. if (addModuleResult.build) {
  900. this.buildModule(
  901. dependentModule,
  902. isOptional(),
  903. module,
  904. dependencies,
  905. err => {
  906. if (err) {
  907. semaphore.release();
  908. return errorOrWarningAndCallback(err);
  909. }
  910. if (currentProfile) {
  911. const afterBuilding = Date.now();
  912. currentProfile.building = afterBuilding - afterFactory;
  913. }
  914. semaphore.release();
  915. afterBuild();
  916. }
  917. );
  918. } else {
  919. semaphore.release();
  920. this.waitForBuildingFinished(dependentModule, afterBuild);
  921. }
  922. }
  923. );
  924. });
  925. },
  926. err => {
  927. // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
  928. // errors are created inside closures that keep a reference to the Compilation, so errors are
  929. // leaking the Compilation object.
  930. if (err) {
  931. // eslint-disable-next-line no-self-assign
  932. err.stack = err.stack;
  933. return callback(err);
  934. }
  935. return process.nextTick(callback);
  936. }
  937. );
  938. }
  939. /**
  940. *
  941. * @param {string} context context string path
  942. * @param {Dependency} dependency dependency used to create Module chain
  943. * @param {OnModuleCallback} onModule function invoked on modules creation
  944. * @param {ModuleChainCallback} callback callback for when module chain is complete
  945. * @returns {void} will throw if dependency instance is not a valid Dependency
  946. */
  947. _addModuleChain(context, dependency, onModule, callback) {
  948. const start = this.profile && Date.now();
  949. const currentProfile = this.profile && {};
  950. const errorAndCallback = this.bail
  951. ? err => {
  952. callback(err);
  953. }
  954. : err => {
  955. err.dependencies = [dependency];
  956. this.errors.push(err);
  957. callback();
  958. };
  959. if (
  960. typeof dependency !== "object" ||
  961. dependency === null ||
  962. !dependency.constructor
  963. ) {
  964. throw new Error("Parameter 'dependency' must be a Dependency");
  965. }
  966. const Dep = /** @type {DepConstructor} */ (dependency.constructor);
  967. const moduleFactory = this.dependencyFactories.get(Dep);
  968. if (!moduleFactory) {
  969. throw new Error(
  970. `No dependency factory available for this dependency type: ${dependency.constructor.name}`
  971. );
  972. }
  973. this.semaphore.acquire(() => {
  974. moduleFactory.create(
  975. {
  976. contextInfo: {
  977. issuer: "",
  978. compiler: this.compiler.name
  979. },
  980. context: context,
  981. dependencies: [dependency]
  982. },
  983. (err, module) => {
  984. if (err) {
  985. this.semaphore.release();
  986. return errorAndCallback(new EntryModuleNotFoundError(err));
  987. }
  988. let afterFactory;
  989. if (currentProfile) {
  990. afterFactory = Date.now();
  991. currentProfile.factory = afterFactory - start;
  992. }
  993. const addModuleResult = this.addModule(module);
  994. module = addModuleResult.module;
  995. onModule(module);
  996. dependency.module = module;
  997. module.addReason(null, dependency);
  998. const afterBuild = () => {
  999. if (addModuleResult.dependencies) {
  1000. this.processModuleDependencies(module, err => {
  1001. if (err) return callback(err);
  1002. callback(null, module);
  1003. });
  1004. } else {
  1005. return callback(null, module);
  1006. }
  1007. };
  1008. if (addModuleResult.issuer) {
  1009. if (currentProfile) {
  1010. module.profile = currentProfile;
  1011. }
  1012. }
  1013. if (addModuleResult.build) {
  1014. this.buildModule(module, false, null, null, err => {
  1015. if (err) {
  1016. this.semaphore.release();
  1017. return errorAndCallback(err);
  1018. }
  1019. if (currentProfile) {
  1020. const afterBuilding = Date.now();
  1021. currentProfile.building = afterBuilding - afterFactory;
  1022. }
  1023. this.semaphore.release();
  1024. afterBuild();
  1025. });
  1026. } else {
  1027. this.semaphore.release();
  1028. this.waitForBuildingFinished(module, afterBuild);
  1029. }
  1030. }
  1031. );
  1032. });
  1033. }
  1034. /**
  1035. *
  1036. * @param {string} context context path for entry
  1037. * @param {Dependency} entry entry dependency being created
  1038. * @param {string} name name of entry
  1039. * @param {ModuleCallback} callback callback function
  1040. * @returns {void} returns
  1041. */
  1042. addEntry(context, entry, name, callback) {
  1043. this.hooks.addEntry.call(entry, name);
  1044. const slot = {
  1045. name: name,
  1046. // TODO webpack 5 remove `request`
  1047. request: null,
  1048. module: null
  1049. };
  1050. if (entry instanceof ModuleDependency) {
  1051. slot.request = entry.request;
  1052. }
  1053. // TODO webpack 5: merge modules instead when multiple entry modules are supported
  1054. const idx = this._preparedEntrypoints.findIndex(slot => slot.name === name);
  1055. if (idx >= 0) {
  1056. // Overwrite existing entrypoint
  1057. this._preparedEntrypoints[idx] = slot;
  1058. } else {
  1059. this._preparedEntrypoints.push(slot);
  1060. }
  1061. this._addModuleChain(
  1062. context,
  1063. entry,
  1064. module => {
  1065. this.entries.push(module);
  1066. },
  1067. (err, module) => {
  1068. if (err) {
  1069. this.hooks.failedEntry.call(entry, name, err);
  1070. return callback(err);
  1071. }
  1072. if (module) {
  1073. slot.module = module;
  1074. } else {
  1075. const idx = this._preparedEntrypoints.indexOf(slot);
  1076. if (idx >= 0) {
  1077. this._preparedEntrypoints.splice(idx, 1);
  1078. }
  1079. }
  1080. this.hooks.succeedEntry.call(entry, name, module);
  1081. return callback(null, module);
  1082. }
  1083. );
  1084. }
  1085. /**
  1086. * @param {string} context context path string
  1087. * @param {Dependency} dependency dep used to create module
  1088. * @param {ModuleCallback} callback module callback sending module up a level
  1089. * @returns {void}
  1090. */
  1091. prefetch(context, dependency, callback) {
  1092. this._addModuleChain(
  1093. context,
  1094. dependency,
  1095. module => {
  1096. module.prefetched = true;
  1097. },
  1098. callback
  1099. );
  1100. }
  1101. /**
  1102. * @param {Module} module module to be rebuilt
  1103. * @param {Callback} thisCallback callback when module finishes rebuilding
  1104. * @returns {void}
  1105. */
  1106. rebuildModule(module, thisCallback) {
  1107. let callbackList = this._rebuildingModules.get(module);
  1108. if (callbackList) {
  1109. callbackList.push(thisCallback);
  1110. return;
  1111. }
  1112. this._rebuildingModules.set(module, (callbackList = [thisCallback]));
  1113. const callback = err => {
  1114. this._rebuildingModules.delete(module);
  1115. for (const cb of callbackList) {
  1116. cb(err);
  1117. }
  1118. };
  1119. this.hooks.rebuildModule.call(module);
  1120. const oldDependencies = module.dependencies.slice();
  1121. const oldVariables = module.variables.slice();
  1122. const oldBlocks = module.blocks.slice();
  1123. module.unbuild();
  1124. this.buildModule(module, false, module, null, err => {
  1125. if (err) {
  1126. this.hooks.finishRebuildingModule.call(module);
  1127. return callback(err);
  1128. }
  1129. this.processModuleDependencies(module, err => {
  1130. if (err) return callback(err);
  1131. this.removeReasonsOfDependencyBlock(module, {
  1132. dependencies: oldDependencies,
  1133. variables: oldVariables,
  1134. blocks: oldBlocks
  1135. });
  1136. this.hooks.finishRebuildingModule.call(module);
  1137. callback();
  1138. });
  1139. });
  1140. }
  1141. finish(callback) {
  1142. const modules = this.modules;
  1143. this.hooks.finishModules.callAsync(modules, err => {
  1144. if (err) return callback(err);
  1145. for (let index = 0; index < modules.length; index++) {
  1146. const module = modules[index];
  1147. this.reportDependencyErrorsAndWarnings(module, [module]);
  1148. }
  1149. callback();
  1150. });
  1151. }
  1152. unseal() {
  1153. this.hooks.unseal.call();
  1154. this.chunks.length = 0;
  1155. this.chunkGroups.length = 0;
  1156. this.namedChunks.clear();
  1157. this.namedChunkGroups.clear();
  1158. this.additionalChunkAssets.length = 0;
  1159. this.assets = {};
  1160. this.assetsInfo.clear();
  1161. for (const module of this.modules) {
  1162. module.unseal();
  1163. }
  1164. }
  1165. /**
  1166. * @param {Callback} callback signals when the seal method is finishes
  1167. * @returns {void}
  1168. */
  1169. seal(callback) {
  1170. this.hooks.seal.call();
  1171. while (
  1172. this.hooks.optimizeDependenciesBasic.call(this.modules) ||
  1173. this.hooks.optimizeDependencies.call(this.modules) ||
  1174. this.hooks.optimizeDependenciesAdvanced.call(this.modules)
  1175. ) {
  1176. /* empty */
  1177. }
  1178. this.hooks.afterOptimizeDependencies.call(this.modules);
  1179. this.hooks.beforeChunks.call();
  1180. for (const preparedEntrypoint of this._preparedEntrypoints) {
  1181. const module = preparedEntrypoint.module;
  1182. const name = preparedEntrypoint.name;
  1183. const chunk = this.addChunk(name);
  1184. const entrypoint = new Entrypoint(name);
  1185. entrypoint.setRuntimeChunk(chunk);
  1186. entrypoint.addOrigin(null, name, preparedEntrypoint.request);
  1187. this.namedChunkGroups.set(name, entrypoint);
  1188. this.entrypoints.set(name, entrypoint);
  1189. this.chunkGroups.push(entrypoint);
  1190. GraphHelpers.connectChunkGroupAndChunk(entrypoint, chunk);
  1191. GraphHelpers.connectChunkAndModule(chunk, module);
  1192. chunk.entryModule = module;
  1193. chunk.name = name;
  1194. this.assignDepth(module);
  1195. }
  1196. buildChunkGraph(
  1197. this,
  1198. /** @type {Entrypoint[]} */ (this.chunkGroups.slice())
  1199. );
  1200. this.sortModules(this.modules);
  1201. this.hooks.afterChunks.call(this.chunks);
  1202. this.hooks.optimize.call();
  1203. while (
  1204. this.hooks.optimizeModulesBasic.call(this.modules) ||
  1205. this.hooks.optimizeModules.call(this.modules) ||
  1206. this.hooks.optimizeModulesAdvanced.call(this.modules)
  1207. ) {
  1208. /* empty */
  1209. }
  1210. this.hooks.afterOptimizeModules.call(this.modules);
  1211. while (
  1212. this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) ||
  1213. this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) ||
  1214. this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)
  1215. ) {
  1216. /* empty */
  1217. }
  1218. this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
  1219. this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
  1220. if (err) {
  1221. return callback(err);
  1222. }
  1223. this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
  1224. while (
  1225. this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) ||
  1226. this.hooks.optimizeChunkModules.call(this.chunks, this.modules) ||
  1227. this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules)
  1228. ) {
  1229. /* empty */
  1230. }
  1231. this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
  1232. const shouldRecord = this.hooks.shouldRecord.call() !== false;
  1233. this.hooks.reviveModules.call(this.modules, this.records);
  1234. this.hooks.optimizeModuleOrder.call(this.modules);
  1235. this.hooks.advancedOptimizeModuleOrder.call(this.modules);
  1236. this.hooks.beforeModuleIds.call(this.modules);
  1237. this.hooks.moduleIds.call(this.modules);
  1238. this.applyModuleIds();
  1239. this.hooks.optimizeModuleIds.call(this.modules);
  1240. this.hooks.afterOptimizeModuleIds.call(this.modules);
  1241. this.sortItemsWithModuleIds();
  1242. this.hooks.reviveChunks.call(this.chunks, this.records);
  1243. this.hooks.optimizeChunkOrder.call(this.chunks);
  1244. this.hooks.beforeChunkIds.call(this.chunks);
  1245. this.applyChunkIds();
  1246. this.hooks.optimizeChunkIds.call(this.chunks);
  1247. this.hooks.afterOptimizeChunkIds.call(this.chunks);
  1248. this.sortItemsWithChunkIds();
  1249. if (shouldRecord) {
  1250. this.hooks.recordModules.call(this.modules, this.records);
  1251. this.hooks.recordChunks.call(this.chunks, this.records);
  1252. }
  1253. this.hooks.beforeHash.call();
  1254. this.createHash();
  1255. this.hooks.afterHash.call();
  1256. if (shouldRecord) {
  1257. this.hooks.recordHash.call(this.records);
  1258. }
  1259. this.hooks.beforeModuleAssets.call();
  1260. this.createModuleAssets();
  1261. if (this.hooks.shouldGenerateChunkAssets.call() !== false) {
  1262. this.hooks.beforeChunkAssets.call();
  1263. this.createChunkAssets();
  1264. }
  1265. this.hooks.additionalChunkAssets.call(this.chunks);
  1266. this.summarizeDependencies();
  1267. if (shouldRecord) {
  1268. this.hooks.record.call(this, this.records);
  1269. }
  1270. this.hooks.additionalAssets.callAsync(err => {
  1271. if (err) {
  1272. return callback(err);
  1273. }
  1274. this.hooks.optimizeChunkAssets.callAsync(this.chunks, err => {
  1275. if (err) {
  1276. return callback(err);
  1277. }
  1278. this.hooks.afterOptimizeChunkAssets.call(this.chunks);
  1279. this.hooks.optimizeAssets.callAsync(this.assets, err => {
  1280. if (err) {
  1281. return callback(err);
  1282. }
  1283. this.hooks.afterOptimizeAssets.call(this.assets);
  1284. if (this.hooks.needAdditionalSeal.call()) {
  1285. this.unseal();
  1286. return this.seal(callback);
  1287. }
  1288. return this.hooks.afterSeal.callAsync(callback);
  1289. });
  1290. });
  1291. });
  1292. });
  1293. }
  1294. /**
  1295. * @param {Module[]} modules the modules array on compilation to perform the sort for
  1296. * @returns {void}
  1297. */
  1298. sortModules(modules) {
  1299. // TODO webpack 5: this should only be enabled when `moduleIds: "natural"`
  1300. // TODO move it into a plugin (NaturalModuleIdsPlugin) and use this in WebpackOptionsApply
  1301. // TODO remove this method
  1302. modules.sort(byIndexOrIdentifier);
  1303. }
  1304. /**
  1305. * @param {Module} module moulde to report from
  1306. * @param {DependenciesBlock[]} blocks blocks to report from
  1307. * @returns {void}
  1308. */
  1309. reportDependencyErrorsAndWarnings(module, blocks) {
  1310. for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
  1311. const block = blocks[indexBlock];
  1312. const dependencies = block.dependencies;
  1313. for (let indexDep = 0; indexDep < dependencies.length; indexDep++) {
  1314. const d = dependencies[indexDep];
  1315. const warnings = d.getWarnings();
  1316. if (warnings) {
  1317. for (let indexWar = 0; indexWar < warnings.length; indexWar++) {
  1318. const w = warnings[indexWar];
  1319. const warning = new ModuleDependencyWarning(module, w, d.loc);
  1320. this.warnings.push(warning);
  1321. }
  1322. }
  1323. const errors = d.getErrors();
  1324. if (errors) {
  1325. for (let indexErr = 0; indexErr < errors.length; indexErr++) {
  1326. const e = errors[indexErr];
  1327. const error = new ModuleDependencyError(module, e, d.loc);
  1328. this.errors.push(error);
  1329. }
  1330. }
  1331. }
  1332. this.reportDependencyErrorsAndWarnings(module, block.blocks);
  1333. }
  1334. }
  1335. /**
  1336. * @param {TODO} groupOptions options for the chunk group
  1337. * @param {Module} module the module the references the chunk group
  1338. * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
  1339. * @param {string} request the request from which the the chunk group is referenced
  1340. * @returns {ChunkGroup} the new or existing chunk group
  1341. */
  1342. addChunkInGroup(groupOptions, module, loc, request) {
  1343. if (typeof groupOptions === "string") {
  1344. groupOptions = { name: groupOptions };
  1345. }
  1346. const name = groupOptions.name;
  1347. if (name) {
  1348. const chunkGroup = this.namedChunkGroups.get(name);
  1349. if (chunkGroup !== undefined) {
  1350. chunkGroup.addOptions(groupOptions);
  1351. if (module) {
  1352. chunkGroup.addOrigin(module, loc, request);
  1353. }
  1354. return chunkGroup;
  1355. }
  1356. }
  1357. const chunkGroup = new ChunkGroup(groupOptions);
  1358. if (module) chunkGroup.addOrigin(module, loc, request);
  1359. const chunk = this.addChunk(name);
  1360. GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk);
  1361. this.chunkGroups.push(chunkGroup);
  1362. if (name) {
  1363. this.namedChunkGroups.set(name, chunkGroup);
  1364. }
  1365. return chunkGroup;
  1366. }
  1367. /**
  1368. * This method first looks to see if a name is provided for a new chunk,
  1369. * and first looks to see if any named chunks already exist and reuse that chunk instead.
  1370. *
  1371. * @param {string=} name optional chunk name to be provided
  1372. * @returns {Chunk} create a chunk (invoked during seal event)
  1373. */
  1374. addChunk(name) {
  1375. if (name) {
  1376. const chunk = this.namedChunks.get(name);
  1377. if (chunk !== undefined) {
  1378. return chunk;
  1379. }
  1380. }
  1381. const chunk = new Chunk(name);
  1382. this.chunks.push(chunk);
  1383. if (name) {
  1384. this.namedChunks.set(name, chunk);
  1385. }
  1386. return chunk;
  1387. }
  1388. /**
  1389. * @param {Module} module module to assign depth
  1390. * @returns {void}
  1391. */
  1392. assignDepth(module) {
  1393. const queue = new Set([module]);
  1394. let depth;
  1395. module.depth = 0;
  1396. /**
  1397. * @param {Module} module module for processeing
  1398. * @returns {void}
  1399. */
  1400. const enqueueJob = module => {
  1401. const d = module.depth;
  1402. if (typeof d === "number" && d <= depth) return;
  1403. queue.add(module);
  1404. module.depth = depth;
  1405. };
  1406. /**
  1407. * @param {Dependency} dependency dependency to assign depth to
  1408. * @returns {void}
  1409. */
  1410. const assignDepthToDependency = dependency => {
  1411. if (dependency.module) {
  1412. enqueueJob(dependency.module);
  1413. }
  1414. };
  1415. /**
  1416. * @param {DependenciesBlock} block block to assign depth to
  1417. * @returns {void}
  1418. */
  1419. const assignDepthToDependencyBlock = block => {
  1420. if (block.variables) {
  1421. iterationBlockVariable(block.variables, assignDepthToDependency);
  1422. }
  1423. if (block.dependencies) {
  1424. iterationOfArrayCallback(block.dependencies, assignDepthToDependency);
  1425. }
  1426. if (block.blocks) {
  1427. iterationOfArrayCallback(block.blocks, assignDepthToDependencyBlock);
  1428. }
  1429. };
  1430. for (module of queue) {
  1431. queue.delete(module);
  1432. depth = module.depth;
  1433. depth++;
  1434. assignDepthToDependencyBlock(module);
  1435. }
  1436. }
  1437. /**
  1438. * @param {Module} module the module containing the dependency
  1439. * @param {Dependency} dependency the dependency
  1440. * @returns {DependencyReference} a reference for the dependency
  1441. */
  1442. getDependencyReference(module, dependency) {
  1443. // TODO remove dep.getReference existence check in webpack 5
  1444. if (typeof dependency.getReference !== "function") return null;
  1445. const ref = dependency.getReference();
  1446. if (!ref) return null;
  1447. return this.hooks.dependencyReference.call(ref, dependency, module);
  1448. }
  1449. /**
  1450. *
  1451. * @param {Module} module module relationship for removal
  1452. * @param {DependenciesBlockLike} block //TODO: good description
  1453. * @returns {void}
  1454. */
  1455. removeReasonsOfDependencyBlock(module, block) {
  1456. const iteratorDependency = d => {
  1457. if (!d.module) {
  1458. return;
  1459. }
  1460. if (d.module.removeReason(module, d)) {
  1461. for (const chunk of d.module.chunksIterable) {
  1462. this.patchChunksAfterReasonRemoval(d.module, chunk);
  1463. }
  1464. }
  1465. };
  1466. if (block.blocks) {
  1467. iterationOfArrayCallback(block.blocks, block =>
  1468. this.removeReasonsOfDependencyBlock(module, block)
  1469. );
  1470. }
  1471. if (block.dependencies) {
  1472. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  1473. }
  1474. if (block.variables) {
  1475. iterationBlockVariable(block.variables, iteratorDependency);
  1476. }
  1477. }
  1478. /**
  1479. * @param {Module} module module to patch tie
  1480. * @param {Chunk} chunk chunk to patch tie
  1481. * @returns {void}
  1482. */
  1483. patchChunksAfterReasonRemoval(module, chunk) {
  1484. if (!module.hasReasons()) {
  1485. this.removeReasonsOfDependencyBlock(module, module);
  1486. }
  1487. if (!module.hasReasonForChunk(chunk)) {
  1488. if (module.removeChunk(chunk)) {
  1489. this.removeChunkFromDependencies(module, chunk);
  1490. }
  1491. }
  1492. }
  1493. /**
  1494. *
  1495. * @param {DependenciesBlock} block block tie for Chunk
  1496. * @param {Chunk} chunk chunk to remove from dep
  1497. * @returns {void}
  1498. */
  1499. removeChunkFromDependencies(block, chunk) {
  1500. const iteratorDependency = d => {
  1501. if (!d.module) {
  1502. return;
  1503. }
  1504. this.patchChunksAfterReasonRemoval(d.module, chunk);
  1505. };
  1506. const blocks = block.blocks;
  1507. for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
  1508. const asyncBlock = blocks[indexBlock];
  1509. // Grab all chunks from the first Block's AsyncDepBlock
  1510. const chunks = asyncBlock.chunkGroup.chunks;
  1511. // For each chunk in chunkGroup
  1512. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1513. const iteratedChunk = chunks[indexChunk];
  1514. asyncBlock.chunkGroup.removeChunk(iteratedChunk);
  1515. asyncBlock.chunkGroup.removeParent(iteratedChunk);
  1516. // Recurse
  1517. this.removeChunkFromDependencies(block, iteratedChunk);
  1518. }
  1519. }
  1520. if (block.dependencies) {
  1521. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  1522. }
  1523. if (block.variables) {
  1524. iterationBlockVariable(block.variables, iteratorDependency);
  1525. }
  1526. }
  1527. applyModuleIds() {
  1528. const unusedIds = [];
  1529. let nextFreeModuleId = 0;
  1530. const usedIds = new Set();
  1531. if (this.usedModuleIds) {
  1532. for (const id of this.usedModuleIds) {
  1533. usedIds.add(id);
  1534. }
  1535. }
  1536. const modules1 = this.modules;
  1537. for (let indexModule1 = 0; indexModule1 < modules1.length; indexModule1++) {
  1538. const module1 = modules1[indexModule1];
  1539. if (module1.id !== null) {
  1540. usedIds.add(module1.id);
  1541. }
  1542. }
  1543. if (usedIds.size > 0) {
  1544. let usedIdMax = -1;
  1545. for (const usedIdKey of usedIds) {
  1546. if (typeof usedIdKey !== "number") {
  1547. continue;
  1548. }
  1549. usedIdMax = Math.max(usedIdMax, usedIdKey);
  1550. }
  1551. let lengthFreeModules = (nextFreeModuleId = usedIdMax + 1);
  1552. while (lengthFreeModules--) {
  1553. if (!usedIds.has(lengthFreeModules)) {
  1554. unusedIds.push(lengthFreeModules);
  1555. }
  1556. }
  1557. }
  1558. const modules2 = this.modules;
  1559. for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
  1560. const module2 = modules2[indexModule2];
  1561. if (module2.id === null) {
  1562. if (unusedIds.length > 0) {
  1563. module2.id = unusedIds.pop();
  1564. } else {
  1565. module2.id = nextFreeModuleId++;
  1566. }
  1567. }
  1568. }
  1569. }
  1570. applyChunkIds() {
  1571. /** @type {Set<number>} */
  1572. const usedIds = new Set();
  1573. // Get used ids from usedChunkIds property (i. e. from records)
  1574. if (this.usedChunkIds) {
  1575. for (const id of this.usedChunkIds) {
  1576. if (typeof id !== "number") {
  1577. continue;
  1578. }
  1579. usedIds.add(id);
  1580. }
  1581. }
  1582. // Get used ids from existing chunks
  1583. const chunks = this.chunks;
  1584. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1585. const chunk = chunks[indexChunk];
  1586. const usedIdValue = chunk.id;
  1587. if (typeof usedIdValue !== "number") {
  1588. continue;
  1589. }
  1590. usedIds.add(usedIdValue);
  1591. }
  1592. // Calculate maximum assigned chunk id
  1593. let nextFreeChunkId = -1;
  1594. for (const id of usedIds) {
  1595. nextFreeChunkId = Math.max(nextFreeChunkId, id);
  1596. }
  1597. nextFreeChunkId++;
  1598. // Determine free chunk ids from 0 to maximum
  1599. /** @type {number[]} */
  1600. const unusedIds = [];
  1601. if (nextFreeChunkId > 0) {
  1602. let index = nextFreeChunkId;
  1603. while (index--) {
  1604. if (!usedIds.has(index)) {
  1605. unusedIds.push(index);
  1606. }
  1607. }
  1608. }
  1609. // Assign ids to chunk which has no id
  1610. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1611. const chunk = chunks[indexChunk];
  1612. if (chunk.id === null) {
  1613. if (unusedIds.length > 0) {
  1614. chunk.id = unusedIds.pop();
  1615. } else {
  1616. chunk.id = nextFreeChunkId++;
  1617. }
  1618. }
  1619. if (!chunk.ids) {
  1620. chunk.ids = [chunk.id];
  1621. }
  1622. }
  1623. }
  1624. sortItemsWithModuleIds() {
  1625. this.modules.sort(byIdOrIdentifier);
  1626. const modules = this.modules;
  1627. for (let indexModule = 0; indexModule < modules.length; indexModule++) {
  1628. modules[indexModule].sortItems(false);
  1629. }
  1630. const chunks = this.chunks;
  1631. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1632. chunks[indexChunk].sortItems();
  1633. }
  1634. chunks.sort((a, b) => a.compareTo(b));
  1635. }
  1636. sortItemsWithChunkIds() {
  1637. for (const chunkGroup of this.chunkGroups) {
  1638. chunkGroup.sortItems();
  1639. }
  1640. this.chunks.sort(byId);
  1641. for (
  1642. let indexModule = 0;
  1643. indexModule < this.modules.length;
  1644. indexModule++
  1645. ) {
  1646. this.modules[indexModule].sortItems(true);
  1647. }
  1648. const chunks = this.chunks;
  1649. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1650. chunks[indexChunk].sortItems();
  1651. }
  1652. /**
  1653. * Used to sort errors and warnings in compilation. this.warnings, and
  1654. * this.errors contribute to the compilation hash and therefore should be
  1655. * updated whenever other references (having a chunk id) are sorted. This preserves the hash
  1656. * integrity
  1657. *
  1658. * @param {WebpackError} a first WebpackError instance (including subclasses)
  1659. * @param {WebpackError} b second WebpackError instance (including subclasses)
  1660. * @returns {-1|0|1} sort order index
  1661. */
  1662. const byMessage = (a, b) => {
  1663. const ma = `${a.message}`;
  1664. const mb = `${b.message}`;
  1665. if (ma < mb) return -1;
  1666. if (mb < ma) return 1;
  1667. return 0;
  1668. };
  1669. this.errors.sort(byMessage);
  1670. this.warnings.sort(byMessage);
  1671. this.children.sort(byNameOrHash);
  1672. }
  1673. summarizeDependencies() {
  1674. this.fileDependencies = new SortableSet(this.compilationDependencies);
  1675. this.contextDependencies = new SortableSet();
  1676. this.missingDependencies = new SortableSet();
  1677. for (
  1678. let indexChildren = 0;
  1679. indexChildren < this.children.length;
  1680. indexChildren++
  1681. ) {
  1682. const child = this.children[indexChildren];
  1683. addAllToSet(this.fileDependencies, child.fileDependencies);
  1684. addAllToSet(this.contextDependencies, child.contextDependencies);
  1685. addAllToSet(this.missingDependencies, child.missingDependencies);
  1686. }
  1687. for (
  1688. let indexModule = 0;
  1689. indexModule < this.modules.length;
  1690. indexModule++
  1691. ) {
  1692. const module = this.modules[indexModule];
  1693. if (module.buildInfo.fileDependencies) {
  1694. addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies);
  1695. }
  1696. if (module.buildInfo.contextDependencies) {
  1697. addAllToSet(
  1698. this.contextDependencies,
  1699. module.buildInfo.contextDependencies
  1700. );
  1701. }
  1702. }
  1703. for (const error of this.errors) {
  1704. if (
  1705. typeof error.missing === "object" &&
  1706. error.missing &&
  1707. error.missing[Symbol.iterator]
  1708. ) {
  1709. addAllToSet(this.missingDependencies, error.missing);
  1710. }
  1711. }
  1712. this.fileDependencies.sort();
  1713. this.contextDependencies.sort();
  1714. this.missingDependencies.sort();
  1715. }
  1716. createHash() {
  1717. const outputOptions = this.outputOptions;
  1718. const hashFunction = outputOptions.hashFunction;
  1719. const hashDigest = outputOptions.hashDigest;
  1720. const hashDigestLength = outputOptions.hashDigestLength;
  1721. const hash = createHash(hashFunction);
  1722. if (outputOptions.hashSalt) {
  1723. hash.update(outputOptions.hashSalt);
  1724. }
  1725. this.mainTemplate.updateHash(hash);
  1726. this.chunkTemplate.updateHash(hash);
  1727. for (const key of Object.keys(this.moduleTemplates).sort()) {
  1728. this.moduleTemplates[key].updateHash(hash);
  1729. }
  1730. for (const child of this.children) {
  1731. hash.update(child.hash);
  1732. }
  1733. for (const warning of this.warnings) {
  1734. hash.update(`${warning.message}`);
  1735. }
  1736. for (const error of this.errors) {
  1737. hash.update(`${error.message}`);
  1738. }
  1739. const modules = this.modules;
  1740. for (let i = 0; i < modules.length; i++) {
  1741. const module = modules[i];
  1742. const moduleHash = createHash(hashFunction);
  1743. module.updateHash(moduleHash);
  1744. module.hash = /** @type {string} */ (moduleHash.digest(hashDigest));
  1745. module.renderedHash = module.hash.substr(0, hashDigestLength);
  1746. }
  1747. // clone needed as sort below is inplace mutation
  1748. const chunks = this.chunks.slice();
  1749. /**
  1750. * sort here will bring all "falsy" values to the beginning
  1751. * this is needed as the "hasRuntime()" chunks are dependent on the
  1752. * hashes of the non-runtime chunks.
  1753. */
  1754. chunks.sort((a, b) => {
  1755. const aEntry = a.hasRuntime();
  1756. const bEntry = b.hasRuntime();
  1757. if (aEntry && !bEntry) return 1;
  1758. if (!aEntry && bEntry) return -1;
  1759. return byId(a, b);
  1760. });
  1761. for (let i = 0; i < chunks.length; i++) {
  1762. const chunk = chunks[i];
  1763. const chunkHash = createHash(hashFunction);
  1764. try {
  1765. if (outputOptions.hashSalt) {
  1766. chunkHash.update(outputOptions.hashSalt);
  1767. }
  1768. chunk.updateHash(chunkHash);
  1769. const template = chunk.hasRuntime()
  1770. ? this.mainTemplate
  1771. : this.chunkTemplate;
  1772. template.updateHashForChunk(
  1773. chunkHash,
  1774. chunk,
  1775. this.moduleTemplates.javascript,
  1776. this.dependencyTemplates
  1777. );
  1778. this.hooks.chunkHash.call(chunk, chunkHash);
  1779. chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest));
  1780. hash.update(chunk.hash);
  1781. chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
  1782. this.hooks.contentHash.call(chunk);
  1783. } catch (err) {
  1784. this.errors.push(new ChunkRenderError(chunk, "", err));
  1785. }
  1786. }
  1787. this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
  1788. this.hash = this.fullHash.substr(0, hashDigestLength);
  1789. }
  1790. /**
  1791. * @param {string} update extra information
  1792. * @returns {void}
  1793. */
  1794. modifyHash(update) {
  1795. const outputOptions = this.outputOptions;
  1796. const hashFunction = outputOptions.hashFunction;
  1797. const hashDigest = outputOptions.hashDigest;
  1798. const hashDigestLength = outputOptions.hashDigestLength;
  1799. const hash = createHash(hashFunction);
  1800. hash.update(this.fullHash);
  1801. hash.update(update);
  1802. this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
  1803. this.hash = this.fullHash.substr(0, hashDigestLength);
  1804. }
  1805. /**
  1806. * @param {string} file file name
  1807. * @param {Source} source asset source
  1808. * @param {AssetInfo} assetInfo extra asset information
  1809. * @returns {void}
  1810. */
  1811. emitAsset(file, source, assetInfo = {}) {
  1812. if (this.assets[file]) {
  1813. if (!isSourceEqual(this.assets[file], source)) {
  1814. // TODO webpack 5: make this an error instead
  1815. this.warnings.push(
  1816. new WebpackError(
  1817. `Conflict: Multiple assets emit different content to the same filename ${file}`
  1818. )
  1819. );
  1820. this.assets[file] = source;
  1821. this.assetsInfo.set(file, assetInfo);
  1822. return;
  1823. }
  1824. const oldInfo = this.assetsInfo.get(file);
  1825. this.assetsInfo.set(file, Object.assign({}, oldInfo, assetInfo));
  1826. return;
  1827. }
  1828. this.assets[file] = source;
  1829. this.assetsInfo.set(file, assetInfo);
  1830. }
  1831. /**
  1832. * @param {string} file file name
  1833. * @param {Source | function(Source): Source} newSourceOrFunction new asset source or function converting old to new
  1834. * @param {AssetInfo | function(AssetInfo | undefined): AssetInfo} assetInfoUpdateOrFunction new asset info or function converting old to new
  1835. */
  1836. updateAsset(
  1837. file,
  1838. newSourceOrFunction,
  1839. assetInfoUpdateOrFunction = undefined
  1840. ) {
  1841. if (!this.assets[file]) {
  1842. throw new Error(
  1843. `Called Compilation.updateAsset for not existing filename ${file}`
  1844. );
  1845. }
  1846. if (typeof newSourceOrFunction === "function") {
  1847. this.assets[file] = newSourceOrFunction(this.assets[file]);
  1848. } else {
  1849. this.assets[file] = newSourceOrFunction;
  1850. }
  1851. if (assetInfoUpdateOrFunction !== undefined) {
  1852. const oldInfo = this.assetsInfo.get(file);
  1853. if (typeof assetInfoUpdateOrFunction === "function") {
  1854. this.assetsInfo.set(file, assetInfoUpdateOrFunction(oldInfo || {}));
  1855. } else {
  1856. this.assetsInfo.set(
  1857. file,
  1858. Object.assign({}, oldInfo, assetInfoUpdateOrFunction)
  1859. );
  1860. }
  1861. }
  1862. }
  1863. getAssets() {
  1864. /** @type {Asset[]} */
  1865. const array = [];
  1866. for (const assetName of Object.keys(this.assets)) {
  1867. if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) {
  1868. array.push({
  1869. name: assetName,
  1870. source: this.assets[assetName],
  1871. info: this.assetsInfo.get(assetName) || {}
  1872. });
  1873. }
  1874. }
  1875. return array;
  1876. }
  1877. /**
  1878. * @param {string} name the name of the asset
  1879. * @returns {Asset | undefined} the asset or undefined when not found
  1880. */
  1881. getAsset(name) {
  1882. if (!Object.prototype.hasOwnProperty.call(this.assets, name))
  1883. return undefined;
  1884. return {
  1885. name,
  1886. source: this.assets[name],
  1887. info: this.assetsInfo.get(name) || {}
  1888. };
  1889. }
  1890. createModuleAssets() {
  1891. for (let i = 0; i < this.modules.length; i++) {
  1892. const module = this.modules[i];
  1893. if (module.buildInfo.assets) {
  1894. const assetsInfo = module.buildInfo.assetsInfo;
  1895. for (const assetName of Object.keys(module.buildInfo.assets)) {
  1896. const fileName = this.getPath(assetName);
  1897. this.emitAsset(
  1898. fileName,
  1899. module.buildInfo.assets[assetName],
  1900. assetsInfo ? assetsInfo.get(assetName) : undefined
  1901. );
  1902. this.hooks.moduleAsset.call(module, fileName);
  1903. }
  1904. }
  1905. }
  1906. }
  1907. createChunkAssets() {
  1908. const outputOptions = this.outputOptions;
  1909. const cachedSourceMap = new Map();
  1910. /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
  1911. const alreadyWrittenFiles = new Map();
  1912. for (let i = 0; i < this.chunks.length; i++) {
  1913. const chunk = this.chunks[i];
  1914. chunk.files = [];
  1915. let source;
  1916. let file;
  1917. let filenameTemplate;
  1918. try {
  1919. const template = chunk.hasRuntime()
  1920. ? this.mainTemplate
  1921. : this.chunkTemplate;
  1922. const manifest = template.getRenderManifest({
  1923. chunk,
  1924. hash: this.hash,
  1925. fullHash: this.fullHash,
  1926. outputOptions,
  1927. moduleTemplates: this.moduleTemplates,
  1928. dependencyTemplates: this.dependencyTemplates
  1929. }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }]
  1930. for (const fileManifest of manifest) {
  1931. const cacheName = fileManifest.identifier;
  1932. const usedHash = fileManifest.hash;
  1933. filenameTemplate = fileManifest.filenameTemplate;
  1934. const pathAndInfo = this.getPathWithInfo(
  1935. filenameTemplate,
  1936. fileManifest.pathOptions
  1937. );
  1938. file = pathAndInfo.path;
  1939. const assetInfo = pathAndInfo.info;
  1940. // check if the same filename was already written by another chunk
  1941. const alreadyWritten = alreadyWrittenFiles.get(file);
  1942. if (alreadyWritten !== undefined) {
  1943. if (alreadyWritten.hash === usedHash) {
  1944. if (this.cache) {
  1945. this.cache[cacheName] = {
  1946. hash: usedHash,
  1947. source: alreadyWritten.source
  1948. };
  1949. }
  1950. chunk.files.push(file);
  1951. this.hooks.chunkAsset.call(chunk, file);
  1952. continue;
  1953. } else {
  1954. throw new Error(
  1955. `Conflict: Multiple chunks emit assets to the same filename ${file}` +
  1956. ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
  1957. );
  1958. }
  1959. }
  1960. if (
  1961. this.cache &&
  1962. this.cache[cacheName] &&
  1963. this.cache[cacheName].hash === usedHash
  1964. ) {
  1965. source = this.cache[cacheName].source;
  1966. } else {
  1967. source = fileManifest.render();
  1968. // Ensure that source is a cached source to avoid additional cost because of repeated access
  1969. if (!(source instanceof CachedSource)) {
  1970. const cacheEntry = cachedSourceMap.get(source);
  1971. if (cacheEntry) {
  1972. source = cacheEntry;
  1973. } else {
  1974. const cachedSource = new CachedSource(source);
  1975. cachedSourceMap.set(source, cachedSource);
  1976. source = cachedSource;
  1977. }
  1978. }
  1979. if (this.cache) {
  1980. this.cache[cacheName] = {
  1981. hash: usedHash,
  1982. source
  1983. };
  1984. }
  1985. }
  1986. this.emitAsset(file, source, assetInfo);
  1987. chunk.files.push(file);
  1988. this.hooks.chunkAsset.call(chunk, file);
  1989. alreadyWrittenFiles.set(file, {
  1990. hash: usedHash,
  1991. source,
  1992. chunk
  1993. });
  1994. }
  1995. } catch (err) {
  1996. this.errors.push(
  1997. new ChunkRenderError(chunk, file || filenameTemplate, err)
  1998. );
  1999. }
  2000. }
  2001. }
  2002. /**
  2003. * @param {string} filename used to get asset path with hash
  2004. * @param {TODO=} data // TODO: figure out this param type
  2005. * @returns {string} interpolated path
  2006. */
  2007. getPath(filename, data) {
  2008. data = data || {};
  2009. data.hash = data.hash || this.hash;
  2010. return this.mainTemplate.getAssetPath(filename, data);
  2011. }
  2012. /**
  2013. * @param {string} filename used to get asset path with hash
  2014. * @param {TODO=} data // TODO: figure out this param type
  2015. * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info
  2016. */
  2017. getPathWithInfo(filename, data) {
  2018. data = data || {};
  2019. data.hash = data.hash || this.hash;
  2020. return this.mainTemplate.getAssetPathWithInfo(filename, data);
  2021. }
  2022. /**
  2023. * This function allows you to run another instance of webpack inside of webpack however as
  2024. * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
  2025. * from parent (or top level compiler) and creates a child Compilation
  2026. *
  2027. * @param {string} name name of the child compiler
  2028. * @param {TODO} outputOptions // Need to convert config schema to types for this
  2029. * @param {Plugin[]} plugins webpack plugins that will be applied
  2030. * @returns {Compiler} creates a child Compiler instance
  2031. */
  2032. createChildCompiler(name, outputOptions, plugins) {
  2033. const idx = this.childrenCounters[name] || 0;
  2034. this.childrenCounters[name] = idx + 1;
  2035. return this.compiler.createChildCompiler(
  2036. this,
  2037. name,
  2038. idx,
  2039. outputOptions,
  2040. plugins
  2041. );
  2042. }
  2043. checkConstraints() {
  2044. /** @type {Set<number|string>} */
  2045. const usedIds = new Set();
  2046. const modules = this.modules;
  2047. for (let indexModule = 0; indexModule < modules.length; indexModule++) {
  2048. const moduleId = modules[indexModule].id;
  2049. if (moduleId === null) continue;
  2050. if (usedIds.has(moduleId)) {
  2051. throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
  2052. }
  2053. usedIds.add(moduleId);
  2054. }
  2055. const chunks = this.chunks;
  2056. for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  2057. const chunk = chunks[indexChunk];
  2058. if (chunks.indexOf(chunk) !== indexChunk) {
  2059. throw new Error(
  2060. `checkConstraints: duplicate chunk in compilation ${chunk.debugId}`
  2061. );
  2062. }
  2063. }
  2064. for (const chunkGroup of this.chunkGroups) {
  2065. chunkGroup.checkConstraints();
  2066. }
  2067. }
  2068. }
  2069. // TODO remove in webpack 5
  2070. Compilation.prototype.applyPlugins = util.deprecate(
  2071. /**
  2072. * @deprecated
  2073. * @param {string} name Name
  2074. * @param {any[]} args Other arguments
  2075. * @returns {void}
  2076. * @this {Compilation}
  2077. */
  2078. function(name, ...args) {
  2079. this.hooks[
  2080. name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())
  2081. ].call(...args);
  2082. },
  2083. "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead"
  2084. );
  2085. // TODO remove in webpack 5
  2086. Object.defineProperty(Compilation.prototype, "moduleTemplate", {
  2087. configurable: false,
  2088. get: util.deprecate(
  2089. /**
  2090. * @deprecated
  2091. * @this {Compilation}
  2092. * @returns {TODO} module template
  2093. */
  2094. function() {
  2095. return this.moduleTemplates.javascript;
  2096. },
  2097. "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead"
  2098. ),
  2099. set: util.deprecate(
  2100. /**
  2101. * @deprecated
  2102. * @param {ModuleTemplate} value Template value
  2103. * @this {Compilation}
  2104. * @returns {void}
  2105. */
  2106. function(value) {
  2107. this.moduleTemplates.javascript = value;
  2108. },
  2109. "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead."
  2110. )
  2111. });
  2112. module.exports = Compilation;