UNPKG

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