Compilation.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348
  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("async");
  7. const crypto = require("crypto");
  8. const Tapable = require("tapable");
  9. const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
  10. const ModuleNotFoundError = require("./ModuleNotFoundError");
  11. const ModuleDependencyWarning = require("./ModuleDependencyWarning");
  12. const ModuleDependencyError = require("./ModuleDependencyError");
  13. const Module = require("./Module");
  14. const Chunk = require("./Chunk");
  15. const Entrypoint = require("./Entrypoint");
  16. const MainTemplate = require("./MainTemplate");
  17. const ChunkTemplate = require("./ChunkTemplate");
  18. const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
  19. const ModuleTemplate = require("./ModuleTemplate");
  20. const Dependency = require("./Dependency");
  21. const ChunkRenderError = require("./ChunkRenderError");
  22. const CachedSource = require("webpack-sources").CachedSource;
  23. const Stats = require("./Stats");
  24. const Semaphore = require("./util/Semaphore");
  25. function byId(a, b) {
  26. if(a.id < b.id) return -1;
  27. if(a.id > b.id) return 1;
  28. return 0;
  29. }
  30. function iterationBlockVariable(variables, fn) {
  31. for(let indexVariable = 0; indexVariable < variables.length; indexVariable++) {
  32. let varDep = variables[indexVariable].dependencies;
  33. for(let indexVDep = 0; indexVDep < varDep.length; indexVDep++) {
  34. fn(varDep[indexVDep]);
  35. }
  36. }
  37. }
  38. function iterationOfArrayCallback(arr, fn) {
  39. for(let index = 0; index < arr.length; index++) {
  40. fn(arr[index]);
  41. }
  42. }
  43. class Compilation extends Tapable {
  44. constructor(compiler) {
  45. super();
  46. this.compiler = compiler;
  47. this.resolvers = compiler.resolvers;
  48. this.inputFileSystem = compiler.inputFileSystem;
  49. const options = this.options = compiler.options;
  50. this.outputOptions = options && options.output;
  51. this.bail = options && options.bail;
  52. this.profile = options && options.profile;
  53. this.performance = options && options.performance;
  54. this.mainTemplate = new MainTemplate(this.outputOptions);
  55. this.chunkTemplate = new ChunkTemplate(this.outputOptions);
  56. this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(this.outputOptions);
  57. this.moduleTemplate = new ModuleTemplate(this.outputOptions);
  58. this.semaphore = new Semaphore(options.parallelism || 100);
  59. this.entries = [];
  60. this.preparedChunks = [];
  61. this.entrypoints = {};
  62. this.chunks = [];
  63. this.namedChunks = {};
  64. this.modules = [];
  65. this._modules = {};
  66. this.cache = null;
  67. this.records = null;
  68. this.nextFreeModuleIndex = undefined;
  69. this.nextFreeModuleIndex2 = undefined;
  70. this.additionalChunkAssets = [];
  71. this.assets = {};
  72. this.errors = [];
  73. this.warnings = [];
  74. this.children = [];
  75. this.dependencyFactories = new Map();
  76. this.dependencyTemplates = new Map();
  77. this.dependencyTemplates.set("hash", "");
  78. this.childrenCounters = {};
  79. }
  80. getStats() {
  81. return new Stats(this);
  82. }
  83. templatesPlugin(name, fn) {
  84. this.mainTemplate.plugin(name, fn);
  85. this.chunkTemplate.plugin(name, fn);
  86. }
  87. addModule(module, cacheGroup) {
  88. const identifier = module.identifier();
  89. if(this._modules[identifier]) {
  90. return false;
  91. }
  92. const cacheName = (cacheGroup || "m") + identifier;
  93. if(this.cache && this.cache[cacheName]) {
  94. const cacheModule = this.cache[cacheName];
  95. let rebuild = true;
  96. if(!cacheModule.error && cacheModule.cacheable && this.fileTimestamps && this.contextTimestamps) {
  97. rebuild = cacheModule.needRebuild(this.fileTimestamps, this.contextTimestamps);
  98. }
  99. if(!rebuild) {
  100. cacheModule.disconnect();
  101. this._modules[identifier] = cacheModule;
  102. this.modules.push(cacheModule);
  103. cacheModule.errors.forEach(err => this.errors.push(err), this);
  104. cacheModule.warnings.forEach(err => this.warnings.push(err), this);
  105. return cacheModule;
  106. }
  107. }
  108. module.unbuild();
  109. this._modules[identifier] = module;
  110. if(this.cache) {
  111. this.cache[cacheName] = module;
  112. }
  113. this.modules.push(module);
  114. return true;
  115. }
  116. getModule(module) {
  117. const identifier = module.identifier();
  118. return this._modules[identifier];
  119. }
  120. findModule(identifier) {
  121. return this._modules[identifier];
  122. }
  123. buildModule(module, optional, origin, dependencies, thisCallback) {
  124. this.applyPlugins1("build-module", module);
  125. if(module.building) return module.building.push(thisCallback);
  126. const building = module.building = [thisCallback];
  127. function callback(err) {
  128. module.building = undefined;
  129. building.forEach(cb => cb(err));
  130. }
  131. module.build(this.options, this, this.resolvers.normal, this.inputFileSystem, (error) => {
  132. const errors = module.errors;
  133. for(let indexError = 0; indexError < errors.length; indexError++) {
  134. const err = errors[indexError];
  135. err.origin = origin;
  136. err.dependencies = dependencies;
  137. if(optional)
  138. this.warnings.push(err);
  139. else
  140. this.errors.push(err);
  141. }
  142. const warnings = module.warnings;
  143. for(let indexWarning = 0; indexWarning < warnings.length; indexWarning++) {
  144. const war = warnings[indexWarning];
  145. war.origin = origin;
  146. war.dependencies = dependencies;
  147. this.warnings.push(war);
  148. }
  149. module.dependencies.sort(Dependency.compare);
  150. if(error) {
  151. this.applyPlugins2("failed-module", module, error);
  152. return callback(error);
  153. }
  154. this.applyPlugins1("succeed-module", module);
  155. return callback();
  156. });
  157. }
  158. processModuleDependencies(module, callback) {
  159. const dependencies = [];
  160. function addDependency(dep) {
  161. for(let i = 0; i < dependencies.length; i++) {
  162. if(dep.isEqualResource(dependencies[i][0])) {
  163. return dependencies[i].push(dep);
  164. }
  165. }
  166. dependencies.push([dep]);
  167. }
  168. function addDependenciesBlock(block) {
  169. if(block.dependencies) {
  170. iterationOfArrayCallback(block.dependencies, addDependency);
  171. }
  172. if(block.blocks) {
  173. iterationOfArrayCallback(block.blocks, addDependenciesBlock);
  174. }
  175. if(block.variables) {
  176. iterationBlockVariable(block.variables, addDependency);
  177. }
  178. }
  179. addDependenciesBlock(module);
  180. this.addModuleDependencies(module, dependencies, this.bail, null, true, callback);
  181. }
  182. addModuleDependencies(module, dependencies, bail, cacheGroup, recursive, callback) {
  183. let _this = this;
  184. const start = _this.profile && Date.now();
  185. const factories = [];
  186. for(let i = 0; i < dependencies.length; i++) {
  187. const factory = _this.dependencyFactories.get(dependencies[i][0].constructor);
  188. if(!factory) {
  189. return callback(new Error(`No module factory available for dependency type: ${dependencies[i][0].constructor.name}`));
  190. }
  191. factories[i] = [factory, dependencies[i]];
  192. }
  193. asyncLib.forEach(factories, function iteratorFactory(item, callback) {
  194. const dependencies = item[1];
  195. const errorAndCallback = function errorAndCallback(err) {
  196. err.origin = module;
  197. _this.errors.push(err);
  198. if(bail) {
  199. callback(err);
  200. } else {
  201. callback();
  202. }
  203. };
  204. const warningAndCallback = function warningAndCallback(err) {
  205. err.origin = module;
  206. _this.warnings.push(err);
  207. callback();
  208. };
  209. _this.semaphore.acquire(() => {
  210. const factory = item[0];
  211. factory.create({
  212. contextInfo: {
  213. issuer: module.nameForCondition && module.nameForCondition(),
  214. compiler: _this.compiler.name
  215. },
  216. context: module.context,
  217. dependencies: dependencies
  218. }, function factoryCallback(err, dependentModule) {
  219. let afterFactory;
  220. function isOptional() {
  221. return dependencies.filter(d => !d.optional).length === 0;
  222. }
  223. function errorOrWarningAndCallback(err) {
  224. if(isOptional()) {
  225. return warningAndCallback(err);
  226. } else {
  227. return errorAndCallback(err);
  228. }
  229. }
  230. function iterationDependencies(depend) {
  231. for(let index = 0; index < depend.length; index++) {
  232. const dep = depend[index];
  233. dep.module = dependentModule;
  234. dependentModule.addReason(module, dep);
  235. }
  236. }
  237. if(err) {
  238. _this.semaphore.release();
  239. return errorOrWarningAndCallback(new ModuleNotFoundError(module, err, dependencies));
  240. }
  241. if(!dependentModule) {
  242. _this.semaphore.release();
  243. return process.nextTick(callback);
  244. }
  245. if(_this.profile) {
  246. if(!dependentModule.profile) {
  247. dependentModule.profile = {};
  248. }
  249. afterFactory = Date.now();
  250. dependentModule.profile.factory = afterFactory - start;
  251. }
  252. dependentModule.issuer = module;
  253. const newModule = _this.addModule(dependentModule, cacheGroup);
  254. if(!newModule) { // from cache
  255. dependentModule = _this.getModule(dependentModule);
  256. if(dependentModule.optional) {
  257. dependentModule.optional = isOptional();
  258. }
  259. iterationDependencies(dependencies);
  260. if(_this.profile) {
  261. if(!module.profile) {
  262. module.profile = {};
  263. }
  264. const time = Date.now() - start;
  265. if(!module.profile.dependencies || time > module.profile.dependencies) {
  266. module.profile.dependencies = time;
  267. }
  268. }
  269. _this.semaphore.release();
  270. return process.nextTick(callback);
  271. }
  272. if(newModule instanceof Module) {
  273. if(_this.profile) {
  274. newModule.profile = dependentModule.profile;
  275. }
  276. newModule.optional = isOptional();
  277. newModule.issuer = dependentModule.issuer;
  278. dependentModule = newModule;
  279. iterationDependencies(dependencies);
  280. if(_this.profile) {
  281. const afterBuilding = Date.now();
  282. module.profile.building = afterBuilding - afterFactory;
  283. }
  284. _this.semaphore.release();
  285. if(recursive) {
  286. return process.nextTick(_this.processModuleDependencies.bind(_this, dependentModule, callback));
  287. } else {
  288. return process.nextTick(callback);
  289. }
  290. }
  291. dependentModule.optional = isOptional();
  292. iterationDependencies(dependencies);
  293. _this.buildModule(dependentModule, isOptional(), module, dependencies, err => {
  294. if(err) {
  295. _this.semaphore.release();
  296. return errorOrWarningAndCallback(err);
  297. }
  298. if(_this.profile) {
  299. const afterBuilding = Date.now();
  300. dependentModule.profile.building = afterBuilding - afterFactory;
  301. }
  302. _this.semaphore.release();
  303. if(recursive) {
  304. _this.processModuleDependencies(dependentModule, callback);
  305. } else {
  306. return callback();
  307. }
  308. });
  309. });
  310. });
  311. }, function finalCallbackAddModuleDependencies(err) {
  312. // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
  313. // errors are created inside closures that keep a reference to the Compilation, so errors are
  314. // leaking the Compilation object. Setting _this to null workarounds the following issue in V8.
  315. // https://bugs.chromium.org/p/chromium/issues/detail?id=612191
  316. _this = null;
  317. if(err) {
  318. return callback(err);
  319. }
  320. return process.nextTick(callback);
  321. });
  322. }
  323. _addModuleChain(context, dependency, onModule, callback) {
  324. const start = this.profile && Date.now();
  325. const errorAndCallback = this.bail ? (err) => {
  326. callback(err);
  327. } : (err) => {
  328. err.dependencies = [dependency];
  329. this.errors.push(err);
  330. callback();
  331. };
  332. if(typeof dependency !== "object" || dependency === null || !dependency.constructor) {
  333. throw new Error("Parameter 'dependency' must be a Dependency");
  334. }
  335. const moduleFactory = this.dependencyFactories.get(dependency.constructor);
  336. if(!moduleFactory) {
  337. throw new Error(`No dependency factory available for this dependency type: ${dependency.constructor.name}`);
  338. }
  339. this.semaphore.acquire(() => {
  340. moduleFactory.create({
  341. contextInfo: {
  342. issuer: "",
  343. compiler: this.compiler.name
  344. },
  345. context: context,
  346. dependencies: [dependency]
  347. }, (err, module) => {
  348. if(err) {
  349. this.semaphore.release();
  350. return errorAndCallback(new EntryModuleNotFoundError(err));
  351. }
  352. let afterFactory;
  353. if(this.profile) {
  354. if(!module.profile) {
  355. module.profile = {};
  356. }
  357. afterFactory = Date.now();
  358. module.profile.factory = afterFactory - start;
  359. }
  360. const result = this.addModule(module);
  361. if(!result) {
  362. module = this.getModule(module);
  363. onModule(module);
  364. if(this.profile) {
  365. const afterBuilding = Date.now();
  366. module.profile.building = afterBuilding - afterFactory;
  367. }
  368. this.semaphore.release();
  369. return callback(null, module);
  370. }
  371. if(result instanceof Module) {
  372. if(this.profile) {
  373. result.profile = module.profile;
  374. }
  375. module = result;
  376. onModule(module);
  377. moduleReady.call(this);
  378. return;
  379. }
  380. onModule(module);
  381. this.buildModule(module, false, null, null, (err) => {
  382. if(err) {
  383. this.semaphore.release();
  384. return errorAndCallback(err);
  385. }
  386. if(this.profile) {
  387. const afterBuilding = Date.now();
  388. module.profile.building = afterBuilding - afterFactory;
  389. }
  390. moduleReady.call(this);
  391. });
  392. function moduleReady() {
  393. this.semaphore.release();
  394. this.processModuleDependencies(module, err => {
  395. if(err) {
  396. return callback(err);
  397. }
  398. return callback(null, module);
  399. });
  400. }
  401. });
  402. });
  403. }
  404. addEntry(context, entry, name, callback) {
  405. const slot = {
  406. name: name,
  407. module: null
  408. };
  409. this.preparedChunks.push(slot);
  410. this._addModuleChain(context, entry, (module) => {
  411. entry.module = module;
  412. this.entries.push(module);
  413. module.issuer = null;
  414. }, (err, module) => {
  415. if(err) {
  416. return callback(err);
  417. }
  418. if(module) {
  419. slot.module = module;
  420. } else {
  421. const idx = this.preparedChunks.indexOf(slot);
  422. this.preparedChunks.splice(idx, 1);
  423. }
  424. return callback(null, module);
  425. });
  426. }
  427. prefetch(context, dependency, callback) {
  428. this._addModuleChain(context, dependency, module => {
  429. module.prefetched = true;
  430. module.issuer = null;
  431. }, callback);
  432. }
  433. rebuildModule(module, thisCallback) {
  434. if(module.variables.length || module.blocks.length)
  435. throw new Error("Cannot rebuild a complex module with variables or blocks");
  436. if(module.rebuilding) {
  437. return module.rebuilding.push(thisCallback);
  438. }
  439. const rebuilding = module.rebuilding = [thisCallback];
  440. function callback(err) {
  441. module.rebuilding = undefined;
  442. rebuilding.forEach(cb => cb(err));
  443. }
  444. const deps = module.dependencies.slice();
  445. this.buildModule(module, false, module, null, (err) => {
  446. if(err) return callback(err);
  447. this.processModuleDependencies(module, (err) => {
  448. if(err) return callback(err);
  449. deps.forEach(d => {
  450. if(d.module && d.module.removeReason(module, d)) {
  451. module.forEachChunk(chunk => {
  452. if(!d.module.hasReasonForChunk(chunk)) {
  453. if(d.module.removeChunk(chunk)) {
  454. this.removeChunkFromDependencies(d.module, chunk);
  455. }
  456. }
  457. });
  458. }
  459. });
  460. callback();
  461. });
  462. });
  463. }
  464. finish() {
  465. const modules = this.modules;
  466. this.applyPlugins1("finish-modules", modules);
  467. for(let index = 0; index < modules.length; index++) {
  468. const module = modules[index];
  469. this.reportDependencyErrorsAndWarnings(module, [module]);
  470. }
  471. }
  472. unseal() {
  473. this.applyPlugins0("unseal");
  474. this.chunks.length = 0;
  475. this.namedChunks = {};
  476. this.additionalChunkAssets.length = 0;
  477. this.assets = {};
  478. this.modules.forEach(module => module.unseal());
  479. }
  480. seal(callback) {
  481. const self = this;
  482. self.applyPlugins0("seal");
  483. self.nextFreeModuleIndex = 0;
  484. self.nextFreeModuleIndex2 = 0;
  485. self.preparedChunks.forEach(preparedChunk => {
  486. const module = preparedChunk.module;
  487. const chunk = self.addChunk(preparedChunk.name, module);
  488. const entrypoint = self.entrypoints[chunk.name] = new Entrypoint(chunk.name);
  489. entrypoint.unshiftChunk(chunk);
  490. chunk.addModule(module);
  491. module.addChunk(chunk);
  492. chunk.entryModule = module;
  493. self.assignIndex(module);
  494. self.assignDepth(module);
  495. self.processDependenciesBlockForChunk(module, chunk);
  496. });
  497. self.sortModules(self.modules);
  498. self.applyPlugins0("optimize");
  499. while(self.applyPluginsBailResult1("optimize-modules-basic", self.modules) ||
  500. self.applyPluginsBailResult1("optimize-modules", self.modules) ||
  501. self.applyPluginsBailResult1("optimize-modules-advanced", self.modules)) { /* empty */ }
  502. self.applyPlugins1("after-optimize-modules", self.modules);
  503. while(self.applyPluginsBailResult1("optimize-chunks-basic", self.chunks) ||
  504. self.applyPluginsBailResult1("optimize-chunks", self.chunks) ||
  505. self.applyPluginsBailResult1("optimize-chunks-advanced", self.chunks)) { /* empty */ }
  506. self.applyPlugins1("after-optimize-chunks", self.chunks);
  507. self.applyPluginsAsyncSeries("optimize-tree", self.chunks, self.modules, function sealPart2(err) {
  508. if(err) {
  509. return callback(err);
  510. }
  511. self.applyPlugins2("after-optimize-tree", self.chunks, self.modules);
  512. while(self.applyPluginsBailResult("optimize-chunk-modules-basic", self.chunks, self.modules) ||
  513. self.applyPluginsBailResult("optimize-chunk-modules", self.chunks, self.modules) ||
  514. self.applyPluginsBailResult("optimize-chunk-modules-advanced", self.chunks, self.modules)) { /* empty */ }
  515. self.applyPlugins2("after-optimize-chunk-modules", self.chunks, self.modules);
  516. const shouldRecord = self.applyPluginsBailResult("should-record") !== false;
  517. self.applyPlugins2("revive-modules", self.modules, self.records);
  518. self.applyPlugins1("optimize-module-order", self.modules);
  519. self.applyPlugins1("advanced-optimize-module-order", self.modules);
  520. self.applyPlugins1("before-module-ids", self.modules);
  521. self.applyPlugins1("module-ids", self.modules);
  522. self.applyModuleIds();
  523. self.applyPlugins1("optimize-module-ids", self.modules);
  524. self.applyPlugins1("after-optimize-module-ids", self.modules);
  525. self.sortItemsWithModuleIds();
  526. self.applyPlugins2("revive-chunks", self.chunks, self.records);
  527. self.applyPlugins1("optimize-chunk-order", self.chunks);
  528. self.applyPlugins1("before-chunk-ids", self.chunks);
  529. self.applyChunkIds();
  530. self.applyPlugins1("optimize-chunk-ids", self.chunks);
  531. self.applyPlugins1("after-optimize-chunk-ids", self.chunks);
  532. self.sortItemsWithChunkIds();
  533. if(shouldRecord)
  534. self.applyPlugins2("record-modules", self.modules, self.records);
  535. if(shouldRecord)
  536. self.applyPlugins2("record-chunks", self.chunks, self.records);
  537. self.applyPlugins0("before-hash");
  538. self.createHash();
  539. self.applyPlugins0("after-hash");
  540. if(shouldRecord)
  541. self.applyPlugins1("record-hash", self.records);
  542. self.applyPlugins0("before-module-assets");
  543. self.createModuleAssets();
  544. if(self.applyPluginsBailResult("should-generate-chunk-assets") !== false) {
  545. self.applyPlugins0("before-chunk-assets");
  546. self.createChunkAssets();
  547. }
  548. self.applyPlugins1("additional-chunk-assets", self.chunks);
  549. self.summarizeDependencies();
  550. if(shouldRecord)
  551. self.applyPlugins2("record", self, self.records);
  552. self.applyPluginsAsync("additional-assets", err => {
  553. if(err) {
  554. return callback(err);
  555. }
  556. self.applyPluginsAsync("optimize-chunk-assets", self.chunks, err => {
  557. if(err) {
  558. return callback(err);
  559. }
  560. self.applyPlugins1("after-optimize-chunk-assets", self.chunks);
  561. self.applyPluginsAsync("optimize-assets", self.assets, err => {
  562. if(err) {
  563. return callback(err);
  564. }
  565. self.applyPlugins1("after-optimize-assets", self.assets);
  566. if(self.applyPluginsBailResult("need-additional-seal")) {
  567. self.unseal();
  568. return self.seal(callback);
  569. }
  570. return self.applyPluginsAsync("after-seal", callback);
  571. });
  572. });
  573. });
  574. });
  575. }
  576. sortModules(modules) {
  577. modules.sort((a, b) => {
  578. if(a.index < b.index) return -1;
  579. if(a.index > b.index) return 1;
  580. return 0;
  581. });
  582. }
  583. reportDependencyErrorsAndWarnings(module, blocks) {
  584. for(let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
  585. const block = blocks[indexBlock];
  586. const dependencies = block.dependencies;
  587. for(let indexDep = 0; indexDep < dependencies.length; indexDep++) {
  588. const d = dependencies[indexDep];
  589. const warnings = d.getWarnings();
  590. if(warnings) {
  591. for(let indexWar = 0; indexWar < warnings.length; indexWar++) {
  592. const w = warnings[indexWar];
  593. const warning = new ModuleDependencyWarning(module, w, d.loc);
  594. this.warnings.push(warning);
  595. }
  596. }
  597. const errors = d.getErrors();
  598. if(errors) {
  599. for(let indexErr = 0; indexErr < errors.length; indexErr++) {
  600. const e = errors[indexErr];
  601. const error = new ModuleDependencyError(module, e, d.loc);
  602. this.errors.push(error);
  603. }
  604. }
  605. }
  606. this.reportDependencyErrorsAndWarnings(module, block.blocks);
  607. }
  608. }
  609. addChunk(name, module, loc) {
  610. if(name) {
  611. if(Object.prototype.hasOwnProperty.call(this.namedChunks, name)) {
  612. const chunk = this.namedChunks[name];
  613. if(module) {
  614. chunk.addOrigin(module, loc);
  615. }
  616. return chunk;
  617. }
  618. }
  619. const chunk = new Chunk(name, module, loc);
  620. this.chunks.push(chunk);
  621. if(name) {
  622. this.namedChunks[name] = chunk;
  623. }
  624. return chunk;
  625. }
  626. assignIndex(module) {
  627. const _this = this;
  628. const queue = [() => {
  629. assignIndexToModule(module);
  630. }];
  631. const iteratorAllDependencies = d => {
  632. queue.push(() => assignIndexToDependency(d));
  633. };
  634. function assignIndexToModule(module) {
  635. // enter module
  636. if(typeof module.index !== "number") {
  637. module.index = _this.nextFreeModuleIndex++;
  638. // leave module
  639. queue.push(() => module.index2 = _this.nextFreeModuleIndex2++);
  640. // enter it as block
  641. assignIndexToDependencyBlock(module);
  642. }
  643. }
  644. function assignIndexToDependency(dependency) {
  645. if(dependency.module) {
  646. queue.push(() => assignIndexToModule(dependency.module));
  647. }
  648. }
  649. function assignIndexToDependencyBlock(block) {
  650. let allDependencies = [];
  651. function iteratorDependency(d) {
  652. allDependencies.push(d);
  653. }
  654. function iteratorBlock(b) {
  655. queue.push(() => assignIndexToDependencyBlock(b));
  656. }
  657. if(block.variables) {
  658. iterationBlockVariable(block.variables, iteratorDependency);
  659. }
  660. if(block.dependencies) {
  661. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  662. }
  663. if(block.blocks) {
  664. const blocks = block.blocks;
  665. let indexBlock = blocks.length;
  666. while(indexBlock--) {
  667. iteratorBlock(blocks[indexBlock]);
  668. }
  669. }
  670. let indexAll = allDependencies.length;
  671. while(indexAll--) {
  672. iteratorAllDependencies(allDependencies[indexAll]);
  673. }
  674. }
  675. while(queue.length) {
  676. queue.pop()();
  677. }
  678. }
  679. assignDepth(module) {
  680. function assignDepthToModule(module, depth) {
  681. // enter module
  682. if(typeof module.depth === "number" && module.depth <= depth) return;
  683. module.depth = depth;
  684. // enter it as block
  685. assignDepthToDependencyBlock(module, depth + 1);
  686. }
  687. function assignDepthToDependency(dependency, depth) {
  688. if(dependency.module) {
  689. queue.push(() => assignDepthToModule(dependency.module, depth));
  690. }
  691. }
  692. function assignDepthToDependencyBlock(block, depth) {
  693. function iteratorDependency(d) {
  694. assignDepthToDependency(d, depth);
  695. }
  696. function iteratorBlock(b) {
  697. assignDepthToDependencyBlock(b, depth);
  698. }
  699. if(block.variables) {
  700. iterationBlockVariable(block.variables, iteratorDependency);
  701. }
  702. if(block.dependencies) {
  703. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  704. }
  705. if(block.blocks) {
  706. iterationOfArrayCallback(block.blocks, iteratorBlock);
  707. }
  708. }
  709. const queue = [() => {
  710. assignDepthToModule(module, 0);
  711. }];
  712. while(queue.length) {
  713. queue.pop()();
  714. }
  715. }
  716. processDependenciesBlockForChunk(module, chunk) {
  717. let block = module;
  718. const initialChunk = chunk;
  719. const chunkDependencies = new Map(); // Map<Chunk, Array<{Module, Chunk}>>
  720. const iteratorBlock = b => {
  721. let c;
  722. if(!b.chunks) {
  723. c = this.addChunk(b.chunkName, b.module, b.loc);
  724. b.chunks = [c];
  725. c.addBlock(b);
  726. } else {
  727. c = b.chunks[0];
  728. }
  729. let deps = chunkDependencies.get(chunk);
  730. if(!deps) chunkDependencies.set(chunk, deps = []);
  731. deps.push({
  732. chunk: c,
  733. module
  734. });
  735. queue.push({
  736. block: b,
  737. module: null,
  738. chunk: c
  739. });
  740. };
  741. const iteratorDependency = d => {
  742. if(!d.module) {
  743. return;
  744. }
  745. if(d.weak) {
  746. return;
  747. }
  748. if(chunk.addModule(d.module)) {
  749. d.module.addChunk(chunk);
  750. queue.push({
  751. block: d.module,
  752. module: d.module,
  753. chunk
  754. });
  755. }
  756. };
  757. const queue = [{
  758. block,
  759. module,
  760. chunk
  761. }];
  762. while(queue.length) {
  763. const queueItem = queue.pop();
  764. block = queueItem.block;
  765. module = queueItem.module;
  766. chunk = queueItem.chunk;
  767. if(block.variables) {
  768. iterationBlockVariable(block.variables, iteratorDependency);
  769. }
  770. if(block.dependencies) {
  771. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  772. }
  773. if(block.blocks) {
  774. iterationOfArrayCallback(block.blocks, iteratorBlock);
  775. }
  776. }
  777. chunk = initialChunk;
  778. let chunks = new Set();
  779. const queue2 = [{
  780. chunk,
  781. chunks
  782. }];
  783. const filterFn = dep => {
  784. if(chunks.has(dep.chunk)) return false;
  785. for(const chunk of chunks) {
  786. if(chunk.containsModule(dep.module))
  787. return false;
  788. }
  789. return true;
  790. };
  791. while(queue2.length) {
  792. const queueItem = queue2.pop();
  793. chunk = queueItem.chunk;
  794. chunks = queueItem.chunks;
  795. const deps = chunkDependencies.get(chunk);
  796. if(!deps) continue;
  797. const depsFiltered = deps.filter(filterFn);
  798. for(let i = 0; i < depsFiltered.length; i++) {
  799. const dep = depsFiltered[i];
  800. const depChunk = dep.chunk;
  801. chunk.addChunk(depChunk);
  802. depChunk.addParent(chunk);
  803. const newChunks = depsFiltered.length > 1 ? new Set(chunks) : chunks;
  804. newChunks.add(chunk);
  805. queue2.push({
  806. chunk: depChunk,
  807. chunks: newChunks
  808. });
  809. }
  810. }
  811. }
  812. removeChunkFromDependencies(block, chunk) {
  813. const iteratorDependency = d => {
  814. if(!d.module) {
  815. return;
  816. }
  817. if(!d.module.hasReasonForChunk(chunk)) {
  818. if(d.module.removeChunk(chunk)) {
  819. this.removeChunkFromDependencies(d.module, chunk);
  820. }
  821. }
  822. };
  823. const blocks = block.blocks;
  824. for(let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
  825. const chunks = blocks[indexBlock].chunks;
  826. for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  827. const blockChunk = chunks[indexChunk];
  828. chunk.removeChunk(blockChunk);
  829. blockChunk.removeParent(chunk);
  830. this.removeChunkFromDependencies(chunks, blockChunk);
  831. }
  832. }
  833. if(block.dependencies) {
  834. iterationOfArrayCallback(block.dependencies, iteratorDependency);
  835. }
  836. if(block.variables) {
  837. iterationBlockVariable(block.variables, iteratorDependency);
  838. }
  839. }
  840. applyModuleIds() {
  841. let unusedIds = [];
  842. let nextFreeModuleId = 0;
  843. let usedIds = [];
  844. // TODO consider Map when performance has improved https://gist.github.com/sokra/234c077e1299b7369461f1708519c392
  845. const usedIdMap = Object.create(null);
  846. if(this.usedModuleIds) {
  847. Object.keys(this.usedModuleIds).forEach(key => {
  848. const id = this.usedModuleIds[key];
  849. if(!usedIdMap[id]) {
  850. usedIds.push(id);
  851. usedIdMap[id] = true;
  852. }
  853. });
  854. }
  855. const modules1 = this.modules;
  856. for(let indexModule1 = 0; indexModule1 < modules1.length; indexModule1++) {
  857. const module1 = modules1[indexModule1];
  858. if(module1.id && !usedIdMap[module1.id]) {
  859. usedIds.push(module1.id);
  860. usedIdMap[module1.id] = true;
  861. }
  862. }
  863. if(usedIds.length > 0) {
  864. let usedIdMax = -1;
  865. for(let index = 0; index < usedIds.length; index++) {
  866. const usedIdKey = usedIds[index];
  867. if(typeof usedIdKey !== "number") {
  868. continue;
  869. }
  870. usedIdMax = Math.max(usedIdMax, usedIdKey);
  871. }
  872. let lengthFreeModules = nextFreeModuleId = usedIdMax + 1;
  873. while(lengthFreeModules--) {
  874. if(!usedIdMap[lengthFreeModules]) {
  875. unusedIds.push(lengthFreeModules);
  876. }
  877. }
  878. }
  879. const modules2 = this.modules;
  880. for(let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
  881. const module2 = modules2[indexModule2];
  882. if(module2.id === null) {
  883. if(unusedIds.length > 0)
  884. module2.id = unusedIds.pop();
  885. else
  886. module2.id = nextFreeModuleId++;
  887. }
  888. }
  889. }
  890. applyChunkIds() {
  891. const unusedIds = [];
  892. let nextFreeChunkId = 0;
  893. function getNextFreeChunkId(usedChunkIds) {
  894. const keyChunks = Object.keys(usedChunkIds);
  895. let result = -1;
  896. for(let index = 0; index < keyChunks.length; index++) {
  897. const usedIdKey = keyChunks[index];
  898. const usedIdValue = usedChunkIds[usedIdKey];
  899. if(typeof usedIdValue !== "number") {
  900. continue;
  901. }
  902. result = Math.max(result, usedIdValue);
  903. }
  904. return result;
  905. }
  906. if(this.usedChunkIds) {
  907. nextFreeChunkId = getNextFreeChunkId(this.usedChunkIds) + 1;
  908. let index = nextFreeChunkId;
  909. while(index--) {
  910. if(this.usedChunkIds[index] !== index) {
  911. unusedIds.push(index);
  912. }
  913. }
  914. }
  915. const chunks = this.chunks;
  916. for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  917. const chunk = chunks[indexChunk];
  918. if(chunk.id === null) {
  919. if(unusedIds.length > 0)
  920. chunk.id = unusedIds.pop();
  921. else
  922. chunk.id = nextFreeChunkId++;
  923. }
  924. if(!chunk.ids) {
  925. chunk.ids = [chunk.id];
  926. }
  927. }
  928. }
  929. sortItemsWithModuleIds() {
  930. this.modules.sort(byId);
  931. const modules = this.modules;
  932. for(let indexModule = 0; indexModule < modules.length; indexModule++) {
  933. modules[indexModule].sortItems(false);
  934. }
  935. const chunks = this.chunks;
  936. for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  937. chunks[indexChunk].sortItems();
  938. }
  939. }
  940. sortItemsWithChunkIds() {
  941. this.chunks.sort(byId);
  942. const modules = this.modules;
  943. for(let indexModule = 0; indexModule < modules.length; indexModule++) {
  944. modules[indexModule].sortItems(true);
  945. }
  946. const chunks = this.chunks;
  947. for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  948. chunks[indexChunk].sortItems();
  949. }
  950. const byMessage = (a, b) => {
  951. const ma = `${a.message}`;
  952. const mb = `${b.message}`;
  953. if(ma < mb) return -1;
  954. if(mb < ma) return 1;
  955. return 0;
  956. };
  957. this.errors.sort(byMessage);
  958. this.warnings.sort(byMessage);
  959. }
  960. summarizeDependencies() {
  961. function filterDups(array) {
  962. const newArray = [];
  963. for(let i = 0; i < array.length; i++) {
  964. if(i === 0 || array[i - 1] !== array[i])
  965. newArray.push(array[i]);
  966. }
  967. return newArray;
  968. }
  969. this.fileDependencies = (this.compilationDependencies || []).slice();
  970. this.contextDependencies = [];
  971. this.missingDependencies = [];
  972. const children = this.children;
  973. for(let indexChildren = 0; indexChildren < children.length; indexChildren++) {
  974. const child = children[indexChildren];
  975. this.fileDependencies = this.fileDependencies.concat(child.fileDependencies);
  976. this.contextDependencies = this.contextDependencies.concat(child.contextDependencies);
  977. this.missingDependencies = this.missingDependencies.concat(child.missingDependencies);
  978. }
  979. const modules = this.modules;
  980. for(let indexModule = 0; indexModule < modules.length; indexModule++) {
  981. const module = modules[indexModule];
  982. if(module.fileDependencies) {
  983. const fileDependencies = module.fileDependencies;
  984. for(let indexFileDep = 0; indexFileDep < fileDependencies.length; indexFileDep++) {
  985. this.fileDependencies.push(fileDependencies[indexFileDep]);
  986. }
  987. }
  988. if(module.contextDependencies) {
  989. const contextDependencies = module.contextDependencies;
  990. for(let indexContextDep = 0; indexContextDep < contextDependencies.length; indexContextDep++) {
  991. this.contextDependencies.push(contextDependencies[indexContextDep]);
  992. }
  993. }
  994. }
  995. this.errors.forEach(error => {
  996. if(Array.isArray(error.missing)) {
  997. error.missing.forEach(item => this.missingDependencies.push(item));
  998. }
  999. });
  1000. this.fileDependencies.sort();
  1001. this.fileDependencies = filterDups(this.fileDependencies);
  1002. this.contextDependencies.sort();
  1003. this.contextDependencies = filterDups(this.contextDependencies);
  1004. this.missingDependencies.sort();
  1005. this.missingDependencies = filterDups(this.missingDependencies);
  1006. }
  1007. createHash() {
  1008. const outputOptions = this.outputOptions;
  1009. const hashFunction = outputOptions.hashFunction;
  1010. const hashDigest = outputOptions.hashDigest;
  1011. const hashDigestLength = outputOptions.hashDigestLength;
  1012. const hash = crypto.createHash(hashFunction);
  1013. if(outputOptions.hashSalt)
  1014. hash.update(outputOptions.hashSalt);
  1015. this.mainTemplate.updateHash(hash);
  1016. this.chunkTemplate.updateHash(hash);
  1017. this.moduleTemplate.updateHash(hash);
  1018. this.children.forEach(function(child) {
  1019. hash.update(child.hash);
  1020. });
  1021. this.warnings.forEach(function(warning) {
  1022. hash.update(`${warning.message}`);
  1023. });
  1024. this.errors.forEach(function(error) {
  1025. hash.update(`${error.message}`);
  1026. });
  1027. // clone needed as sort below is inplace mutation
  1028. const chunks = this.chunks.slice();
  1029. /**
  1030. * sort here will bring all "falsy" values to the beginning
  1031. * this is needed as the "hasRuntime()" chunks are dependent on the
  1032. * hashes of the non-runtime chunks.
  1033. */
  1034. chunks.sort((a, b) => {
  1035. const aEntry = a.hasRuntime();
  1036. const bEntry = b.hasRuntime();
  1037. if(aEntry && !bEntry) return 1;
  1038. if(!aEntry && bEntry) return -1;
  1039. return 0;
  1040. });
  1041. for(let i = 0; i < chunks.length; i++) {
  1042. const chunk = chunks[i];
  1043. const chunkHash = crypto.createHash(hashFunction);
  1044. if(outputOptions.hashSalt)
  1045. chunkHash.update(outputOptions.hashSalt);
  1046. chunk.updateHash(chunkHash);
  1047. if(chunk.hasRuntime()) {
  1048. this.mainTemplate.updateHashForChunk(chunkHash, chunk);
  1049. } else {
  1050. this.chunkTemplate.updateHashForChunk(chunkHash, chunk);
  1051. }
  1052. this.applyPlugins2("chunk-hash", chunk, chunkHash);
  1053. chunk.hash = chunkHash.digest(hashDigest);
  1054. hash.update(chunk.hash);
  1055. chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
  1056. }
  1057. this.fullHash = hash.digest(hashDigest);
  1058. this.hash = this.fullHash.substr(0, hashDigestLength);
  1059. }
  1060. modifyHash(update) {
  1061. const outputOptions = this.outputOptions;
  1062. const hashFunction = outputOptions.hashFunction;
  1063. const hashDigest = outputOptions.hashDigest;
  1064. const hashDigestLength = outputOptions.hashDigestLength;
  1065. const hash = crypto.createHash(hashFunction);
  1066. hash.update(this.fullHash);
  1067. hash.update(update);
  1068. this.fullHash = hash.digest(hashDigest);
  1069. this.hash = this.fullHash.substr(0, hashDigestLength);
  1070. }
  1071. createModuleAssets() {
  1072. for(let i = 0; i < this.modules.length; i++) {
  1073. const module = this.modules[i];
  1074. if(module.assets) {
  1075. Object.keys(module.assets).forEach((assetName) => {
  1076. const fileName = this.getPath(assetName);
  1077. this.assets[fileName] = module.assets[assetName];
  1078. this.applyPlugins2("module-asset", module, fileName);
  1079. });
  1080. }
  1081. }
  1082. }
  1083. createChunkAssets() {
  1084. const outputOptions = this.outputOptions;
  1085. const filename = outputOptions.filename;
  1086. const chunkFilename = outputOptions.chunkFilename;
  1087. for(let i = 0; i < this.chunks.length; i++) {
  1088. const chunk = this.chunks[i];
  1089. chunk.files = [];
  1090. const chunkHash = chunk.hash;
  1091. let source;
  1092. let file;
  1093. const filenameTemplate = chunk.filenameTemplate ? chunk.filenameTemplate :
  1094. chunk.isInitial() ? filename :
  1095. chunkFilename;
  1096. try {
  1097. const useChunkHash = !chunk.hasRuntime() || (this.mainTemplate.useChunkHash && this.mainTemplate.useChunkHash(chunk));
  1098. const usedHash = useChunkHash ? chunkHash : this.fullHash;
  1099. const cacheName = "c" + chunk.id;
  1100. if(this.cache && this.cache[cacheName] && this.cache[cacheName].hash === usedHash) {
  1101. source = this.cache[cacheName].source;
  1102. } else {
  1103. if(chunk.hasRuntime()) {
  1104. source = this.mainTemplate.render(this.hash, chunk, this.moduleTemplate, this.dependencyTemplates);
  1105. } else {
  1106. source = this.chunkTemplate.render(chunk, this.moduleTemplate, this.dependencyTemplates);
  1107. }
  1108. if(this.cache) {
  1109. this.cache[cacheName] = {
  1110. hash: usedHash,
  1111. source: source = (source instanceof CachedSource ? source : new CachedSource(source))
  1112. };
  1113. }
  1114. }
  1115. file = this.getPath(filenameTemplate, {
  1116. noChunkHash: !useChunkHash,
  1117. chunk
  1118. });
  1119. if(this.assets[file])
  1120. throw new Error(`Conflict: Multiple assets emit to the same filename ${file}`);
  1121. this.assets[file] = source;
  1122. chunk.files.push(file);
  1123. this.applyPlugins2("chunk-asset", chunk, file);
  1124. } catch(err) {
  1125. this.errors.push(new ChunkRenderError(chunk, file || filenameTemplate, err));
  1126. }
  1127. }
  1128. }
  1129. getPath(filename, data) {
  1130. data = data || {};
  1131. data.hash = data.hash || this.hash;
  1132. return this.mainTemplate.applyPluginsWaterfall("asset-path", filename, data);
  1133. }
  1134. createChildCompiler(name, outputOptions, plugins) {
  1135. var idx = (this.childrenCounters[name] || 0);
  1136. this.childrenCounters[name] = idx + 1;
  1137. return this.compiler.createChildCompiler(this, name, idx, outputOptions, plugins);
  1138. }
  1139. checkConstraints() {
  1140. const usedIds = {};
  1141. const modules = this.modules;
  1142. for(let indexModule = 0; indexModule < modules.length; indexModule++) {
  1143. const moduleId = modules[indexModule].id;
  1144. if(usedIds[moduleId])
  1145. throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
  1146. }
  1147. const chunks = this.chunks;
  1148. for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
  1149. const chunk = chunks[indexChunk];
  1150. if(chunks.indexOf(chunk) !== indexChunk)
  1151. throw new Error(`checkConstraints: duplicate chunk in compilation ${chunk.debugId}`);
  1152. chunk.checkConstraints();
  1153. }
  1154. }
  1155. }
  1156. module.exports = Compilation;