Compilation.js 35 KB

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