Compilation.js 71 KB

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