source: imaps-frontend/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 51.6 KB
RevLine 
[79a0317]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const eslintScope = require("eslint-scope");
9const { SyncWaterfallHook, SyncHook, SyncBailHook } = require("tapable");
10const vm = require("vm");
11const {
12 ConcatSource,
13 OriginalSource,
14 PrefixSource,
15 RawSource,
16 CachedSource,
17 ReplaceSource
18} = require("webpack-sources");
19const Compilation = require("../Compilation");
20const { tryRunOrWebpackError } = require("../HookWebpackError");
21const HotUpdateChunk = require("../HotUpdateChunk");
22const InitFragment = require("../InitFragment");
23const {
24 JAVASCRIPT_MODULE_TYPE_AUTO,
25 JAVASCRIPT_MODULE_TYPE_DYNAMIC,
26 JAVASCRIPT_MODULE_TYPE_ESM,
27 WEBPACK_MODULE_TYPE_RUNTIME
28} = require("../ModuleTypeConstants");
29const RuntimeGlobals = require("../RuntimeGlobals");
30const Template = require("../Template");
31const { last, someInIterable } = require("../util/IterableHelpers");
32const StringXor = require("../util/StringXor");
33const { compareModulesByIdentifier } = require("../util/comparators");
34const {
35 getPathInAst,
36 getAllReferences,
37 RESERVED_NAMES,
38 findNewName,
39 addScopeSymbols,
40 getUsedNamesInScopeInfo
41} = require("../util/concatenate");
42const createHash = require("../util/createHash");
43const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
44const { intersectRuntime } = require("../util/runtime");
45const JavascriptGenerator = require("./JavascriptGenerator");
46const JavascriptParser = require("./JavascriptParser");
47
48/** @typedef {import("eslint-scope").Reference} Reference */
49/** @typedef {import("eslint-scope").Scope} Scope */
50/** @typedef {import("eslint-scope").Variable} Variable */
51/** @typedef {import("webpack-sources").Source} Source */
52/** @typedef {import("../../declarations/WebpackOptions").Output} OutputOptions */
53/** @typedef {import("../Chunk")} Chunk */
54/** @typedef {import("../ChunkGraph")} ChunkGraph */
55/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
56/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
57/** @typedef {import("../Compilation").ModuleObject} ModuleObject */
58/** @typedef {import("../Compiler")} Compiler */
59/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
60/** @typedef {import("../Entrypoint")} Entrypoint */
61/** @typedef {import("../Module")} Module */
62/** @typedef {import("../Module").BuildInfo} BuildInfo */
63/** @typedef {import("../ModuleGraph")} ModuleGraph */
64/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
65/** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
66/** @typedef {import("../WebpackError")} WebpackError */
67/** @typedef {import("../javascript/JavascriptParser").Range} Range */
68/** @typedef {import("../util/Hash")} Hash */
69/** @typedef {import("../util/createHash").Algorithm} Algorithm */
70
71/**
72 * @param {Chunk} chunk a chunk
73 * @param {ChunkGraph} chunkGraph the chunk graph
74 * @returns {boolean} true, when a JS file is needed for this chunk
75 */
76const chunkHasJs = (chunk, chunkGraph) => {
77 if (chunkGraph.getNumberOfEntryModules(chunk) > 0) return true;
78
79 return Boolean(
80 chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")
81 );
82};
83
84/**
85 * @param {Chunk} chunk a chunk
86 * @param {ChunkGraph} chunkGraph the chunk graph
87 * @returns {boolean} true, when a JS file is needed for this chunk
88 */
89const chunkHasRuntimeOrJs = (chunk, chunkGraph) => {
90 if (
91 chunkGraph.getChunkModulesIterableBySourceType(
92 chunk,
93 WEBPACK_MODULE_TYPE_RUNTIME
94 )
95 )
96 return true;
97
98 return Boolean(
99 chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")
100 );
101};
102
103/**
104 * @param {Module} module a module
105 * @param {string} code the code
106 * @returns {string} generated code for the stack
107 */
108const printGeneratedCodeForStack = (module, code) => {
109 const lines = code.split("\n");
110 const n = `${lines.length}`.length;
111 return `\n\nGenerated code for ${module.identifier()}\n${lines
112 .map(
113 /**
114 * @param {string} line the line
115 * @param {number} i the index
116 * @param {string[]} lines the lines
117 * @returns {string} the line with line number
118 */
119 (line, i, lines) => {
120 const iStr = `${i + 1}`;
121 return `${" ".repeat(n - iStr.length)}${iStr} | ${line}`;
122 }
123 )
124 .join("\n")}`;
125};
126
127/**
128 * @typedef {object} RenderContext
129 * @property {Chunk} chunk the chunk
130 * @property {DependencyTemplates} dependencyTemplates the dependency templates
131 * @property {RuntimeTemplate} runtimeTemplate the runtime template
132 * @property {ModuleGraph} moduleGraph the module graph
133 * @property {ChunkGraph} chunkGraph the chunk graph
134 * @property {CodeGenerationResults} codeGenerationResults results of code generation
135 * @property {boolean | undefined} strictMode rendering in strict context
136 */
137
138/**
139 * @typedef {object} MainRenderContext
140 * @property {Chunk} chunk the chunk
141 * @property {DependencyTemplates} dependencyTemplates the dependency templates
142 * @property {RuntimeTemplate} runtimeTemplate the runtime template
143 * @property {ModuleGraph} moduleGraph the module graph
144 * @property {ChunkGraph} chunkGraph the chunk graph
145 * @property {CodeGenerationResults} codeGenerationResults results of code generation
146 * @property {string} hash hash to be used for render call
147 * @property {boolean | undefined} strictMode rendering in strict context
148 */
149
150/**
151 * @typedef {object} ChunkRenderContext
152 * @property {Chunk} chunk the chunk
153 * @property {DependencyTemplates} dependencyTemplates the dependency templates
154 * @property {RuntimeTemplate} runtimeTemplate the runtime template
155 * @property {ModuleGraph} moduleGraph the module graph
156 * @property {ChunkGraph} chunkGraph the chunk graph
157 * @property {CodeGenerationResults} codeGenerationResults results of code generation
158 * @property {InitFragment<ChunkRenderContext>[]} chunkInitFragments init fragments for the chunk
159 * @property {boolean | undefined} strictMode rendering in strict context
160 */
161
162/**
163 * @typedef {object} RenderBootstrapContext
164 * @property {Chunk} chunk the chunk
165 * @property {CodeGenerationResults} codeGenerationResults results of code generation
166 * @property {RuntimeTemplate} runtimeTemplate the runtime template
167 * @property {ModuleGraph} moduleGraph the module graph
168 * @property {ChunkGraph} chunkGraph the chunk graph
169 * @property {string} hash hash to be used for render call
170 */
171
172/** @typedef {RenderContext & { inlined: boolean }} StartupRenderContext */
173
174/**
175 * @typedef {object} CompilationHooks
176 * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContent
177 * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContainer
178 * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage
179 * @property {SyncWaterfallHook<[Source, RenderContext]>} renderChunk
180 * @property {SyncWaterfallHook<[Source, RenderContext]>} renderMain
181 * @property {SyncWaterfallHook<[Source, RenderContext]>} renderContent
182 * @property {SyncWaterfallHook<[Source, RenderContext]>} render
183 * @property {SyncWaterfallHook<[Source, Module, StartupRenderContext]>} renderStartup
184 * @property {SyncWaterfallHook<[string, RenderBootstrapContext]>} renderRequire
185 * @property {SyncBailHook<[Module, RenderBootstrapContext], string | void>} inlineInRuntimeBailout
186 * @property {SyncBailHook<[Module, RenderContext], string | void>} embedInRuntimeBailout
187 * @property {SyncBailHook<[RenderContext], string | void>} strictRuntimeBailout
188 * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash
189 * @property {SyncBailHook<[Chunk, RenderContext], boolean | void>} useSourceMap
190 */
191
192/** @type {WeakMap<Compilation, CompilationHooks>} */
193const compilationHooksMap = new WeakMap();
194
195const PLUGIN_NAME = "JavascriptModulesPlugin";
196
197/** @typedef {{ header: string[], beforeStartup: string[], startup: string[], afterStartup: string[], allowInlineStartup: boolean }} Bootstrap */
198
199class JavascriptModulesPlugin {
200 /**
201 * @param {Compilation} compilation the compilation
202 * @returns {CompilationHooks} the attached hooks
203 */
204 static getCompilationHooks(compilation) {
205 if (!(compilation instanceof Compilation)) {
206 throw new TypeError(
207 "The 'compilation' argument must be an instance of Compilation"
208 );
209 }
210 let hooks = compilationHooksMap.get(compilation);
211 if (hooks === undefined) {
212 hooks = {
213 renderModuleContent: new SyncWaterfallHook([
214 "source",
215 "module",
216 "renderContext"
217 ]),
218 renderModuleContainer: new SyncWaterfallHook([
219 "source",
220 "module",
221 "renderContext"
222 ]),
223 renderModulePackage: new SyncWaterfallHook([
224 "source",
225 "module",
226 "renderContext"
227 ]),
228 render: new SyncWaterfallHook(["source", "renderContext"]),
229 renderContent: new SyncWaterfallHook(["source", "renderContext"]),
230 renderStartup: new SyncWaterfallHook([
231 "source",
232 "module",
233 "startupRenderContext"
234 ]),
235 renderChunk: new SyncWaterfallHook(["source", "renderContext"]),
236 renderMain: new SyncWaterfallHook(["source", "renderContext"]),
237 renderRequire: new SyncWaterfallHook(["code", "renderContext"]),
238 inlineInRuntimeBailout: new SyncBailHook(["module", "renderContext"]),
239 embedInRuntimeBailout: new SyncBailHook(["module", "renderContext"]),
240 strictRuntimeBailout: new SyncBailHook(["renderContext"]),
241 chunkHash: new SyncHook(["chunk", "hash", "context"]),
242 useSourceMap: new SyncBailHook(["chunk", "renderContext"])
243 };
244 compilationHooksMap.set(compilation, hooks);
245 }
246 return hooks;
247 }
248
249 constructor(options = {}) {
250 this.options = options;
251 /** @type {WeakMap<Source, TODO>} */
252 this._moduleFactoryCache = new WeakMap();
253 }
254
255 /**
256 * Apply the plugin
257 * @param {Compiler} compiler the compiler instance
258 * @returns {void}
259 */
260 apply(compiler) {
261 compiler.hooks.compilation.tap(
262 PLUGIN_NAME,
263 (compilation, { normalModuleFactory }) => {
264 const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
265 normalModuleFactory.hooks.createParser
266 .for(JAVASCRIPT_MODULE_TYPE_AUTO)
267 .tap(PLUGIN_NAME, options => new JavascriptParser("auto"));
268 normalModuleFactory.hooks.createParser
269 .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
270 .tap(PLUGIN_NAME, options => new JavascriptParser("script"));
271 normalModuleFactory.hooks.createParser
272 .for(JAVASCRIPT_MODULE_TYPE_ESM)
273 .tap(PLUGIN_NAME, options => new JavascriptParser("module"));
274 normalModuleFactory.hooks.createGenerator
275 .for(JAVASCRIPT_MODULE_TYPE_AUTO)
276 .tap(PLUGIN_NAME, () => new JavascriptGenerator());
277 normalModuleFactory.hooks.createGenerator
278 .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
279 .tap(PLUGIN_NAME, () => new JavascriptGenerator());
280 normalModuleFactory.hooks.createGenerator
281 .for(JAVASCRIPT_MODULE_TYPE_ESM)
282 .tap(PLUGIN_NAME, () => new JavascriptGenerator());
283 compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
284 const {
285 hash,
286 chunk,
287 chunkGraph,
288 moduleGraph,
289 runtimeTemplate,
290 dependencyTemplates,
291 outputOptions,
292 codeGenerationResults
293 } = options;
294
295 const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
296 const filenameTemplate =
297 JavascriptModulesPlugin.getChunkFilenameTemplate(
298 chunk,
299 outputOptions
300 );
301
302 let render;
303
304 if (hotUpdateChunk) {
305 render = () =>
306 this.renderChunk(
307 {
308 chunk,
309 dependencyTemplates,
310 runtimeTemplate,
311 moduleGraph,
312 chunkGraph,
313 codeGenerationResults,
314 strictMode: runtimeTemplate.isModule()
315 },
316 hooks
317 );
318 } else if (chunk.hasRuntime()) {
319 if (!chunkHasRuntimeOrJs(chunk, chunkGraph)) {
320 return result;
321 }
322
323 render = () =>
324 this.renderMain(
325 {
326 hash,
327 chunk,
328 dependencyTemplates,
329 runtimeTemplate,
330 moduleGraph,
331 chunkGraph,
332 codeGenerationResults,
333 strictMode: runtimeTemplate.isModule()
334 },
335 hooks,
336 compilation
337 );
338 } else {
339 if (!chunkHasJs(chunk, chunkGraph)) {
340 return result;
341 }
342
343 render = () =>
344 this.renderChunk(
345 {
346 chunk,
347 dependencyTemplates,
348 runtimeTemplate,
349 moduleGraph,
350 chunkGraph,
351 codeGenerationResults,
352 strictMode: runtimeTemplate.isModule()
353 },
354 hooks
355 );
356 }
357
358 result.push({
359 render,
360 filenameTemplate,
361 pathOptions: {
362 hash,
363 runtime: chunk.runtime,
364 chunk,
365 contentHashType: "javascript"
366 },
367 info: {
368 javascriptModule: compilation.runtimeTemplate.isModule()
369 },
370 identifier: hotUpdateChunk
371 ? `hotupdatechunk${chunk.id}`
372 : `chunk${chunk.id}`,
373 hash: chunk.contentHash.javascript
374 });
375
376 return result;
377 });
378 compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => {
379 hooks.chunkHash.call(chunk, hash, context);
380 if (chunk.hasRuntime()) {
381 this.updateHashWithBootstrap(
382 hash,
383 {
384 hash: "0000",
385 chunk,
386 codeGenerationResults: context.codeGenerationResults,
387 chunkGraph: context.chunkGraph,
388 moduleGraph: context.moduleGraph,
389 runtimeTemplate: context.runtimeTemplate
390 },
391 hooks
392 );
393 }
394 });
395 compilation.hooks.contentHash.tap(PLUGIN_NAME, chunk => {
396 const {
397 chunkGraph,
398 codeGenerationResults,
399 moduleGraph,
400 runtimeTemplate,
401 outputOptions: {
402 hashSalt,
403 hashDigest,
404 hashDigestLength,
405 hashFunction
406 }
407 } = compilation;
408 const hash = createHash(/** @type {Algorithm} */ (hashFunction));
409 if (hashSalt) hash.update(hashSalt);
410 if (chunk.hasRuntime()) {
411 this.updateHashWithBootstrap(
412 hash,
413 {
414 hash: "0000",
415 chunk,
416 codeGenerationResults,
417 chunkGraph: compilation.chunkGraph,
418 moduleGraph: compilation.moduleGraph,
419 runtimeTemplate: compilation.runtimeTemplate
420 },
421 hooks
422 );
423 } else {
424 hash.update(`${chunk.id} `);
425 hash.update(chunk.ids ? chunk.ids.join(",") : "");
426 }
427 hooks.chunkHash.call(chunk, hash, {
428 chunkGraph,
429 codeGenerationResults,
430 moduleGraph,
431 runtimeTemplate
432 });
433 const modules = chunkGraph.getChunkModulesIterableBySourceType(
434 chunk,
435 "javascript"
436 );
437 if (modules) {
438 const xor = new StringXor();
439 for (const m of modules) {
440 xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
441 }
442 xor.updateHash(hash);
443 }
444 const runtimeModules = chunkGraph.getChunkModulesIterableBySourceType(
445 chunk,
446 WEBPACK_MODULE_TYPE_RUNTIME
447 );
448 if (runtimeModules) {
449 const xor = new StringXor();
450 for (const m of runtimeModules) {
451 xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
452 }
453 xor.updateHash(hash);
454 }
455 const digest = /** @type {string} */ (hash.digest(hashDigest));
456 chunk.contentHash.javascript = nonNumericOnlyHash(
457 digest,
458 /** @type {number} */
459 (hashDigestLength)
460 );
461 });
462 compilation.hooks.additionalTreeRuntimeRequirements.tap(
463 PLUGIN_NAME,
464 (chunk, set, { chunkGraph }) => {
465 if (
466 !set.has(RuntimeGlobals.startupNoDefault) &&
467 chunkGraph.hasChunkEntryDependentChunks(chunk)
468 ) {
469 set.add(RuntimeGlobals.onChunksLoaded);
470 set.add(RuntimeGlobals.exports);
471 set.add(RuntimeGlobals.require);
472 }
473 }
474 );
475 compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
476 const source = options.codeGenerationResult.sources.get("javascript");
477 if (source === undefined) return;
478 const { module } = options;
479 const code = source.source();
480
481 const fn = vm.runInThisContext(
482 `(function(${module.moduleArgument}, ${module.exportsArgument}, ${RuntimeGlobals.require}) {\n${code}\n/**/})`,
483 {
484 filename: module.identifier(),
485 lineOffset: -1
486 }
487 );
488
489 const moduleObject =
490 /** @type {ModuleObject} */
491 (options.moduleObject);
492
493 try {
494 fn.call(
495 moduleObject.exports,
496 moduleObject,
497 moduleObject.exports,
498 context.__webpack_require__
499 );
500 } catch (err) {
501 /** @type {Error} */
502 (err).stack += printGeneratedCodeForStack(
503 options.module,
504 /** @type {string} */ (code)
505 );
506 throw err;
507 }
508 });
509 compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => {
510 const source = options.codeGenerationResult.sources.get("runtime");
511 if (source === undefined) return;
512 let code = source.source();
513 if (typeof code !== "string") code = code.toString();
514
515 const fn = vm.runInThisContext(
516 `(function(${RuntimeGlobals.require}) {\n${code}\n/**/})`,
517 {
518 filename: options.module.identifier(),
519 lineOffset: -1
520 }
521 );
522 try {
523 // eslint-disable-next-line no-useless-call
524 fn.call(null, context.__webpack_require__);
525 } catch (err) {
526 /** @type {Error} */
527 (err).stack += printGeneratedCodeForStack(options.module, code);
528 throw err;
529 }
530 });
531 }
532 );
533 }
534
535 /**
536 * @param {Chunk} chunk chunk
537 * @param {OutputOptions} outputOptions output options
538 * @returns {TemplatePath} used filename template
539 */
540 static getChunkFilenameTemplate(chunk, outputOptions) {
541 if (chunk.filenameTemplate) {
542 return chunk.filenameTemplate;
543 } else if (chunk instanceof HotUpdateChunk) {
544 return /** @type {TemplatePath} */ (outputOptions.hotUpdateChunkFilename);
545 } else if (chunk.canBeInitial()) {
546 return /** @type {TemplatePath} */ (outputOptions.filename);
547 }
548 return /** @type {TemplatePath} */ (outputOptions.chunkFilename);
549 }
550
551 /**
552 * @param {Module} module the rendered module
553 * @param {ChunkRenderContext} renderContext options object
554 * @param {CompilationHooks} hooks hooks
555 * @param {boolean} factory true: renders as factory method, false: pure module content
556 * @returns {Source | null} the newly generated source from rendering
557 */
558 renderModule(module, renderContext, hooks, factory) {
559 const {
560 chunk,
561 chunkGraph,
562 runtimeTemplate,
563 codeGenerationResults,
564 strictMode
565 } = renderContext;
566 try {
567 const codeGenResult = codeGenerationResults.get(module, chunk.runtime);
568 const moduleSource = codeGenResult.sources.get("javascript");
569 if (!moduleSource) return null;
570 if (codeGenResult.data !== undefined) {
571 const chunkInitFragments = codeGenResult.data.get("chunkInitFragments");
572 if (chunkInitFragments) {
573 for (const i of chunkInitFragments)
574 renderContext.chunkInitFragments.push(i);
575 }
576 }
577 const moduleSourcePostContent = tryRunOrWebpackError(
578 () =>
579 hooks.renderModuleContent.call(moduleSource, module, renderContext),
580 "JavascriptModulesPlugin.getCompilationHooks().renderModuleContent"
581 );
582 let moduleSourcePostContainer;
583 if (factory) {
584 const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
585 module,
586 chunk.runtime
587 );
588 const needModule = runtimeRequirements.has(RuntimeGlobals.module);
589 const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
590 const needRequire =
591 runtimeRequirements.has(RuntimeGlobals.require) ||
592 runtimeRequirements.has(RuntimeGlobals.requireScope);
593 const needThisAsExports = runtimeRequirements.has(
594 RuntimeGlobals.thisAsExports
595 );
596 const needStrict =
597 /** @type {BuildInfo} */
598 (module.buildInfo).strict && !strictMode;
599 const cacheEntry = this._moduleFactoryCache.get(
600 moduleSourcePostContent
601 );
602 let source;
603 if (
604 cacheEntry &&
605 cacheEntry.needModule === needModule &&
606 cacheEntry.needExports === needExports &&
607 cacheEntry.needRequire === needRequire &&
608 cacheEntry.needThisAsExports === needThisAsExports &&
609 cacheEntry.needStrict === needStrict
610 ) {
611 source = cacheEntry.source;
612 } else {
613 const factorySource = new ConcatSource();
614 const args = [];
615 if (needExports || needRequire || needModule)
616 args.push(
617 needModule
618 ? module.moduleArgument
619 : `__unused_webpack_${module.moduleArgument}`
620 );
621 if (needExports || needRequire)
622 args.push(
623 needExports
624 ? module.exportsArgument
625 : `__unused_webpack_${module.exportsArgument}`
626 );
627 if (needRequire) args.push(RuntimeGlobals.require);
628 if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
629 factorySource.add(`/***/ ((${args.join(", ")}) => {\n\n`);
630 } else {
631 factorySource.add(`/***/ (function(${args.join(", ")}) {\n\n`);
632 }
633 if (needStrict) {
634 factorySource.add('"use strict";\n');
635 }
636 factorySource.add(moduleSourcePostContent);
637 factorySource.add("\n\n/***/ })");
638 source = new CachedSource(factorySource);
639 this._moduleFactoryCache.set(moduleSourcePostContent, {
640 source,
641 needModule,
642 needExports,
643 needRequire,
644 needThisAsExports,
645 needStrict
646 });
647 }
648 moduleSourcePostContainer = tryRunOrWebpackError(
649 () => hooks.renderModuleContainer.call(source, module, renderContext),
650 "JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
651 );
652 } else {
653 moduleSourcePostContainer = moduleSourcePostContent;
654 }
655 return tryRunOrWebpackError(
656 () =>
657 hooks.renderModulePackage.call(
658 moduleSourcePostContainer,
659 module,
660 renderContext
661 ),
662 "JavascriptModulesPlugin.getCompilationHooks().renderModulePackage"
663 );
664 } catch (err) {
665 /** @type {WebpackError} */
666 (err).module = module;
667 throw err;
668 }
669 }
670
671 /**
672 * @param {RenderContext} renderContext the render context
673 * @param {CompilationHooks} hooks hooks
674 * @returns {Source} the rendered source
675 */
676 renderChunk(renderContext, hooks) {
677 const { chunk, chunkGraph } = renderContext;
678 const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
679 chunk,
680 "javascript",
681 compareModulesByIdentifier
682 );
683 const allModules = modules ? Array.from(modules) : [];
684 let strictHeader;
685 let allStrict = renderContext.strictMode;
686 if (
687 !allStrict &&
688 allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict)
689 ) {
690 const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
691 strictHeader = strictBailout
692 ? `// runtime can't be in strict mode because ${strictBailout}.\n`
693 : '"use strict";\n';
694 if (!strictBailout) allStrict = true;
695 }
696 /** @type {ChunkRenderContext} */
697 const chunkRenderContext = {
698 ...renderContext,
699 chunkInitFragments: [],
700 strictMode: allStrict
701 };
702 const moduleSources =
703 Template.renderChunkModules(chunkRenderContext, allModules, module =>
704 this.renderModule(module, chunkRenderContext, hooks, true)
705 ) || new RawSource("{}");
706 let source = tryRunOrWebpackError(
707 () => hooks.renderChunk.call(moduleSources, chunkRenderContext),
708 "JavascriptModulesPlugin.getCompilationHooks().renderChunk"
709 );
710 source = tryRunOrWebpackError(
711 () => hooks.renderContent.call(source, chunkRenderContext),
712 "JavascriptModulesPlugin.getCompilationHooks().renderContent"
713 );
714 if (!source) {
715 throw new Error(
716 "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
717 );
718 }
719 source = InitFragment.addToSource(
720 source,
721 chunkRenderContext.chunkInitFragments,
722 chunkRenderContext
723 );
724 source = tryRunOrWebpackError(
725 () => hooks.render.call(source, chunkRenderContext),
726 "JavascriptModulesPlugin.getCompilationHooks().render"
727 );
728 if (!source) {
729 throw new Error(
730 "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
731 );
732 }
733 chunk.rendered = true;
734 return strictHeader
735 ? new ConcatSource(strictHeader, source, ";")
736 : renderContext.runtimeTemplate.isModule()
737 ? source
738 : new ConcatSource(source, ";");
739 }
740
741 /**
742 * @param {MainRenderContext} renderContext options object
743 * @param {CompilationHooks} hooks hooks
744 * @param {Compilation} compilation the compilation
745 * @returns {Source} the newly generated source from rendering
746 */
747 renderMain(renderContext, hooks, compilation) {
748 const { chunk, chunkGraph, runtimeTemplate } = renderContext;
749
750 const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
751 const iife = runtimeTemplate.isIIFE();
752
753 const bootstrap = this.renderBootstrap(renderContext, hooks);
754 const useSourceMap = hooks.useSourceMap.call(chunk, renderContext);
755
756 const allModules = Array.from(
757 chunkGraph.getOrderedChunkModulesIterableBySourceType(
758 chunk,
759 "javascript",
760 compareModulesByIdentifier
761 ) || []
762 );
763
764 const hasEntryModules = chunkGraph.getNumberOfEntryModules(chunk) > 0;
765 /** @type {Set<Module> | undefined} */
766 let inlinedModules;
767 if (bootstrap.allowInlineStartup && hasEntryModules) {
768 inlinedModules = new Set(chunkGraph.getChunkEntryModulesIterable(chunk));
769 }
770
771 const source = new ConcatSource();
772 let prefix;
773 if (iife) {
774 if (runtimeTemplate.supportsArrowFunction()) {
775 source.add("/******/ (() => { // webpackBootstrap\n");
776 } else {
777 source.add("/******/ (function() { // webpackBootstrap\n");
778 }
779 prefix = "/******/ \t";
780 } else {
781 prefix = "/******/ ";
782 }
783 let allStrict = renderContext.strictMode;
784 if (
785 !allStrict &&
786 allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict)
787 ) {
788 const strictBailout = hooks.strictRuntimeBailout.call(renderContext);
789 if (strictBailout) {
790 source.add(
791 `${
792 prefix
793 }// runtime can't be in strict mode because ${strictBailout}.\n`
794 );
795 } else {
796 allStrict = true;
797 source.add(`${prefix}"use strict";\n`);
798 }
799 }
800
801 /** @type {ChunkRenderContext} */
802 const chunkRenderContext = {
803 ...renderContext,
804 chunkInitFragments: [],
805 strictMode: allStrict
806 };
807
808 const chunkModules = Template.renderChunkModules(
809 chunkRenderContext,
810 inlinedModules
811 ? allModules.filter(
812 m => !(/** @type {Set<Module>} */ (inlinedModules).has(m))
813 )
814 : allModules,
815 module => this.renderModule(module, chunkRenderContext, hooks, true),
816 prefix
817 );
818 if (
819 chunkModules ||
820 runtimeRequirements.has(RuntimeGlobals.moduleFactories) ||
821 runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly) ||
822 runtimeRequirements.has(RuntimeGlobals.require)
823 ) {
824 source.add(`${prefix}var __webpack_modules__ = (`);
825 source.add(chunkModules || "{}");
826 source.add(");\n");
827 source.add(
828 "/************************************************************************/\n"
829 );
830 }
831
832 if (bootstrap.header.length > 0) {
833 const header = `${Template.asString(bootstrap.header)}\n`;
834 source.add(
835 new PrefixSource(
836 prefix,
837 useSourceMap
838 ? new OriginalSource(header, "webpack/bootstrap")
839 : new RawSource(header)
840 )
841 );
842 source.add(
843 "/************************************************************************/\n"
844 );
845 }
846
847 const runtimeModules =
848 renderContext.chunkGraph.getChunkRuntimeModulesInOrder(chunk);
849
850 if (runtimeModules.length > 0) {
851 source.add(
852 new PrefixSource(
853 prefix,
854 Template.renderRuntimeModules(runtimeModules, chunkRenderContext)
855 )
856 );
857 source.add(
858 "/************************************************************************/\n"
859 );
860 // runtimeRuntimeModules calls codeGeneration
861 for (const module of runtimeModules) {
862 compilation.codeGeneratedModules.add(module);
863 }
864 }
865 if (inlinedModules) {
866 if (bootstrap.beforeStartup.length > 0) {
867 const beforeStartup = `${Template.asString(bootstrap.beforeStartup)}\n`;
868 source.add(
869 new PrefixSource(
870 prefix,
871 useSourceMap
872 ? new OriginalSource(beforeStartup, "webpack/before-startup")
873 : new RawSource(beforeStartup)
874 )
875 );
876 }
877 const lastInlinedModule = /** @type {Module} */ (last(inlinedModules));
878 const startupSource = new ConcatSource();
879
880 if (runtimeRequirements.has(RuntimeGlobals.exports)) {
881 startupSource.add(`var ${RuntimeGlobals.exports} = {};\n`);
882 }
883
884 const avoidEntryIife = compilation.options.optimization.avoidEntryIife;
885 /** @type {Map<Module, Source> | false} */
886 let renamedInlinedModule = false;
887 if (avoidEntryIife) {
888 renamedInlinedModule = this.getRenamedInlineModule(
889 allModules,
890 renderContext,
891 inlinedModules,
892 chunkRenderContext,
893 hooks,
894 allStrict,
895 Boolean(chunkModules)
896 );
897 }
898
899 for (const m of inlinedModules) {
900 const renderedModule = renamedInlinedModule
901 ? renamedInlinedModule.get(m)
902 : this.renderModule(m, chunkRenderContext, hooks, false);
903
904 if (renderedModule) {
905 const innerStrict =
906 !allStrict && /** @type {BuildInfo} */ (m.buildInfo).strict;
907 const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
908 m,
909 chunk.runtime
910 );
911 const exports = runtimeRequirements.has(RuntimeGlobals.exports);
912 const webpackExports =
913 exports && m.exportsArgument === RuntimeGlobals.exports;
914 const iife = innerStrict
915 ? "it needs to be in strict mode."
916 : inlinedModules.size > 1
917 ? // TODO check globals and top-level declarations of other entries and chunk modules
918 // to make a better decision
919 "it needs to be isolated against other entry modules."
920 : chunkModules && !renamedInlinedModule
921 ? "it needs to be isolated against other modules in the chunk."
922 : exports && !webpackExports
923 ? `it uses a non-standard name for the exports (${m.exportsArgument}).`
924 : hooks.embedInRuntimeBailout.call(m, renderContext);
925 let footer;
926 if (iife !== undefined) {
927 startupSource.add(
928 `// This entry needs to be wrapped in an IIFE because ${iife}\n`
929 );
930 const arrow = runtimeTemplate.supportsArrowFunction();
931 if (arrow) {
932 startupSource.add("(() => {\n");
933 footer = "\n})();\n\n";
934 } else {
935 startupSource.add("!function() {\n");
936 footer = "\n}();\n";
937 }
938 if (innerStrict) startupSource.add('"use strict";\n');
939 } else {
940 footer = "\n";
941 }
942 if (exports) {
943 if (m !== lastInlinedModule)
944 startupSource.add(`var ${m.exportsArgument} = {};\n`);
945 else if (m.exportsArgument !== RuntimeGlobals.exports)
946 startupSource.add(
947 `var ${m.exportsArgument} = ${RuntimeGlobals.exports};\n`
948 );
949 }
950 startupSource.add(renderedModule);
951 startupSource.add(footer);
952 }
953 }
954 if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
955 startupSource.add(
956 `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});\n`
957 );
958 }
959 source.add(
960 hooks.renderStartup.call(startupSource, lastInlinedModule, {
961 ...renderContext,
962 inlined: true
963 })
964 );
965 if (bootstrap.afterStartup.length > 0) {
966 const afterStartup = `${Template.asString(bootstrap.afterStartup)}\n`;
967 source.add(
968 new PrefixSource(
969 prefix,
970 useSourceMap
971 ? new OriginalSource(afterStartup, "webpack/after-startup")
972 : new RawSource(afterStartup)
973 )
974 );
975 }
976 } else {
977 const lastEntryModule =
978 /** @type {Module} */
979 (last(chunkGraph.getChunkEntryModulesIterable(chunk)));
980 /** @type {function(string[], string): Source} */
981 const toSource = useSourceMap
982 ? (content, name) =>
983 new OriginalSource(Template.asString(content), name)
984 : content => new RawSource(Template.asString(content));
985 source.add(
986 new PrefixSource(
987 prefix,
988 new ConcatSource(
989 toSource(bootstrap.beforeStartup, "webpack/before-startup"),
990 "\n",
991 hooks.renderStartup.call(
992 toSource(bootstrap.startup.concat(""), "webpack/startup"),
993 lastEntryModule,
994 {
995 ...renderContext,
996 inlined: false
997 }
998 ),
999 toSource(bootstrap.afterStartup, "webpack/after-startup"),
1000 "\n"
1001 )
1002 )
1003 );
1004 }
1005 if (
1006 hasEntryModules &&
1007 runtimeRequirements.has(RuntimeGlobals.returnExportsFromRuntime)
1008 ) {
1009 source.add(`${prefix}return ${RuntimeGlobals.exports};\n`);
1010 }
1011 if (iife) {
1012 source.add("/******/ })()\n");
1013 }
1014
1015 /** @type {Source} */
1016 let finalSource = tryRunOrWebpackError(
1017 () => hooks.renderMain.call(source, renderContext),
1018 "JavascriptModulesPlugin.getCompilationHooks().renderMain"
1019 );
1020 if (!finalSource) {
1021 throw new Error(
1022 "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderMain plugins should return something"
1023 );
1024 }
1025 finalSource = tryRunOrWebpackError(
1026 () => hooks.renderContent.call(finalSource, renderContext),
1027 "JavascriptModulesPlugin.getCompilationHooks().renderContent"
1028 );
1029 if (!finalSource) {
1030 throw new Error(
1031 "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something"
1032 );
1033 }
1034
1035 finalSource = InitFragment.addToSource(
1036 finalSource,
1037 chunkRenderContext.chunkInitFragments,
1038 chunkRenderContext
1039 );
1040 finalSource = tryRunOrWebpackError(
1041 () => hooks.render.call(finalSource, renderContext),
1042 "JavascriptModulesPlugin.getCompilationHooks().render"
1043 );
1044 if (!finalSource) {
1045 throw new Error(
1046 "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something"
1047 );
1048 }
1049 chunk.rendered = true;
1050 return iife ? new ConcatSource(finalSource, ";") : finalSource;
1051 }
1052
1053 /**
1054 * @param {Hash} hash the hash to be updated
1055 * @param {RenderBootstrapContext} renderContext options object
1056 * @param {CompilationHooks} hooks hooks
1057 */
1058 updateHashWithBootstrap(hash, renderContext, hooks) {
1059 const bootstrap = this.renderBootstrap(renderContext, hooks);
1060 for (const _k of Object.keys(bootstrap)) {
1061 const key = /** @type {keyof Bootstrap} */ (_k);
1062 hash.update(key);
1063 if (Array.isArray(bootstrap[key])) {
1064 for (const line of bootstrap[key]) {
1065 hash.update(line);
1066 }
1067 } else {
1068 hash.update(JSON.stringify(bootstrap[key]));
1069 }
1070 }
1071 }
1072
1073 /**
1074 * @param {RenderBootstrapContext} renderContext options object
1075 * @param {CompilationHooks} hooks hooks
1076 * @returns {Bootstrap} the generated source of the bootstrap code
1077 */
1078 renderBootstrap(renderContext, hooks) {
1079 const {
1080 chunkGraph,
1081 codeGenerationResults,
1082 moduleGraph,
1083 chunk,
1084 runtimeTemplate
1085 } = renderContext;
1086
1087 const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
1088
1089 const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
1090 const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
1091 const moduleFactories = runtimeRequirements.has(
1092 RuntimeGlobals.moduleFactories
1093 );
1094 const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
1095 const requireScopeUsed = runtimeRequirements.has(
1096 RuntimeGlobals.requireScope
1097 );
1098 const interceptModuleExecution = runtimeRequirements.has(
1099 RuntimeGlobals.interceptModuleExecution
1100 );
1101
1102 const useRequire =
1103 requireFunction || interceptModuleExecution || moduleUsed;
1104
1105 /**
1106 * @type {{startup: string[], beforeStartup: string[], header: string[], afterStartup: string[], allowInlineStartup: boolean}}
1107 */
1108 const result = {
1109 header: [],
1110 beforeStartup: [],
1111 startup: [],
1112 afterStartup: [],
1113 allowInlineStartup: true
1114 };
1115
1116 const { header: buf, startup, beforeStartup, afterStartup } = result;
1117
1118 if (result.allowInlineStartup && moduleFactories) {
1119 startup.push(
1120 "// module factories are used so entry inlining is disabled"
1121 );
1122 result.allowInlineStartup = false;
1123 }
1124 if (result.allowInlineStartup && moduleCache) {
1125 startup.push("// module cache are used so entry inlining is disabled");
1126 result.allowInlineStartup = false;
1127 }
1128 if (result.allowInlineStartup && interceptModuleExecution) {
1129 startup.push(
1130 "// module execution is intercepted so entry inlining is disabled"
1131 );
1132 result.allowInlineStartup = false;
1133 }
1134
1135 if (useRequire || moduleCache) {
1136 buf.push("// The module cache");
1137 buf.push("var __webpack_module_cache__ = {};");
1138 buf.push("");
1139 }
1140
1141 if (useRequire) {
1142 buf.push("// The require function");
1143 buf.push(`function ${RuntimeGlobals.require}(moduleId) {`);
1144 buf.push(Template.indent(this.renderRequire(renderContext, hooks)));
1145 buf.push("}");
1146 buf.push("");
1147 } else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
1148 buf.push("// The require scope");
1149 buf.push(`var ${RuntimeGlobals.require} = {};`);
1150 buf.push("");
1151 }
1152
1153 if (
1154 moduleFactories ||
1155 runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)
1156 ) {
1157 buf.push("// expose the modules object (__webpack_modules__)");
1158 buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
1159 buf.push("");
1160 }
1161
1162 if (moduleCache) {
1163 buf.push("// expose the module cache");
1164 buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
1165 buf.push("");
1166 }
1167
1168 if (interceptModuleExecution) {
1169 buf.push("// expose the module execution interceptor");
1170 buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
1171 buf.push("");
1172 }
1173
1174 if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
1175 if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
1176 /** @type {string[]} */
1177 const buf2 = [];
1178 const runtimeRequirements =
1179 chunkGraph.getTreeRuntimeRequirements(chunk);
1180 buf2.push("// Load entry module and return exports");
1181 let i = chunkGraph.getNumberOfEntryModules(chunk);
1182 for (const [
1183 entryModule,
1184 entrypoint
1185 ] of chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)) {
1186 if (!chunkGraph.getModuleSourceTypes(entryModule).has("javascript")) {
1187 i--;
1188 continue;
1189 }
1190 const chunks =
1191 /** @type {Entrypoint} */
1192 (entrypoint).chunks.filter(c => c !== chunk);
1193 if (result.allowInlineStartup && chunks.length > 0) {
1194 buf2.push(
1195 "// This entry module depends on other loaded chunks and execution need to be delayed"
1196 );
1197 result.allowInlineStartup = false;
1198 }
1199 if (
1200 result.allowInlineStartup &&
1201 someInIterable(
1202 moduleGraph.getIncomingConnectionsByOriginModule(entryModule),
1203 ([originModule, connections]) =>
1204 originModule &&
1205 connections.some(c => c.isTargetActive(chunk.runtime)) &&
1206 someInIterable(
1207 chunkGraph.getModuleRuntimes(originModule),
1208 runtime =>
1209 intersectRuntime(runtime, chunk.runtime) !== undefined
1210 )
1211 )
1212 ) {
1213 buf2.push(
1214 "// This entry module is referenced by other modules so it can't be inlined"
1215 );
1216 result.allowInlineStartup = false;
1217 }
1218
1219 let data;
1220 if (codeGenerationResults.has(entryModule, chunk.runtime)) {
1221 const result = codeGenerationResults.get(
1222 entryModule,
1223 chunk.runtime
1224 );
1225 data = result.data;
1226 }
1227 if (
1228 result.allowInlineStartup &&
1229 (!data || !data.get("topLevelDeclarations")) &&
1230 (!entryModule.buildInfo ||
1231 !entryModule.buildInfo.topLevelDeclarations)
1232 ) {
1233 buf2.push(
1234 "// This entry module doesn't tell about it's top-level declarations so it can't be inlined"
1235 );
1236 result.allowInlineStartup = false;
1237 }
1238 if (result.allowInlineStartup) {
1239 const bailout = hooks.inlineInRuntimeBailout.call(
1240 entryModule,
1241 renderContext
1242 );
1243 if (bailout !== undefined) {
1244 buf2.push(
1245 `// This entry module can't be inlined because ${bailout}`
1246 );
1247 result.allowInlineStartup = false;
1248 }
1249 }
1250 i--;
1251 const moduleId = chunkGraph.getModuleId(entryModule);
1252 const entryRuntimeRequirements =
1253 chunkGraph.getModuleRuntimeRequirements(entryModule, chunk.runtime);
1254 let moduleIdExpr = JSON.stringify(moduleId);
1255 if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
1256 moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
1257 }
1258 if (
1259 result.allowInlineStartup &&
1260 entryRuntimeRequirements.has(RuntimeGlobals.module)
1261 ) {
1262 result.allowInlineStartup = false;
1263 buf2.push(
1264 "// This entry module used 'module' so it can't be inlined"
1265 );
1266 }
1267 if (chunks.length > 0) {
1268 buf2.push(
1269 `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
1270 RuntimeGlobals.onChunksLoaded
1271 }(undefined, ${JSON.stringify(
1272 chunks.map(c => c.id)
1273 )}, ${runtimeTemplate.returningFunction(
1274 `${RuntimeGlobals.require}(${moduleIdExpr})`
1275 )})`
1276 );
1277 } else if (useRequire) {
1278 buf2.push(
1279 `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${
1280 RuntimeGlobals.require
1281 }(${moduleIdExpr});`
1282 );
1283 } else {
1284 if (i === 0) buf2.push(`var ${RuntimeGlobals.exports} = {};`);
1285 if (requireScopeUsed) {
1286 buf2.push(
1287 `__webpack_modules__[${moduleIdExpr}](0, ${
1288 i === 0 ? RuntimeGlobals.exports : "{}"
1289 }, ${RuntimeGlobals.require});`
1290 );
1291 } else if (entryRuntimeRequirements.has(RuntimeGlobals.exports)) {
1292 buf2.push(
1293 `__webpack_modules__[${moduleIdExpr}](0, ${
1294 i === 0 ? RuntimeGlobals.exports : "{}"
1295 });`
1296 );
1297 } else {
1298 buf2.push(`__webpack_modules__[${moduleIdExpr}]();`);
1299 }
1300 }
1301 }
1302 if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) {
1303 buf2.push(
1304 `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});`
1305 );
1306 }
1307 if (
1308 runtimeRequirements.has(RuntimeGlobals.startup) ||
1309 (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) &&
1310 runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter))
1311 ) {
1312 result.allowInlineStartup = false;
1313 buf.push("// the startup function");
1314 buf.push(
1315 `${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction("", [
1316 ...buf2,
1317 `return ${RuntimeGlobals.exports};`
1318 ])};`
1319 );
1320 buf.push("");
1321 startup.push("// run startup");
1322 startup.push(
1323 `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
1324 );
1325 } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore)) {
1326 buf.push("// the startup function");
1327 buf.push(
1328 `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
1329 );
1330 beforeStartup.push("// run runtime startup");
1331 beforeStartup.push(`${RuntimeGlobals.startup}();`);
1332 startup.push("// startup");
1333 startup.push(Template.asString(buf2));
1334 } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)) {
1335 buf.push("// the startup function");
1336 buf.push(
1337 `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
1338 );
1339 startup.push("// startup");
1340 startup.push(Template.asString(buf2));
1341 afterStartup.push("// run runtime startup");
1342 afterStartup.push(`${RuntimeGlobals.startup}();`);
1343 } else {
1344 startup.push("// startup");
1345 startup.push(Template.asString(buf2));
1346 }
1347 } else if (
1348 runtimeRequirements.has(RuntimeGlobals.startup) ||
1349 runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
1350 runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
1351 ) {
1352 buf.push(
1353 "// the startup function",
1354 "// It's empty as no entry modules are in this chunk",
1355 `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`,
1356 ""
1357 );
1358 }
1359 } else if (
1360 runtimeRequirements.has(RuntimeGlobals.startup) ||
1361 runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) ||
1362 runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)
1363 ) {
1364 result.allowInlineStartup = false;
1365 buf.push(
1366 "// the startup function",
1367 "// It's empty as some runtime module handles the default behavior",
1368 `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`
1369 );
1370 startup.push("// run startup");
1371 startup.push(
1372 `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();`
1373 );
1374 }
1375 return result;
1376 }
1377
1378 /**
1379 * @param {RenderBootstrapContext} renderContext options object
1380 * @param {CompilationHooks} hooks hooks
1381 * @returns {string} the generated source of the require function
1382 */
1383 renderRequire(renderContext, hooks) {
1384 const {
1385 chunk,
1386 chunkGraph,
1387 runtimeTemplate: { outputOptions }
1388 } = renderContext;
1389 const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
1390 const moduleExecution = runtimeRequirements.has(
1391 RuntimeGlobals.interceptModuleExecution
1392 )
1393 ? Template.asString([
1394 `var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: ${RuntimeGlobals.require} };`,
1395 `${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`,
1396 "module = execOptions.module;",
1397 "execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
1398 ])
1399 : runtimeRequirements.has(RuntimeGlobals.thisAsExports)
1400 ? Template.asString([
1401 `__webpack_modules__[moduleId].call(module.exports, module, module.exports, ${RuntimeGlobals.require});`
1402 ])
1403 : Template.asString([
1404 `__webpack_modules__[moduleId](module, module.exports, ${RuntimeGlobals.require});`
1405 ]);
1406 const needModuleId = runtimeRequirements.has(RuntimeGlobals.moduleId);
1407 const needModuleLoaded = runtimeRequirements.has(
1408 RuntimeGlobals.moduleLoaded
1409 );
1410 const content = Template.asString([
1411 "// Check if module is in cache",
1412 "var cachedModule = __webpack_module_cache__[moduleId];",
1413 "if (cachedModule !== undefined) {",
1414 outputOptions.strictModuleErrorHandling
1415 ? Template.indent([
1416 "if (cachedModule.error !== undefined) throw cachedModule.error;",
1417 "return cachedModule.exports;"
1418 ])
1419 : Template.indent("return cachedModule.exports;"),
1420 "}",
1421 "// Create a new module (and put it into the cache)",
1422 "var module = __webpack_module_cache__[moduleId] = {",
1423 Template.indent([
1424 needModuleId ? "id: moduleId," : "// no module.id needed",
1425 needModuleLoaded ? "loaded: false," : "// no module.loaded needed",
1426 "exports: {}"
1427 ]),
1428 "};",
1429 "",
1430 outputOptions.strictModuleExceptionHandling
1431 ? Template.asString([
1432 "// Execute the module function",
1433 "var threw = true;",
1434 "try {",
1435 Template.indent([moduleExecution, "threw = false;"]),
1436 "} finally {",
1437 Template.indent([
1438 "if(threw) delete __webpack_module_cache__[moduleId];"
1439 ]),
1440 "}"
1441 ])
1442 : outputOptions.strictModuleErrorHandling
1443 ? Template.asString([
1444 "// Execute the module function",
1445 "try {",
1446 Template.indent(moduleExecution),
1447 "} catch(e) {",
1448 Template.indent(["module.error = e;", "throw e;"]),
1449 "}"
1450 ])
1451 : Template.asString([
1452 "// Execute the module function",
1453 moduleExecution
1454 ]),
1455 needModuleLoaded
1456 ? Template.asString([
1457 "",
1458 "// Flag the module as loaded",
1459 `${RuntimeGlobals.moduleLoaded} = true;`,
1460 ""
1461 ])
1462 : "",
1463 "// Return the exports of the module",
1464 "return module.exports;"
1465 ]);
1466 return tryRunOrWebpackError(
1467 () => hooks.renderRequire.call(content, renderContext),
1468 "JavascriptModulesPlugin.getCompilationHooks().renderRequire"
1469 );
1470 }
1471
1472 /**
1473 * @param {Module[]} allModules allModules
1474 * @param {MainRenderContext} renderContext renderContext
1475 * @param {Set<Module>} inlinedModules inlinedModules
1476 * @param {ChunkRenderContext} chunkRenderContext chunkRenderContext
1477 * @param {CompilationHooks} hooks hooks
1478 * @param {boolean | undefined} allStrict allStrict
1479 * @param {boolean} hasChunkModules hasChunkModules
1480 * @returns {Map<Module, Source> | false} renamed inlined modules
1481 */
1482 getRenamedInlineModule(
1483 allModules,
1484 renderContext,
1485 inlinedModules,
1486 chunkRenderContext,
1487 hooks,
1488 allStrict,
1489 hasChunkModules
1490 ) {
1491 const innerStrict =
1492 !allStrict &&
1493 allModules.every(m => /** @type {BuildInfo} */ (m.buildInfo).strict);
1494 const isMultipleEntries = inlinedModules.size > 1;
1495 const singleEntryWithModules = inlinedModules.size === 1 && hasChunkModules;
1496
1497 // TODO:
1498 // This step is before the IIFE reason calculation. Ideally, it should only be executed when this function can optimize the
1499 // IIFE reason. Otherwise, it should directly return false. There are four reasons now, we have skipped two already, the left
1500 // one is 'it uses a non-standard name for the exports'.
1501 if (isMultipleEntries || innerStrict || !singleEntryWithModules) {
1502 return false;
1503 }
1504
1505 /** @type {Map<Module, Source>} */
1506 const renamedInlinedModules = new Map();
1507 const { runtimeTemplate } = renderContext;
1508
1509 /** @typedef {{ source: Source, module: Module, ast: any, variables: Set<Variable>, through: Set<Reference>, usedInNonInlined: Set<Variable>, moduleScope: Scope }} Info */
1510 /** @type {Map<Module, Info>} */
1511 const inlinedModulesToInfo = new Map();
1512 /** @type {Set<string>} */
1513 const nonInlinedModuleThroughIdentifiers = new Set();
1514 /** @type {Map<Module, Source>} */
1515
1516 for (const m of allModules) {
1517 const isInlinedModule = inlinedModules && inlinedModules.has(m);
1518 const moduleSource = this.renderModule(
1519 m,
1520 chunkRenderContext,
1521 hooks,
1522 !isInlinedModule
1523 );
1524
1525 if (!moduleSource) continue;
1526 const code = /** @type {string} */ (moduleSource.source());
1527 const ast = JavascriptParser._parse(code, {
1528 sourceType: "auto"
1529 });
1530
1531 const scopeManager = eslintScope.analyze(ast, {
1532 ecmaVersion: 6,
1533 sourceType: "module",
1534 optimistic: true,
1535 ignoreEval: true
1536 });
1537
1538 const globalScope = /** @type {Scope} */ (scopeManager.acquire(ast));
1539 if (inlinedModules && inlinedModules.has(m)) {
1540 const moduleScope = globalScope.childScopes[0];
1541 inlinedModulesToInfo.set(m, {
1542 source: moduleSource,
1543 ast,
1544 module: m,
1545 variables: new Set(moduleScope.variables),
1546 through: new Set(moduleScope.through),
1547 usedInNonInlined: new Set(),
1548 moduleScope
1549 });
1550 } else {
1551 for (const ref of globalScope.through) {
1552 nonInlinedModuleThroughIdentifiers.add(ref.identifier.name);
1553 }
1554 }
1555 }
1556
1557 for (const [, { variables, usedInNonInlined }] of inlinedModulesToInfo) {
1558 for (const variable of variables) {
1559 if (
1560 nonInlinedModuleThroughIdentifiers.has(variable.name) ||
1561 RESERVED_NAMES.has(variable.name)
1562 ) {
1563 usedInNonInlined.add(variable);
1564 }
1565 }
1566 }
1567
1568 for (const [m, moduleInfo] of inlinedModulesToInfo) {
1569 const { ast, source: _source, usedInNonInlined } = moduleInfo;
1570 const source = new ReplaceSource(_source);
1571 if (usedInNonInlined.size === 0) {
1572 renamedInlinedModules.set(m, source);
1573 continue;
1574 }
1575
1576 const info = /** @type {Info} */ (inlinedModulesToInfo.get(m));
1577 const allUsedNames = new Set(
1578 Array.from(info.through, v => v.identifier.name)
1579 );
1580
1581 for (const variable of usedInNonInlined) {
1582 allUsedNames.add(variable.name);
1583 }
1584
1585 for (const variable of info.variables) {
1586 allUsedNames.add(variable.name);
1587 const references = getAllReferences(variable);
1588 const allIdentifiers = new Set(
1589 references.map(r => r.identifier).concat(variable.identifiers)
1590 );
1591
1592 const usedNamesInScopeInfo = new Map();
1593 const ignoredScopes = new Set();
1594
1595 const name = variable.name;
1596 const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
1597 usedNamesInScopeInfo,
1598 info.module.identifier(),
1599 name
1600 );
1601
1602 if (allUsedNames.has(name) || usedNames.has(name)) {
1603 const references = getAllReferences(variable);
1604 for (const ref of references) {
1605 addScopeSymbols(
1606 ref.from,
1607 usedNames,
1608 alreadyCheckedScopes,
1609 ignoredScopes
1610 );
1611 }
1612
1613 const newName = findNewName(
1614 variable.name,
1615 allUsedNames,
1616 usedNames,
1617 m.readableIdentifier(runtimeTemplate.requestShortener)
1618 );
1619 allUsedNames.add(newName);
1620 for (const identifier of allIdentifiers) {
1621 const r = /** @type {Range} */ (identifier.range);
1622 const path = getPathInAst(ast, identifier);
1623 if (path && path.length > 1) {
1624 const maybeProperty =
1625 path[1].type === "AssignmentPattern" && path[1].left === path[0]
1626 ? path[2]
1627 : path[1];
1628 if (
1629 maybeProperty.type === "Property" &&
1630 maybeProperty.shorthand
1631 ) {
1632 source.insert(r[1], `: ${newName}`);
1633 continue;
1634 }
1635 }
1636 source.replace(r[0], r[1] - 1, newName);
1637 }
1638 } else {
1639 allUsedNames.add(name);
1640 }
1641 }
1642
1643 renamedInlinedModules.set(m, source);
1644 }
1645
1646 return renamedInlinedModules;
1647 }
1648}
1649
1650module.exports = JavascriptModulesPlugin;
1651module.exports.chunkHasJs = chunkHasJs;
Note: See TracBrowser for help on using the repository browser.