Compilation.js 62 KB

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