| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- */
- "use strict";
- const RuntimeGlobals = require("../RuntimeGlobals");
- const Template = require("../Template");
- const HelperRuntimeModule = require("./HelperRuntimeModule");
- /** @import Compilation from "../Compilation" */
- class AsyncModuleRuntimeModule extends HelperRuntimeModule {
- /**
- * @param {boolean=} deferInterop if defer import is used.
- */
- constructor(deferInterop = false) {
- super("async module");
- /** @type {boolean} */
- this._deferInterop = deferInterop;
- }
- /**
- * Generates runtime code for this runtime module.
- * @returns {string | null} runtime code
- */
- generate() {
- const compilation = /** @type {Compilation} */ (this.compilation);
- const { runtimeTemplate } = compilation;
- const fn = RuntimeGlobals.asyncModule;
- const defer = this._deferInterop;
- const cst = runtimeTemplate.renderConst();
- const lt = runtimeTemplate.renderLet();
- const supportsSymbol = runtimeTemplate.supportsSymbol();
- /** @type {(name: string, fallback: string) => string} */
- const renderSymbol = (name, fallback) =>
- supportsSymbol
- ? `Symbol("${name}")`
- : `hasSymbol ? Symbol("${name}") : "${fallback}"`;
- return Template.asString([
- ...(supportsSymbol
- ? []
- : [`${cst} hasSymbol = typeof Symbol === "function";`]),
- `${cst} webpackQueues = ${renderSymbol("webpack queues", "__webpack_queues__")};`,
- `${cst} webpackExports = ${
- defer ? `${RuntimeGlobals.asyncModuleExportSymbol}= ` : ""
- }${renderSymbol("webpack exports", RuntimeGlobals.exports)};`,
- `${cst} webpackError = ${renderSymbol("webpack error", "__webpack_error__")};`,
- defer
- ? Template.asString([
- `${cst} webpackDone = ${RuntimeGlobals.asyncModuleDoneSymbol} = ${renderSymbol("webpack done", "__webpack_done__")};`,
- `${cst} webpackDefer = ${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol} = ${renderSymbol("webpack defer", "__webpack_defer__")};`,
- `${RuntimeGlobals.deferredModuleAsyncTransitiveDependencies} = ${runtimeTemplate.basicFunction(
- "asyncDeps",
- [
- Template.indent([
- `${cst} hasUnresolvedAsyncSubgraph = asyncDeps.some((id) => {`,
- Template.indent([
- `${cst} cache = __webpack_module_cache__[id];`,
- "return !cache || cache[webpackDone] === false;"
- ]),
- "});",
- "if (hasUnresolvedAsyncSubgraph) {",
- Template.indent([
- "return ({ then(onFulfilled, onRejected) { return Promise.all(asyncDeps.map(__webpack_require__)).then(onFulfilled, onRejected) } })"
- ]),
- "}"
- ])
- ]
- )}`
- ])
- : "",
- `${cst} resolveQueue = ${runtimeTemplate.basicFunction("queue", [
- `if(${runtimeTemplate.optionalChaining("queue", "d < 1")}) {`,
- Template.indent([
- "queue.d = 1;",
- `queue.forEach(${runtimeTemplate.expressionFunction(
- "fn.r--",
- "fn"
- )});`,
- `queue.forEach(${runtimeTemplate.expressionFunction(
- "fn.r-- ? fn.r++ : fn()",
- "fn"
- )});`
- ]),
- "}"
- ])}`,
- `${cst} wrapDeps = ${runtimeTemplate.returningFunction(
- `deps.map(${runtimeTemplate.basicFunction("dep", [
- 'if(dep !== null && typeof dep === "object") {',
- Template.indent([
- defer
- ? Template.asString([
- "if(!dep[webpackQueues] && dep[webpackDefer]) {",
- Template.indent([
- `${cst} asyncDeps = ${RuntimeGlobals.deferredModuleAsyncTransitiveDependencies}(dep[webpackDefer]);`,
- "if (asyncDeps) {",
- Template.indent([
- `${cst} d = dep;`,
- "dep = {",
- Template.indent([
- "then(onFulfilled, onRejected) {",
- Template.indent([
- `asyncDeps.then(${runtimeTemplate.returningFunction(
- "onFulfilled(d)"
- )}, onRejected);`
- ]),
- "}"
- ]),
- "};"
- ]),
- "} else return dep;"
- ]),
- "}"
- ])
- : "",
- "if(dep[webpackQueues]) return dep;",
- "if(dep.then) {",
- Template.indent([
- `${cst} queue = [];`,
- "queue.d = 0;",
- `dep.then(${runtimeTemplate.basicFunction("r", [
- "obj[webpackExports] = r;",
- "resolveQueue(queue);"
- ])}, ${runtimeTemplate.basicFunction("e", [
- "obj[webpackError] = e;",
- "resolveQueue(queue);"
- ])});`,
- `${cst} obj = {};`,
- defer ? "obj[webpackDefer] = false;" : "",
- `obj[webpackQueues] = ${runtimeTemplate.expressionFunction(
- "fn(queue)",
- "fn"
- )};`,
- "return obj;"
- ]),
- "}"
- ]),
- "}",
- `${cst} ret = {};`,
- `ret[webpackQueues] = ${runtimeTemplate.emptyFunction()};`,
- "ret[webpackExports] = dep;",
- "return ret;"
- ])})`,
- "deps"
- )};`,
- `${fn} = ${runtimeTemplate.basicFunction("module, body, hasAwait", [
- `${lt} queue;`,
- "hasAwait && ((queue = []).d = -1);",
- `${cst} depQueues = new Set();`,
- `${cst} exports = module.exports;`,
- `${lt} currentDeps;`,
- `${lt} outerResolve;`,
- `${lt} reject;`,
- `${cst} promise = new Promise(${runtimeTemplate.basicFunction(
- "resolve, rej",
- ["reject = rej;", "outerResolve = resolve;"]
- )});`,
- "promise[webpackExports] = exports;",
- `promise[webpackQueues] = ${runtimeTemplate.expressionFunction(
- `queue && fn(queue), depQueues.forEach(fn), promise["catch"](${runtimeTemplate.emptyFunction()})`,
- "fn"
- )};`,
- "module.exports = promise;",
- `${cst} handle = ${runtimeTemplate.basicFunction("deps", [
- "currentDeps = wrapDeps(deps);",
- `${lt} fn;`,
- `${cst} getResult = ${runtimeTemplate.returningFunction(
- `currentDeps.map(${runtimeTemplate.basicFunction("d", [
- defer ? "if(d[webpackDefer]) return d;" : "",
- "if(d[webpackError]) throw d[webpackError];",
- "return d[webpackExports];"
- ])})`
- )}`,
- `${cst} promise = new Promise(${runtimeTemplate.basicFunction(
- "resolve",
- [
- `fn = ${runtimeTemplate.expressionFunction(
- "resolve(getResult)",
- ""
- )};`,
- "fn.r = 0;",
- `${cst} fnQueue = ${runtimeTemplate.expressionFunction(
- "q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn)))",
- "q"
- )};`,
- `currentDeps.forEach(${runtimeTemplate.expressionFunction(
- `${
- defer ? "dep[webpackDefer]||" : ""
- }dep[webpackQueues](fnQueue)`,
- "dep"
- )});`
- ]
- )});`,
- "return fn.r ? promise : getResult();"
- ])}`,
- `${cst} done = ${runtimeTemplate.expressionFunction(
- `(err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)${
- defer
- ? ", promise[webpackDone] = true, module.evaluatingAsync = false"
- : ""
- }`,
- "err"
- )}`,
- // Track the async body's whole lifetime (evaluating +
- // evaluating-async states) with a dedicated flag — the sync require
- // wrapper clears `module.evaluating` as soon as `.a` returns, so a
- // deferred namespace reaching this module through a cycle relies on
- // `evaluatingAsync` to keep throwing until it is fully evaluated.
- defer ? "module.evaluatingAsync = true;" : "",
- "body(handle, done);",
- `${runtimeTemplate.optionalChaining("queue", "d < 0")} && (queue.d = 0);`
- ])};`
- ]);
- }
- }
- module.exports = AsyncModuleRuntimeModule;
|