123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- */
- "use strict";
- const RuntimeGlobals = require("../RuntimeGlobals");
- const Template = require("../Template");
- const HelperRuntimeModule = require("./HelperRuntimeModule");
- /**
- * @param {import("../Module").ExportsType} exportsType exports type
- * @returns {string} mode
- */
- function getMakeDeferredNamespaceModeFromExportsType(exportsType) {
- if (exportsType === "namespace") return `/* ${exportsType} */ 0`;
- if (exportsType === "default-only") return `/* ${exportsType} */ 1`;
- if (exportsType === "default-with-named") return `/* ${exportsType} */ 2`;
- if (exportsType === "dynamic") return `/* ${exportsType} */ 3`;
- return "";
- }
- /**
- * @param {import("../ModuleTemplate").RuntimeTemplate} _runtimeTemplate runtimeTemplate
- * @param {import("../Module").ExportsType} exportsType exportsType
- * @param {string} moduleId moduleId
- * @param {(import("../ChunkGraph").ModuleId | null)[]} asyncDepsIds asyncDepsIds
- * @returns {string} function
- */
- function getOptimizedDeferredModule(
- _runtimeTemplate,
- exportsType,
- moduleId,
- asyncDepsIds
- ) {
- const isAsync = asyncDepsIds && asyncDepsIds.length;
- const init = `${RuntimeGlobals.require}(${moduleId})${
- isAsync ? `[${RuntimeGlobals.asyncModuleExportSymbol}]` : ""
- }`;
- const props = [
- `/* ${exportsType} */ get a() {`,
- // if exportsType is "namespace" we can generate the most optimized code,
- // on the second access, we can avoid trigger the getter.
- // we can also do this if exportsType is "dynamic" and there is a "__esModule" property on it.
- exportsType === "namespace" || exportsType === "dynamic"
- ? Template.indent([
- `var exports = ${init};`,
- `${
- exportsType === "dynamic" ? "if (exports.__esModule) " : ""
- }Object.defineProperty(this, "a", { value: exports });`,
- "return exports;"
- ])
- : Template.indent([`return ${init};`]),
- isAsync ? "}," : "}",
- isAsync
- ? `[${
- RuntimeGlobals.makeDeferredNamespaceObjectSymbol
- }]: ${JSON.stringify(asyncDepsIds.filter(x => x !== null))}`
- : ""
- ];
- return Template.asString(["{", Template.indent(props), "}"]);
- }
- const strictModuleCache = [
- "if (cachedModule && cachedModule.error === undefined) {",
- Template.indent([
- "var exports = cachedModule.exports;",
- "if (mode == 0) return exports;",
- `if (mode == 1) return ${RuntimeGlobals.createFakeNamespaceObject}(exports);`,
- `if (mode == 2) return ${RuntimeGlobals.createFakeNamespaceObject}(exports, 2);`,
- `if (mode == 3) return ${RuntimeGlobals.createFakeNamespaceObject}(exports, 6);` // 2 | 4
- ]),
- "}"
- ];
- const nonStrictModuleCache = [
- "// optimization not applied when output.strictModuleErrorHandling is off"
- ];
- class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
- /**
- * @param {boolean} hasAsyncRuntime if async module is used.
- */
- constructor(hasAsyncRuntime) {
- super("make deferred namespace object");
- this.hasAsyncRuntime = hasAsyncRuntime;
- }
- /**
- * @returns {string | null} runtime code
- */
- generate() {
- if (!this.compilation) return null;
- const { runtimeTemplate } = this.compilation;
- const fn = RuntimeGlobals.makeDeferredNamespaceObject;
- const hasAsync = this.hasAsyncRuntime;
- const strictError =
- this.compilation.options.output.strictModuleErrorHandling;
- const init = runtimeTemplate.supportsOptionalChaining()
- ? "init?.();"
- : "if (init) init();";
- return `${fn} = ${runtimeTemplate.basicFunction("moduleId, mode", [
- "// mode: 0 => namespace (esm)",
- "// mode: 1 => default-only (esm strict cjs)",
- "// mode: 2 => default-with-named (esm-cjs compat)",
- "// mode: 3 => dynamic (if exports has __esModule, then esm, otherwise default-with-named)",
- "",
- "var cachedModule = __webpack_module_cache__[moduleId];",
- ...(strictError ? strictModuleCache : nonStrictModuleCache),
- "",
- `var init = ${runtimeTemplate.basicFunction("", [
- `ns = ${RuntimeGlobals.require}(moduleId);`,
- hasAsync
- ? `if (${RuntimeGlobals.asyncModuleExportSymbol} in ns) ns = ns[${RuntimeGlobals.asyncModuleExportSymbol}];`
- : "",
- "init = null;",
- "if (mode == 0 || mode == 3 && ns.__esModule && typeof ns === 'object') {",
- Template.indent([
- "delete handler.defineProperty;",
- "delete handler.deleteProperty;",
- "delete handler.set;",
- "delete handler.get;",
- "delete handler.has;",
- "delete handler.ownKeys;",
- "delete handler.getOwnPropertyDescriptor;"
- ]),
- "} else if (mode == 1) {",
- Template.indent([
- `ns = ${RuntimeGlobals.createFakeNamespaceObject}(ns);`
- ]),
- "} else if (mode == 2) {",
- Template.indent([
- `ns = ${RuntimeGlobals.createFakeNamespaceObject}(ns, 2);`
- ]),
- "} else if (mode == 3) {",
- Template.indent([
- `ns = ${RuntimeGlobals.createFakeNamespaceObject}(ns, 6);`
- ]),
- "}"
- ])};`,
- "",
- `var ns = ${
- strictError ? "" : "cachedModule && cachedModule.exports || "
- }__webpack_module_deferred_exports__[moduleId] || (__webpack_module_deferred_exports__[moduleId] = { __proto__: null });`,
- "var handler = {",
- Template.indent([
- "__proto__: null,",
- `get: ${runtimeTemplate.basicFunction("_, name", [
- "switch (name) {",
- Template.indent([
- 'case "__esModule": return true;',
- 'case Symbol.toStringTag: return "Deferred Module";',
- 'case "then": return undefined;'
- ]),
- "}",
- init,
- "return ns[name];"
- ])},`,
- `has: ${runtimeTemplate.basicFunction("_, name", [
- "switch (name) {",
- Template.indent(
- [
- 'case "__esModule":',
- "case Symbol.toStringTag:",
- hasAsync
- ? `case ${RuntimeGlobals.makeDeferredNamespaceObjectSymbol}:`
- : "",
- Template.indent("return true;"),
- 'case "then":',
- Template.indent("return false;")
- ].filter(Boolean)
- ),
- "}",
- init,
- "return name in ns;"
- ])},`,
- `ownKeys: ${runtimeTemplate.basicFunction("", [
- init,
- `var keys = Reflect.ownKeys(ns).filter(${runtimeTemplate.expressionFunction('x !== "then"', "x")}).concat([Symbol.toStringTag]);`,
- "return keys;"
- ])},`,
- `getOwnPropertyDescriptor: ${runtimeTemplate.basicFunction("_, name", [
- "switch (name) {",
- Template.indent([
- 'case "__esModule": return { value: true, configurable: !!mode };',
- 'case Symbol.toStringTag: return { value: "Deferred Module", configurable: !!mode };',
- 'case "then": return undefined;'
- ]),
- "}",
- init,
- "var desc = Reflect.getOwnPropertyDescriptor(ns, name);",
- 'if (mode == 2 && name == "default" && !desc) {',
- Template.indent("desc = { value: ns, configurable: true };"),
- "}",
- "return desc;"
- ])},`,
- `defineProperty: ${runtimeTemplate.basicFunction("_, name", [
- init,
- // Note: This behavior does not match the spec one, but since webpack does not do it either
- // for a normal Module Namespace object (in MakeNamespaceObjectRuntimeModule), let's keep it simple.
- "return false;"
- ])},`,
- `deleteProperty: ${runtimeTemplate.returningFunction("false")},`,
- `set: ${runtimeTemplate.returningFunction("false")},`
- ]),
- "}",
- // we don't fully emulate ES Module semantics in this Proxy to align with normal webpack esm namespace object.
- "return new Proxy(ns, handler);"
- ])};`;
- }
- }
- module.exports = MakeDeferredNamespaceObjectRuntimeModule;
- module.exports.getMakeDeferredNamespaceModeFromExportsType =
- getMakeDeferredNamespaceModeFromExportsType;
- module.exports.getOptimizedDeferredModule = getOptimizedDeferredModule;
|