source: frontend/node_modules/webpack/lib/runtime/MakeDeferredNamespaceObjectRuntime.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const RuntimeGlobals = require("../RuntimeGlobals");
8const Template = require("../Template");
9const HelperRuntimeModule = require("./HelperRuntimeModule");
10
11/** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
12/** @typedef {import("../Module").ExportsType} ExportsType */
13/** @typedef {import("../ChunkGraph").ModuleId} ModuleId */
14
15/**
16 * @param {ExportsType} exportsType exports type
17 * @returns {string} mode
18 */
19function getMakeDeferredNamespaceModeFromExportsType(exportsType) {
20 // number is from createFakeNamespaceObject mode ^ 1
21 if (exportsType === "namespace") return `/* ${exportsType} */ 8`;
22 if (exportsType === "default-only") return `/* ${exportsType} */ 0`;
23 if (exportsType === "default-with-named") return `/* ${exportsType} */ 2`;
24 if (exportsType === "dynamic") return `/* ${exportsType} */ 6`;
25 throw new Error(`Unknown exports type: ${exportsType}`);
26}
27
28/**
29 * @param {string} moduleId moduleId
30 * @param {ExportsType} exportsType exportsType
31 * @param {(ModuleId | null)[]} asyncDepsIds asyncDepsIds
32 * @param {RuntimeRequirements} runtimeRequirements runtime requirements
33 * @returns {string} call make optimized deferred namespace object
34 */
35function getOptimizedDeferredModule(
36 moduleId,
37 exportsType,
38 asyncDepsIds,
39 runtimeRequirements
40) {
41 runtimeRequirements.add(RuntimeGlobals.makeOptimizedDeferredNamespaceObject);
42 const mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
43 return `${RuntimeGlobals.makeOptimizedDeferredNamespaceObject}(${moduleId}, ${mode}${
44 asyncDepsIds.length > 0
45 ? `, ${JSON.stringify(asyncDepsIds.filter((x) => x !== null))}`
46 : ""
47 })`;
48}
49
50class MakeOptimizedDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
51 /**
52 * @param {boolean} hasAsyncRuntime if async module is used.
53 */
54 constructor(hasAsyncRuntime) {
55 super("make optimized deferred namespace object");
56 /** @type {boolean} */
57 this.hasAsyncRuntime = hasAsyncRuntime;
58 }
59
60 /**
61 * Generates runtime code for this runtime module.
62 * @returns {string | null} runtime code
63 */
64 generate() {
65 if (!this.compilation) return null;
66 const fn = RuntimeGlobals.makeOptimizedDeferredNamespaceObject;
67 const hasAsync = this.hasAsyncRuntime;
68 return Template.asString([
69 // Note: must be a function (not arrow), because this is used in body!
70 `${fn} = function(moduleId, mode${hasAsync ? ", asyncDeps" : ""}) {`,
71 Template.indent([
72 "var r = this;",
73 hasAsync ? "var isAsync = asyncDeps && asyncDeps.length;" : "",
74 "var obj = {",
75 Template.indent([
76 "get a() {",
77 Template.indent([
78 "var exports = r(moduleId);",
79 hasAsync
80 ? `if(isAsync) exports = exports[${RuntimeGlobals.asyncModuleExportSymbol}];`
81 : "",
82 // if exportsType is "namespace" we can generate the most optimized code,
83 // on the second access, we can avoid trigger the getter.
84 // we can also do this if exportsType is "dynamic" and there is a "__esModule" property on it.
85 'if(mode & 8 || (mode & 4 && exports.__esModule)) Object.defineProperty(this, "a", { value: exports });',
86 "return exports;"
87 ]),
88 "}"
89 ]),
90 "};",
91 hasAsync
92 ? `if(isAsync) obj[${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol}] = asyncDeps;`
93 : "",
94 "return obj;"
95 ]),
96 "};"
97 ]);
98 }
99}
100
101class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
102 /**
103 * @param {boolean} hasAsyncRuntime if async module is used.
104 */
105 constructor(hasAsyncRuntime) {
106 super("make deferred namespace object");
107 /** @type {boolean} */
108 this.hasAsyncRuntime = hasAsyncRuntime;
109 }
110
111 /**
112 * Generates runtime code for this runtime module.
113 * @returns {string | null} runtime code
114 */
115 generate() {
116 if (!this.compilation) return null;
117 const { runtimeTemplate } = this.compilation;
118 const fn = RuntimeGlobals.makeDeferredNamespaceObject;
119 const hasAsync = this.hasAsyncRuntime;
120 const init = runtimeTemplate.supportsOptionalChaining()
121 ? "init?.();"
122 : "if (init) init();";
123 return `${fn} = ${runtimeTemplate.basicFunction("moduleId, mode", [
124 // Per the TC39 import-defer spec, deferred namespaces are
125 // distinct from their eager counterparts and the same module
126 // referenced from multiple defer-import sites must yield the
127 // same object. Cache the Proxy / fake namespace per-moduleId so
128 // repeated calls (including across files) share identity.
129 //
130 // Bit 16 (`createFakeNamespaceObject`'s "return value when
131 // it's Promise-like" flag added by
132 // `RuntimeTemplate.moduleNamespacePromise` for dynamic
133 // imports) is irrelevant for deferred namespaces — the value
134 // passed into `createFakeNamespaceObject` here is always the
135 // resolved module exports (after unwrapping the async-module
136 // export symbol when present), never a Promise. Strip it
137 // once so all downstream behavior, the cache key, and the
138 // `createFakeNamespaceObject` call below see the same shape
139 // mode. This keeps static defer (mode 8) and dynamic
140 // `await import.defer` (mode 8 | 16) sharing the same
141 // Deferred Module Namespace object, while still keying by
142 // `(moduleId, mode)` so distinct exports-type shapes
143 // (e.g. one importer treats a CJS module as
144 // "default-with-named", another as "namespace") get
145 // distinct cache entries.
146 "mode &= ~16;",
147 "var byMode = __webpack_module_deferred_namespace_cache__[moduleId];",
148 "if (byMode && byMode[mode] !== undefined) return byMode[mode];",
149 "if (!byMode) byMode = __webpack_module_deferred_namespace_cache__[moduleId] = {};",
150 "var cachedModule = __webpack_module_cache__[moduleId];",
151 "if (cachedModule && cachedModule.error === undefined && !(mode & 8)) {",
152 Template.indent([
153 "var exports = cachedModule.exports;",
154 hasAsync
155 ? `if (${RuntimeGlobals.asyncModuleExportSymbol} in exports) exports = exports[${RuntimeGlobals.asyncModuleExportSymbol}];`
156 : "",
157 `return byMode[mode] = ${RuntimeGlobals.createFakeNamespaceObject}(exports, mode);`
158 ]),
159 "}",
160 "",
161 `var init = ${runtimeTemplate.basicFunction("", [
162 `ns = ${RuntimeGlobals.require}(moduleId);`,
163 hasAsync
164 ? `if (${RuntimeGlobals.asyncModuleExportSymbol} in ns) ns = ns[${RuntimeGlobals.asyncModuleExportSymbol}];`
165 : "",
166 "init = null;",
167 "if (mode & 8 || mode & 4 && ns.__esModule && typeof ns === 'object') {",
168 Template.indent([
169 // Drop only the read-side traps after init: with the
170 // resolved namespace's own keys mirrored onto
171 // `ns_target` below, the default `Reflect` behavior
172 // returns the right values via the live-binding
173 // getters, so we no longer need to intercept `get` /
174 // `has` / `ownKeys` / `getOwnPropertyDescriptor`.
175 //
176 // The mutation traps (`set`, `deleteProperty`,
177 // `defineProperty`) are kept because per the TC39
178 // import-defer spec, `[[Set]]` / `[[Delete]]` /
179 // `[[DefineOwnProperty]]` on a Deferred Module
180 // Namespace Exotic Object never succeed — and the
181 // proxy target itself remains extensible
182 // (architecturally we cannot freeze it up-front),
183 // so without these traps `ns.notExported = "x"`
184 // after evaluation would silently create a property
185 // on the target instead of returning false.
186 "delete handler.get;",
187 "delete handler.has;",
188 "delete handler.ownKeys;",
189 "delete handler.getOwnPropertyDescriptor;"
190 ]),
191 "} else {",
192 Template.indent([
193 `ns = ${RuntimeGlobals.createFakeNamespaceObject}(ns, mode);`
194 ]),
195 "}",
196 // Mirror own properties from the resolved namespace onto the proxy
197 // target so that proxy invariants hold for callers that structurally
198 // introspect via `Object.keys` / `Object.getOwnPropertyNames` /
199 // `Object.getOwnPropertyDescriptor`: when our trap reports a
200 // non-configurable descriptor for a key, the target must also have
201 // that key with a matching descriptor.
202 //
203 // `__esModule` and `Symbol.toStringTag` are intentionally skipped:
204 // the proxy synthesizes "Deferred Module" / true regardless of what
205 // the underlying namespace exposes (per the TC39 import-defer
206 // proposal, the [[StringTag]] of a Deferred Module Namespace
207 // Exotic Object is "Deferred Module"), and the target was already
208 // pre-populated with those values below.
209 "var keys = Reflect.ownKeys(ns);",
210 "for (var i = 0; i < keys.length; i++) {",
211 Template.indent([
212 "var k = keys[i];",
213 'if (k === "__esModule" || k === Symbol.toStringTag) continue;',
214 "if (!Object.prototype.hasOwnProperty.call(ns_target, k)) {",
215 Template.indent([
216 "try { Object.defineProperty(ns_target, k, Reflect.getOwnPropertyDescriptor(ns, k)); } catch (_) {}"
217 ]),
218 "}"
219 ]),
220 "}"
221 ])};`,
222 "",
223 // The proxy target is a fresh placeholder, separate from
224 // `__webpack_module_deferred_exports__[moduleId]` (which is reused
225 // by `__webpack_require__` as `module.exports` for deferred-loaded
226 // modules and would conflict with our pre-populated synthetic
227 // `__esModule` / `Symbol.toStringTag` non-configurable properties).
228 // Using a dedicated target keeps the proxy invariant-compliant
229 // without interfering with the module's own exports object.
230 "var ns_target = { __proto__: null };",
231 // Pre-populate the synthetic deferred-namespace properties with
232 // fully non-configurable, non-writable, non-enumerable descriptors
233 // (matching the TC39 import-defer spec for Module Namespace
234 // Exotic Objects). The trap returns the same descriptors below.
235 'Object.defineProperty(ns_target, "__esModule", { value: true });',
236 'Object.defineProperty(ns_target, Symbol.toStringTag, { value: "Deferred Module" });',
237 "var ns = ns_target;",
238 "var handler = {",
239 Template.indent([
240 "__proto__: null,",
241 // Per the TC39 import-defer proposal, `IsSymbolLikeNamespaceKey`
242 // returns true for any Symbol-keyed access (and for "then"); such
243 // accesses go through `OrdinaryGetOwnProperty` and must not
244 // trigger evaluation of the deferred module. The Symbol checks
245 // below short-circuit to the pre-populated target without
246 // running `init()`.
247 `get: ${runtimeTemplate.basicFunction("_, name", [
248 "switch (name) {",
249 Template.indent([
250 'case "__esModule": return true;',
251 'case Symbol.toStringTag: return "Deferred Module";',
252 'case "then": return undefined;'
253 ]),
254 "}",
255 'if (typeof name === "symbol") return ns_target[name];',
256 init,
257 "return ns[name];"
258 ])},`,
259 `has: ${runtimeTemplate.basicFunction("_, name", [
260 "switch (name) {",
261 Template.indent(
262 [
263 'case "__esModule":',
264 "case Symbol.toStringTag:",
265 hasAsync
266 ? `case ${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol}:`
267 : "",
268 Template.indent("return true;"),
269 'case "then":',
270 Template.indent("return false;")
271 ].filter(Boolean)
272 ),
273 "}",
274 'if (typeof name === "symbol") return name in ns_target;',
275 init,
276 "return name in ns;"
277 ])},`,
278 `ownKeys: ${runtimeTemplate.basicFunction("", [
279 init,
280 `var keys = Reflect.ownKeys(ns).filter(${runtimeTemplate.expressionFunction('x !== "then" && x !== Symbol.toStringTag', "x")}).concat([Symbol.toStringTag]);`,
281 "return keys;"
282 ])},`,
283 `getOwnPropertyDescriptor: ${runtimeTemplate.basicFunction("_, name", [
284 "switch (name) {",
285 Template.indent([
286 // Match the descriptors actually defined on `ns_target`
287 // (non-configurable, non-writable, non-enumerable) so the
288 // proxy invariant holds for both the trap result and any
289 // post-init forwarding via the deleted-handler path.
290 'case "__esModule": return { value: true, writable: false, enumerable: false, configurable: false };',
291 'case Symbol.toStringTag: return { value: "Deferred Module", writable: false, enumerable: false, configurable: false };',
292 'case "then": return undefined;'
293 ]),
294 "}",
295 'if (typeof name === "symbol") return Reflect.getOwnPropertyDescriptor(ns_target, name);',
296 init,
297 "var desc = Reflect.getOwnPropertyDescriptor(ns, name);",
298 'if (mode & 2 && name == "default" && !desc) {',
299 Template.indent("desc = { value: ns, configurable: true };"),
300 "}",
301 "return desc;"
302 ])},`,
303 // `defineProperty` always rejects, but per the TC39 spec it
304 // must still trigger evaluation for string keys (the spec
305 // algorithm calls `[[GetOwnProperty]]` first, which forces
306 // evaluation on a deferred namespace). Symbol keys go through
307 // OrdinaryDefineOwnProperty and do not trigger eval.
308 `defineProperty: ${runtimeTemplate.basicFunction("_, name", [
309 'if (typeof name === "symbol" || name === "then") return false;',
310 init,
311 "return false;"
312 ])},`,
313 // `deleteProperty` rejects, but per the TC39 spec it must
314 // still trigger evaluation for string keys (the spec
315 // algorithm calls `GetModuleExportsList` for non-symbol-like
316 // keys, forcing evaluation on a deferred namespace).
317 `deleteProperty: ${runtimeTemplate.basicFunction("_, name", [
318 'if (typeof name === "symbol" || name === "then") return false;',
319 init,
320 "return false;"
321 ])},`,
322 // `set` always returns false without triggering evaluation —
323 // the spec [[Set]] algorithm for Module Namespaces is just
324 // "return false" (no [[GetOwnProperty]], no eval).
325 `set: ${runtimeTemplate.returningFunction("false")},`
326 ]),
327 "}",
328 // we don't fully emulate ES Module semantics in this Proxy to align with normal webpack esm namespace object.
329 "return byMode[mode] = new Proxy(ns_target, handler);"
330 ])};`;
331 }
332}
333
334module.exports.MakeDeferredNamespaceObjectRuntimeModule =
335 MakeDeferredNamespaceObjectRuntimeModule;
336module.exports.MakeOptimizedDeferredNamespaceObjectRuntimeModule =
337 MakeOptimizedDeferredNamespaceObjectRuntimeModule;
338module.exports.getMakeDeferredNamespaceModeFromExportsType =
339 getMakeDeferredNamespaceModeFromExportsType;
340module.exports.getOptimizedDeferredModule = getOptimizedDeferredModule;
Note: See TracBrowser for help on using the repository browser.