UNPKG

31.9 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const InitFragment = require("./InitFragment");
9const RuntimeGlobals = require("./RuntimeGlobals");
10const Template = require("./Template");
11const { equals } = require("./util/ArrayHelpers");
12const compileBooleanMatcher = require("./util/compileBooleanMatcher");
13const propertyAccess = require("./util/propertyAccess");
14const { forEachRuntime, subtractRuntime } = require("./util/runtime");
15
16/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
17/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
18/** @typedef {import("./ChunkGraph")} ChunkGraph */
19/** @typedef {import("./CodeGenerationResults")} CodeGenerationResults */
20/** @typedef {import("./Compilation")} Compilation */
21/** @typedef {import("./Dependency")} Dependency */
22/** @typedef {import("./Module")} Module */
23/** @typedef {import("./ModuleGraph")} ModuleGraph */
24/** @typedef {import("./RequestShortener")} RequestShortener */
25/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
26
27/**
28 * @param {Module} module the module
29 * @param {ChunkGraph} chunkGraph the chunk graph
30 * @returns {string} error message
31 */
32const noModuleIdErrorMessage = (module, chunkGraph) => {
33 return `Module ${module.identifier()} has no id assigned.
34This should not happen.
35It's in these chunks: ${
36 Array.from(
37 chunkGraph.getModuleChunksIterable(module),
38 c => c.name || c.id || c.debugId
39 ).join(", ") || "none"
40 } (If module is in no chunk this indicates a bug in some chunk/module optimization logic)
41Module has these incoming connections: ${Array.from(
42 chunkGraph.moduleGraph.getIncomingConnections(module),
43 connection =>
44 `\n - ${
45 connection.originModule && connection.originModule.identifier()
46 } ${connection.dependency && connection.dependency.type} ${
47 (connection.explanations &&
48 Array.from(connection.explanations).join(", ")) ||
49 ""
50 }`
51 ).join("")}`;
52};
53
54/**
55 * @param {string|undefined} definition global object definition
56 * @returns {string} save to use global object
57 */
58function getGlobalObject(definition) {
59 if (!definition) return definition;
60 const trimmed = definition.trim();
61
62 if (
63 // identifier, we do not need real identifier regarding ECMAScript/Unicode
64 trimmed.match(/^[_\p{L}][_0-9\p{L}]*$/iu) ||
65 // iife
66 // call expression
67 // expression in parentheses
68 trimmed.match(/^([_\p{L}][_0-9\p{L}]*)?\(.*\)$/iu)
69 )
70 return trimmed;
71
72 return `Object(${trimmed})`;
73}
74
75class RuntimeTemplate {
76 /**
77 * @param {Compilation} compilation the compilation
78 * @param {OutputOptions} outputOptions the compilation output options
79 * @param {RequestShortener} requestShortener the request shortener
80 */
81 constructor(compilation, outputOptions, requestShortener) {
82 this.compilation = compilation;
83 this.outputOptions = outputOptions || {};
84 this.requestShortener = requestShortener;
85 this.globalObject = getGlobalObject(outputOptions.globalObject);
86 this.contentHashReplacement = "X".repeat(outputOptions.hashDigestLength);
87 }
88
89 isIIFE() {
90 return this.outputOptions.iife;
91 }
92
93 isModule() {
94 return this.outputOptions.module;
95 }
96
97 supportsConst() {
98 return this.outputOptions.environment.const;
99 }
100
101 supportsArrowFunction() {
102 return this.outputOptions.environment.arrowFunction;
103 }
104
105 supportsOptionalChaining() {
106 return this.outputOptions.environment.optionalChaining;
107 }
108
109 supportsForOf() {
110 return this.outputOptions.environment.forOf;
111 }
112
113 supportsDestructuring() {
114 return this.outputOptions.environment.destructuring;
115 }
116
117 supportsBigIntLiteral() {
118 return this.outputOptions.environment.bigIntLiteral;
119 }
120
121 supportsDynamicImport() {
122 return this.outputOptions.environment.dynamicImport;
123 }
124
125 supportsEcmaScriptModuleSyntax() {
126 return this.outputOptions.environment.module;
127 }
128
129 supportTemplateLiteral() {
130 return this.outputOptions.environment.templateLiteral;
131 }
132
133 returningFunction(returnValue, args = "") {
134 return this.supportsArrowFunction()
135 ? `(${args}) => (${returnValue})`
136 : `function(${args}) { return ${returnValue}; }`;
137 }
138
139 basicFunction(args, body) {
140 return this.supportsArrowFunction()
141 ? `(${args}) => {\n${Template.indent(body)}\n}`
142 : `function(${args}) {\n${Template.indent(body)}\n}`;
143 }
144
145 /**
146 * @param {Array<string|{expr: string}>} args args
147 * @returns {string} result expression
148 */
149 concatenation(...args) {
150 const len = args.length;
151
152 if (len === 2) return this._es5Concatenation(args);
153 if (len === 0) return '""';
154 if (len === 1) {
155 return typeof args[0] === "string"
156 ? JSON.stringify(args[0])
157 : `"" + ${args[0].expr}`;
158 }
159 if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
160
161 // cost comparison between template literal and concatenation:
162 // both need equal surroundings: `xxx` vs "xxx"
163 // template literal has constant cost of 3 chars for each expression
164 // es5 concatenation has cost of 3 + n chars for n expressions in row
165 // when a es5 concatenation ends with an expression it reduces cost by 3
166 // when a es5 concatenation starts with an single expression it reduces cost by 3
167 // e. g. `${a}${b}${c}` (3*3 = 9) is longer than ""+a+b+c ((3+3)-3 = 3)
168 // e. g. `x${a}x${b}x${c}x` (3*3 = 9) is shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12)
169
170 let templateCost = 0;
171 let concatenationCost = 0;
172
173 let lastWasExpr = false;
174 for (const arg of args) {
175 const isExpr = typeof arg !== "string";
176 if (isExpr) {
177 templateCost += 3;
178 concatenationCost += lastWasExpr ? 1 : 4;
179 }
180 lastWasExpr = isExpr;
181 }
182 if (lastWasExpr) concatenationCost -= 3;
183 if (typeof args[0] !== "string" && typeof args[1] === "string")
184 concatenationCost -= 3;
185
186 if (concatenationCost <= templateCost) return this._es5Concatenation(args);
187
188 return `\`${args
189 .map(arg => (typeof arg === "string" ? arg : `\${${arg.expr}}`))
190 .join("")}\``;
191 }
192
193 /**
194 * @param {Array<string|{expr: string}>} args args (len >= 2)
195 * @returns {string} result expression
196 * @private
197 */
198 _es5Concatenation(args) {
199 const str = args
200 .map(arg => (typeof arg === "string" ? JSON.stringify(arg) : arg.expr))
201 .join(" + ");
202
203 // when the first two args are expression, we need to prepend "" + to force string
204 // concatenation instead of number addition.
205 return typeof args[0] !== "string" && typeof args[1] !== "string"
206 ? `"" + ${str}`
207 : str;
208 }
209
210 expressionFunction(expression, args = "") {
211 return this.supportsArrowFunction()
212 ? `(${args}) => (${expression})`
213 : `function(${args}) { ${expression}; }`;
214 }
215
216 emptyFunction() {
217 return this.supportsArrowFunction() ? "x => {}" : "function() {}";
218 }
219
220 destructureArray(items, value) {
221 return this.supportsDestructuring()
222 ? `var [${items.join(", ")}] = ${value};`
223 : Template.asString(
224 items.map((item, i) => `var ${item} = ${value}[${i}];`)
225 );
226 }
227
228 destructureObject(items, value) {
229 return this.supportsDestructuring()
230 ? `var {${items.join(", ")}} = ${value};`
231 : Template.asString(
232 items.map(item => `var ${item} = ${value}${propertyAccess([item])};`)
233 );
234 }
235
236 iife(args, body) {
237 return `(${this.basicFunction(args, body)})()`;
238 }
239
240 forEach(variable, array, body) {
241 return this.supportsForOf()
242 ? `for(const ${variable} of ${array}) {\n${Template.indent(body)}\n}`
243 : `${array}.forEach(function(${variable}) {\n${Template.indent(
244 body
245 )}\n});`;
246 }
247
248 /**
249 * Add a comment
250 * @param {object} options Information content of the comment
251 * @param {string=} options.request request string used originally
252 * @param {string=} options.chunkName name of the chunk referenced
253 * @param {string=} options.chunkReason reason information of the chunk
254 * @param {string=} options.message additional message
255 * @param {string=} options.exportName name of the export
256 * @returns {string} comment
257 */
258 comment({ request, chunkName, chunkReason, message, exportName }) {
259 let content;
260 if (this.outputOptions.pathinfo) {
261 content = [message, request, chunkName, chunkReason]
262 .filter(Boolean)
263 .map(item => this.requestShortener.shorten(item))
264 .join(" | ");
265 } else {
266 content = [message, chunkName, chunkReason]
267 .filter(Boolean)
268 .map(item => this.requestShortener.shorten(item))
269 .join(" | ");
270 }
271 if (!content) return "";
272 if (this.outputOptions.pathinfo) {
273 return Template.toComment(content) + " ";
274 } else {
275 return Template.toNormalComment(content) + " ";
276 }
277 }
278
279 /**
280 * @param {object} options generation options
281 * @param {string=} options.request request string used originally
282 * @returns {string} generated error block
283 */
284 throwMissingModuleErrorBlock({ request }) {
285 const err = `Cannot find module '${request}'`;
286 return `var e = new Error(${JSON.stringify(
287 err
288 )}); e.code = 'MODULE_NOT_FOUND'; throw e;`;
289 }
290
291 /**
292 * @param {object} options generation options
293 * @param {string=} options.request request string used originally
294 * @returns {string} generated error function
295 */
296 throwMissingModuleErrorFunction({ request }) {
297 return `function webpackMissingModule() { ${this.throwMissingModuleErrorBlock(
298 { request }
299 )} }`;
300 }
301
302 /**
303 * @param {object} options generation options
304 * @param {string=} options.request request string used originally
305 * @returns {string} generated error IIFE
306 */
307 missingModule({ request }) {
308 return `Object(${this.throwMissingModuleErrorFunction({ request })}())`;
309 }
310
311 /**
312 * @param {object} options generation options
313 * @param {string=} options.request request string used originally
314 * @returns {string} generated error statement
315 */
316 missingModuleStatement({ request }) {
317 return `${this.missingModule({ request })};\n`;
318 }
319
320 /**
321 * @param {object} options generation options
322 * @param {string=} options.request request string used originally
323 * @returns {string} generated error code
324 */
325 missingModulePromise({ request }) {
326 return `Promise.resolve().then(${this.throwMissingModuleErrorFunction({
327 request
328 })})`;
329 }
330
331 /**
332 * @param {Object} options options object
333 * @param {ChunkGraph} options.chunkGraph the chunk graph
334 * @param {Module} options.module the module
335 * @param {string} options.request the request that should be printed as comment
336 * @param {string=} options.idExpr expression to use as id expression
337 * @param {"expression" | "promise" | "statements"} options.type which kind of code should be returned
338 * @returns {string} the code
339 */
340 weakError({ module, chunkGraph, request, idExpr, type }) {
341 const moduleId = chunkGraph.getModuleId(module);
342 const errorMessage =
343 moduleId === null
344 ? JSON.stringify("Module is not available (weak dependency)")
345 : idExpr
346 ? `"Module '" + ${idExpr} + "' is not available (weak dependency)"`
347 : JSON.stringify(
348 `Module '${moduleId}' is not available (weak dependency)`
349 );
350 const comment = request ? Template.toNormalComment(request) + " " : "";
351 const errorStatements =
352 `var e = new Error(${errorMessage}); ` +
353 comment +
354 "e.code = 'MODULE_NOT_FOUND'; throw e;";
355 switch (type) {
356 case "statements":
357 return errorStatements;
358 case "promise":
359 return `Promise.resolve().then(${this.basicFunction(
360 "",
361 errorStatements
362 )})`;
363 case "expression":
364 return this.iife("", errorStatements);
365 }
366 }
367
368 /**
369 * @param {Object} options options object
370 * @param {Module} options.module the module
371 * @param {ChunkGraph} options.chunkGraph the chunk graph
372 * @param {string} options.request the request that should be printed as comment
373 * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
374 * @returns {string} the expression
375 */
376 moduleId({ module, chunkGraph, request, weak }) {
377 if (!module) {
378 return this.missingModule({
379 request
380 });
381 }
382 const moduleId = chunkGraph.getModuleId(module);
383 if (moduleId === null) {
384 if (weak) {
385 return "null /* weak dependency, without id */";
386 }
387 throw new Error(
388 `RuntimeTemplate.moduleId(): ${noModuleIdErrorMessage(
389 module,
390 chunkGraph
391 )}`
392 );
393 }
394 return `${this.comment({ request })}${JSON.stringify(moduleId)}`;
395 }
396
397 /**
398 * @param {Object} options options object
399 * @param {Module} options.module the module
400 * @param {ChunkGraph} options.chunkGraph the chunk graph
401 * @param {string} options.request the request that should be printed as comment
402 * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
403 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
404 * @returns {string} the expression
405 */
406 moduleRaw({ module, chunkGraph, request, weak, runtimeRequirements }) {
407 if (!module) {
408 return this.missingModule({
409 request
410 });
411 }
412 const moduleId = chunkGraph.getModuleId(module);
413 if (moduleId === null) {
414 if (weak) {
415 // only weak referenced modules don't get an id
416 // we can always emit an error emitting code here
417 return this.weakError({
418 module,
419 chunkGraph,
420 request,
421 type: "expression"
422 });
423 }
424 throw new Error(
425 `RuntimeTemplate.moduleId(): ${noModuleIdErrorMessage(
426 module,
427 chunkGraph
428 )}`
429 );
430 }
431 runtimeRequirements.add(RuntimeGlobals.require);
432 return `__webpack_require__(${this.moduleId({
433 module,
434 chunkGraph,
435 request,
436 weak
437 })})`;
438 }
439
440 /**
441 * @param {Object} options options object
442 * @param {Module} options.module the module
443 * @param {ChunkGraph} options.chunkGraph the chunk graph
444 * @param {string} options.request the request that should be printed as comment
445 * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
446 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
447 * @returns {string} the expression
448 */
449 moduleExports({ module, chunkGraph, request, weak, runtimeRequirements }) {
450 return this.moduleRaw({
451 module,
452 chunkGraph,
453 request,
454 weak,
455 runtimeRequirements
456 });
457 }
458
459 /**
460 * @param {Object} options options object
461 * @param {Module} options.module the module
462 * @param {ChunkGraph} options.chunkGraph the chunk graph
463 * @param {string} options.request the request that should be printed as comment
464 * @param {boolean=} options.strict if the current module is in strict esm mode
465 * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
466 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
467 * @returns {string} the expression
468 */
469 moduleNamespace({
470 module,
471 chunkGraph,
472 request,
473 strict,
474 weak,
475 runtimeRequirements
476 }) {
477 if (!module) {
478 return this.missingModule({
479 request
480 });
481 }
482 if (chunkGraph.getModuleId(module) === null) {
483 if (weak) {
484 // only weak referenced modules don't get an id
485 // we can always emit an error emitting code here
486 return this.weakError({
487 module,
488 chunkGraph,
489 request,
490 type: "expression"
491 });
492 }
493 throw new Error(
494 `RuntimeTemplate.moduleNamespace(): ${noModuleIdErrorMessage(
495 module,
496 chunkGraph
497 )}`
498 );
499 }
500 const moduleId = this.moduleId({
501 module,
502 chunkGraph,
503 request,
504 weak
505 });
506 const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
507 switch (exportsType) {
508 case "namespace":
509 return this.moduleRaw({
510 module,
511 chunkGraph,
512 request,
513 weak,
514 runtimeRequirements
515 });
516 case "default-with-named":
517 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
518 return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`;
519 case "default-only":
520 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
521 return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 1)`;
522 case "dynamic":
523 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
524 return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 7)`;
525 }
526 }
527
528 /**
529 * @param {Object} options options object
530 * @param {ChunkGraph} options.chunkGraph the chunk graph
531 * @param {AsyncDependenciesBlock=} options.block the current dependencies block
532 * @param {Module} options.module the module
533 * @param {string} options.request the request that should be printed as comment
534 * @param {string} options.message a message for the comment
535 * @param {boolean=} options.strict if the current module is in strict esm mode
536 * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
537 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
538 * @returns {string} the promise expression
539 */
540 moduleNamespacePromise({
541 chunkGraph,
542 block,
543 module,
544 request,
545 message,
546 strict,
547 weak,
548 runtimeRequirements
549 }) {
550 if (!module) {
551 return this.missingModulePromise({
552 request
553 });
554 }
555 const moduleId = chunkGraph.getModuleId(module);
556 if (moduleId === null) {
557 if (weak) {
558 // only weak referenced modules don't get an id
559 // we can always emit an error emitting code here
560 return this.weakError({
561 module,
562 chunkGraph,
563 request,
564 type: "promise"
565 });
566 }
567 throw new Error(
568 `RuntimeTemplate.moduleNamespacePromise(): ${noModuleIdErrorMessage(
569 module,
570 chunkGraph
571 )}`
572 );
573 }
574 const promise = this.blockPromise({
575 chunkGraph,
576 block,
577 message,
578 runtimeRequirements
579 });
580
581 let appending;
582 let idExpr = JSON.stringify(chunkGraph.getModuleId(module));
583 const comment = this.comment({
584 request
585 });
586 let header = "";
587 if (weak) {
588 if (idExpr.length > 8) {
589 // 'var x="nnnnnn";x,"+x+",x' vs '"nnnnnn",nnnnnn,"nnnnnn"'
590 header += `var id = ${idExpr}; `;
591 idExpr = "id";
592 }
593 runtimeRequirements.add(RuntimeGlobals.moduleFactories);
594 header += `if(!${
595 RuntimeGlobals.moduleFactories
596 }[${idExpr}]) { ${this.weakError({
597 module,
598 chunkGraph,
599 request,
600 idExpr,
601 type: "statements"
602 })} } `;
603 }
604 const moduleIdExpr = this.moduleId({
605 module,
606 chunkGraph,
607 request,
608 weak
609 });
610 const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
611 let fakeType = 16;
612 switch (exportsType) {
613 case "namespace":
614 if (header) {
615 const rawModule = this.moduleRaw({
616 module,
617 chunkGraph,
618 request,
619 weak,
620 runtimeRequirements
621 });
622 appending = `.then(${this.basicFunction(
623 "",
624 `${header}return ${rawModule};`
625 )})`;
626 } else {
627 runtimeRequirements.add(RuntimeGlobals.require);
628 appending = `.then(__webpack_require__.bind(__webpack_require__, ${comment}${idExpr}))`;
629 }
630 break;
631 case "dynamic":
632 fakeType |= 4;
633 /* fall through */
634 case "default-with-named":
635 fakeType |= 2;
636 /* fall through */
637 case "default-only":
638 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
639 if (chunkGraph.moduleGraph.isAsync(module)) {
640 if (header) {
641 const rawModule = this.moduleRaw({
642 module,
643 chunkGraph,
644 request,
645 weak,
646 runtimeRequirements
647 });
648 appending = `.then(${this.basicFunction(
649 "",
650 `${header}return ${rawModule};`
651 )})`;
652 } else {
653 runtimeRequirements.add(RuntimeGlobals.require);
654 appending = `.then(__webpack_require__.bind(__webpack_require__, ${comment}${idExpr}))`;
655 }
656 appending += `.then(${this.returningFunction(
657 `${RuntimeGlobals.createFakeNamespaceObject}(m, ${fakeType})`,
658 "m"
659 )})`;
660 } else {
661 fakeType |= 1;
662 if (header) {
663 const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, ${fakeType})`;
664 appending = `.then(${this.basicFunction(
665 "",
666 `${header}return ${returnExpression};`
667 )})`;
668 } else {
669 appending = `.then(${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, ${fakeType}))`;
670 }
671 }
672 break;
673 }
674
675 return `${promise || "Promise.resolve()"}${appending}`;
676 }
677
678 /**
679 * @param {Object} options options object
680 * @param {ChunkGraph} options.chunkGraph the chunk graph
681 * @param {RuntimeSpec=} options.runtime runtime for which this code will be generated
682 * @param {RuntimeSpec | boolean=} options.runtimeCondition only execute the statement in some runtimes
683 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
684 * @returns {string} expression
685 */
686 runtimeConditionExpression({
687 chunkGraph,
688 runtimeCondition,
689 runtime,
690 runtimeRequirements
691 }) {
692 if (runtimeCondition === undefined) return "true";
693 if (typeof runtimeCondition === "boolean") return `${runtimeCondition}`;
694 /** @type {Set<string>} */
695 const positiveRuntimeIds = new Set();
696 forEachRuntime(runtimeCondition, runtime =>
697 positiveRuntimeIds.add(`${chunkGraph.getRuntimeId(runtime)}`)
698 );
699 /** @type {Set<string>} */
700 const negativeRuntimeIds = new Set();
701 forEachRuntime(subtractRuntime(runtime, runtimeCondition), runtime =>
702 negativeRuntimeIds.add(`${chunkGraph.getRuntimeId(runtime)}`)
703 );
704 runtimeRequirements.add(RuntimeGlobals.runtimeId);
705 return compileBooleanMatcher.fromLists(
706 Array.from(positiveRuntimeIds),
707 Array.from(negativeRuntimeIds)
708 )(RuntimeGlobals.runtimeId);
709 }
710
711 /**
712 *
713 * @param {Object} options options object
714 * @param {boolean=} options.update whether a new variable should be created or the existing one updated
715 * @param {Module} options.module the module
716 * @param {ChunkGraph} options.chunkGraph the chunk graph
717 * @param {string} options.request the request that should be printed as comment
718 * @param {string} options.importVar name of the import variable
719 * @param {Module} options.originModule module in which the statement is emitted
720 * @param {boolean=} options.weak true, if this is a weak dependency
721 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
722 * @returns {[string, string]} the import statement and the compat statement
723 */
724 importStatement({
725 update,
726 module,
727 chunkGraph,
728 request,
729 importVar,
730 originModule,
731 weak,
732 runtimeRequirements
733 }) {
734 if (!module) {
735 return [
736 this.missingModuleStatement({
737 request
738 }),
739 ""
740 ];
741 }
742 if (chunkGraph.getModuleId(module) === null) {
743 if (weak) {
744 // only weak referenced modules don't get an id
745 // we can always emit an error emitting code here
746 return [
747 this.weakError({
748 module,
749 chunkGraph,
750 request,
751 type: "statements"
752 }),
753 ""
754 ];
755 }
756 throw new Error(
757 `RuntimeTemplate.importStatement(): ${noModuleIdErrorMessage(
758 module,
759 chunkGraph
760 )}`
761 );
762 }
763 const moduleId = this.moduleId({
764 module,
765 chunkGraph,
766 request,
767 weak
768 });
769 const optDeclaration = update ? "" : "var ";
770
771 const exportsType = module.getExportsType(
772 chunkGraph.moduleGraph,
773 originModule.buildMeta.strictHarmonyModule
774 );
775 runtimeRequirements.add(RuntimeGlobals.require);
776 const importContent = `/* harmony import */ ${optDeclaration}${importVar} = __webpack_require__(${moduleId});\n`;
777
778 if (exportsType === "dynamic") {
779 runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
780 return [
781 importContent,
782 `/* harmony import */ ${optDeclaration}${importVar}_default = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${importVar});\n`
783 ];
784 }
785 return [importContent, ""];
786 }
787
788 /**
789 * @param {Object} options options
790 * @param {ModuleGraph} options.moduleGraph the module graph
791 * @param {Module} options.module the module
792 * @param {string} options.request the request
793 * @param {string | string[]} options.exportName the export name
794 * @param {Module} options.originModule the origin module
795 * @param {boolean|undefined} options.asiSafe true, if location is safe for ASI, a bracket can be emitted
796 * @param {boolean} options.isCall true, if expression will be called
797 * @param {boolean} options.callContext when false, call context will not be preserved
798 * @param {boolean} options.defaultInterop when true and accessing the default exports, interop code will be generated
799 * @param {string} options.importVar the identifier name of the import variable
800 * @param {InitFragment[]} options.initFragments init fragments will be added here
801 * @param {RuntimeSpec} options.runtime runtime for which this code will be generated
802 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
803 * @returns {string} expression
804 */
805 exportFromImport({
806 moduleGraph,
807 module,
808 request,
809 exportName,
810 originModule,
811 asiSafe,
812 isCall,
813 callContext,
814 defaultInterop,
815 importVar,
816 initFragments,
817 runtime,
818 runtimeRequirements
819 }) {
820 if (!module) {
821 return this.missingModule({
822 request
823 });
824 }
825 if (!Array.isArray(exportName)) {
826 exportName = exportName ? [exportName] : [];
827 }
828 const exportsType = module.getExportsType(
829 moduleGraph,
830 originModule.buildMeta.strictHarmonyModule
831 );
832
833 if (defaultInterop) {
834 if (exportName.length > 0 && exportName[0] === "default") {
835 switch (exportsType) {
836 case "dynamic":
837 if (isCall) {
838 return `${importVar}_default()${propertyAccess(exportName, 1)}`;
839 } else {
840 return asiSafe
841 ? `(${importVar}_default()${propertyAccess(exportName, 1)})`
842 : asiSafe === false
843 ? `;(${importVar}_default()${propertyAccess(exportName, 1)})`
844 : `${importVar}_default.a${propertyAccess(exportName, 1)}`;
845 }
846 case "default-only":
847 case "default-with-named":
848 exportName = exportName.slice(1);
849 break;
850 }
851 } else if (exportName.length > 0) {
852 if (exportsType === "default-only") {
853 return (
854 "/* non-default import from non-esm module */undefined" +
855 propertyAccess(exportName, 1)
856 );
857 } else if (
858 exportsType !== "namespace" &&
859 exportName[0] === "__esModule"
860 ) {
861 return "/* __esModule */true";
862 }
863 } else if (
864 exportsType === "default-only" ||
865 exportsType === "default-with-named"
866 ) {
867 runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
868 initFragments.push(
869 new InitFragment(
870 `var ${importVar}_namespace_cache;\n`,
871 InitFragment.STAGE_CONSTANTS,
872 -1,
873 `${importVar}_namespace_cache`
874 )
875 );
876 return `/*#__PURE__*/ ${
877 asiSafe ? "" : asiSafe === false ? ";" : "Object"
878 }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${
879 RuntimeGlobals.createFakeNamespaceObject
880 }(${importVar}${exportsType === "default-only" ? "" : ", 2"})))`;
881 }
882 }
883
884 if (exportName.length > 0) {
885 const exportsInfo = moduleGraph.getExportsInfo(module);
886 const used = exportsInfo.getUsedName(exportName, runtime);
887 if (!used) {
888 const comment = Template.toNormalComment(
889 `unused export ${propertyAccess(exportName)}`
890 );
891 return `${comment} undefined`;
892 }
893 const comment = equals(used, exportName)
894 ? ""
895 : Template.toNormalComment(propertyAccess(exportName)) + " ";
896 const access = `${importVar}${comment}${propertyAccess(used)}`;
897 if (isCall && callContext === false) {
898 return asiSafe
899 ? `(0,${access})`
900 : asiSafe === false
901 ? `;(0,${access})`
902 : `/*#__PURE__*/Object(${access})`;
903 }
904 return access;
905 } else {
906 return importVar;
907 }
908 }
909
910 /**
911 * @param {Object} options options
912 * @param {AsyncDependenciesBlock} options.block the async block
913 * @param {string} options.message the message
914 * @param {ChunkGraph} options.chunkGraph the chunk graph
915 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
916 * @returns {string} expression
917 */
918 blockPromise({ block, message, chunkGraph, runtimeRequirements }) {
919 if (!block) {
920 const comment = this.comment({
921 message
922 });
923 return `Promise.resolve(${comment.trim()})`;
924 }
925 const chunkGroup = chunkGraph.getBlockChunkGroup(block);
926 if (!chunkGroup || chunkGroup.chunks.length === 0) {
927 const comment = this.comment({
928 message
929 });
930 return `Promise.resolve(${comment.trim()})`;
931 }
932 const chunks = chunkGroup.chunks.filter(
933 chunk => !chunk.hasRuntime() && chunk.id !== null
934 );
935 const comment = this.comment({
936 message,
937 chunkName: block.chunkName
938 });
939 if (chunks.length === 1) {
940 const chunkId = JSON.stringify(chunks[0].id);
941 runtimeRequirements.add(RuntimeGlobals.ensureChunk);
942 return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId})`;
943 } else if (chunks.length > 0) {
944 runtimeRequirements.add(RuntimeGlobals.ensureChunk);
945 const requireChunkId = chunk =>
946 `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)})`;
947 return `Promise.all(${comment.trim()}[${chunks
948 .map(requireChunkId)
949 .join(", ")}])`;
950 } else {
951 return `Promise.resolve(${comment.trim()})`;
952 }
953 }
954
955 /**
956 * @param {Object} options options
957 * @param {AsyncDependenciesBlock} options.block the async block
958 * @param {ChunkGraph} options.chunkGraph the chunk graph
959 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
960 * @param {string=} options.request request string used originally
961 * @returns {string} expression
962 */
963 asyncModuleFactory({ block, chunkGraph, runtimeRequirements, request }) {
964 const dep = block.dependencies[0];
965 const module = chunkGraph.moduleGraph.getModule(dep);
966 const ensureChunk = this.blockPromise({
967 block,
968 message: "",
969 chunkGraph,
970 runtimeRequirements
971 });
972 const factory = this.returningFunction(
973 this.moduleRaw({
974 module,
975 chunkGraph,
976 request,
977 runtimeRequirements
978 })
979 );
980 return this.returningFunction(
981 ensureChunk.startsWith("Promise.resolve(")
982 ? `${factory}`
983 : `${ensureChunk}.then(${this.returningFunction(factory)})`
984 );
985 }
986
987 /**
988 * @param {Object} options options
989 * @param {Dependency} options.dependency the dependency
990 * @param {ChunkGraph} options.chunkGraph the chunk graph
991 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
992 * @param {string=} options.request request string used originally
993 * @returns {string} expression
994 */
995 syncModuleFactory({ dependency, chunkGraph, runtimeRequirements, request }) {
996 const module = chunkGraph.moduleGraph.getModule(dependency);
997 const factory = this.returningFunction(
998 this.moduleRaw({
999 module,
1000 chunkGraph,
1001 request,
1002 runtimeRequirements
1003 })
1004 );
1005 return this.returningFunction(factory);
1006 }
1007
1008 /**
1009 * @param {Object} options options
1010 * @param {string} options.exportsArgument the name of the exports object
1011 * @param {Set<string>} options.runtimeRequirements if set, will be filled with runtime requirements
1012 * @returns {string} statement
1013 */
1014 defineEsModuleFlagStatement({ exportsArgument, runtimeRequirements }) {
1015 runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
1016 runtimeRequirements.add(RuntimeGlobals.exports);
1017 return `${RuntimeGlobals.makeNamespaceObject}(${exportsArgument});\n`;
1018 }
1019
1020 /**
1021 * @param {Object} options options object
1022 * @param {Module} options.module the module
1023 * @param {string} options.publicPath the public path
1024 * @param {RuntimeSpec=} options.runtime runtime
1025 * @param {CodeGenerationResults} options.codeGenerationResults the code generation results
1026 * @returns {string} the url of the asset
1027 */
1028 assetUrl({ publicPath, runtime, module, codeGenerationResults }) {
1029 if (!module) {
1030 return "data:,";
1031 }
1032 const codeGen = codeGenerationResults.get(module, runtime);
1033 const { data } = codeGen;
1034 const url = data.get("url");
1035 if (url) return url.toString();
1036 const filename = data.get("filename");
1037 return publicPath + filename;
1038 }
1039}
1040
1041module.exports = RuntimeTemplate;