/* 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;