mirror of https://github.com/webpack/webpack.git
refactor: use runtime module for optimized deferred module (#20057)
This commit is contained in:
parent
a576d0f318
commit
9a2e984b76
|
|
@ -267,6 +267,11 @@ module.exports.makeDeferredNamespaceObjectSymbol = "__webpack_require__.zS";
|
|||
*/
|
||||
module.exports.makeNamespaceObject = "__webpack_require__.r";
|
||||
|
||||
/**
|
||||
* make a optimized deferred namespace object
|
||||
*/
|
||||
module.exports.makeOptimizedDeferredNamespaceObject = "__webpack_require__.zO";
|
||||
|
||||
/**
|
||||
* the internal module object
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ const GetTrustedTypesPolicyRuntimeModule = require("./runtime/GetTrustedTypesPol
|
|||
const GlobalRuntimeModule = require("./runtime/GlobalRuntimeModule");
|
||||
const HasOwnPropertyRuntimeModule = require("./runtime/HasOwnPropertyRuntimeModule");
|
||||
const LoadScriptRuntimeModule = require("./runtime/LoadScriptRuntimeModule");
|
||||
const MakeDeferredNamespaceObjectRuntime = require("./runtime/MakeDeferredNamespaceObjectRuntime");
|
||||
const {
|
||||
MakeDeferredNamespaceObjectRuntimeModule,
|
||||
MakeOptimizedDeferredNamespaceObjectRuntimeModule
|
||||
} = require("./runtime/MakeDeferredNamespaceObjectRuntime");
|
||||
const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
|
||||
const NonceRuntimeModule = require("./runtime/NonceRuntimeModule");
|
||||
const OnChunksLoadedRuntimeModule = require("./runtime/OnChunksLoadedRuntimeModule");
|
||||
|
|
@ -78,6 +81,7 @@ const GLOBALS_ON_REQUIRE = [
|
|||
RuntimeGlobals.loadScript,
|
||||
RuntimeGlobals.systemContext,
|
||||
RuntimeGlobals.onChunksLoaded,
|
||||
RuntimeGlobals.makeOptimizedDeferredNamespaceObject,
|
||||
RuntimeGlobals.makeDeferredNamespaceObject
|
||||
];
|
||||
|
||||
|
|
@ -96,11 +100,11 @@ const TREE_DEPENDENCIES = {
|
|||
RuntimeGlobals.makeNamespaceObject,
|
||||
RuntimeGlobals.require
|
||||
],
|
||||
[RuntimeGlobals.makeOptimizedDeferredNamespaceObject]: [
|
||||
RuntimeGlobals.require
|
||||
],
|
||||
[RuntimeGlobals.makeDeferredNamespaceObject]: [
|
||||
RuntimeGlobals.definePropertyGetters,
|
||||
RuntimeGlobals.makeNamespaceObject,
|
||||
RuntimeGlobals.createFakeNamespaceObject,
|
||||
RuntimeGlobals.hasOwnProperty,
|
||||
RuntimeGlobals.require
|
||||
],
|
||||
[RuntimeGlobals.initializeSharing]: [RuntimeGlobals.shareScopeMap],
|
||||
|
|
@ -190,12 +194,23 @@ class RuntimePlugin {
|
|||
);
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.makeOptimizedDeferredNamespaceObject)
|
||||
.tap("RuntimePlugin", (chunk, runtimeRequirement) => {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new MakeOptimizedDeferredNamespaceObjectRuntimeModule(
|
||||
runtimeRequirement.has(RuntimeGlobals.asyncModule)
|
||||
)
|
||||
);
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.makeDeferredNamespaceObject)
|
||||
.tap("RuntimePlugin", (chunk, runtimeRequirement) => {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new MakeDeferredNamespaceObjectRuntime(
|
||||
new MakeDeferredNamespaceObjectRuntimeModule(
|
||||
runtimeRequirement.has(RuntimeGlobals.asyncModule)
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -871,10 +871,10 @@ class RuntimeTemplate {
|
|||
const outgoingAsyncModules = getOutgoingAsyncModules(moduleGraph, module);
|
||||
|
||||
importContent = `/* deferred harmony import */ ${optDeclaration}${importVar} = ${getOptimizedDeferredModule(
|
||||
this,
|
||||
exportsType,
|
||||
moduleId,
|
||||
Array.from(outgoingAsyncModules, (mod) => chunkGraph.getModuleId(mod))
|
||||
exportsType,
|
||||
Array.from(outgoingAsyncModules, (mod) => chunkGraph.getModuleId(mod)),
|
||||
runtimeRequirements
|
||||
)};\n`;
|
||||
|
||||
return [importContent, ""];
|
||||
|
|
|
|||
|
|
@ -1837,15 +1837,15 @@ ${defineGetters}`
|
|||
if (info.type === "external" && info.deferred) {
|
||||
const moduleId = JSON.stringify(chunkGraph.getModuleId(info.module));
|
||||
const loader = getOptimizedDeferredModule(
|
||||
runtimeTemplate,
|
||||
moduleId,
|
||||
info.module.getExportsType(
|
||||
moduleGraph,
|
||||
/** @type {BuildMeta} */
|
||||
(this.rootModule.buildMeta).strictHarmonyModule
|
||||
),
|
||||
moduleId,
|
||||
// an async module will opt-out of the concat module optimization.
|
||||
[]
|
||||
[],
|
||||
runtimeRequirements
|
||||
);
|
||||
runtimeRequirements.add(RuntimeGlobals.require);
|
||||
result.add(
|
||||
|
|
|
|||
|
|
@ -8,8 +8,12 @@ const RuntimeGlobals = require("../RuntimeGlobals");
|
|||
const Template = require("../Template");
|
||||
const HelperRuntimeModule = require("./HelperRuntimeModule");
|
||||
|
||||
/** @typedef {import("../Module").RuntimeRequirements} RuntimeRequirements */
|
||||
/** @typedef {import("../Module").ExportsType} ExportsType */
|
||||
/** @typedef {import("../ChunkGraph").ModuleId} ModuleId */
|
||||
|
||||
/**
|
||||
* @param {import("../Module").ExportsType} exportsType exports type
|
||||
* @param {ExportsType} exportsType exports type
|
||||
* @returns {string} mode
|
||||
*/
|
||||
function getMakeDeferredNamespaceModeFromExportsType(exportsType) {
|
||||
|
|
@ -19,45 +23,80 @@ function getMakeDeferredNamespaceModeFromExportsType(exportsType) {
|
|||
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
|
||||
* @param {ExportsType} exportsType exportsType
|
||||
* @param {(ModuleId | null)[]} asyncDepsIds asyncDepsIds
|
||||
* @param {RuntimeRequirements} runtimeRequirements runtime requirements
|
||||
* @returns {string} call make optimized deferred namespace object
|
||||
*/
|
||||
function getOptimizedDeferredModule(
|
||||
_runtimeTemplate,
|
||||
exportsType,
|
||||
moduleId,
|
||||
asyncDepsIds
|
||||
exportsType,
|
||||
asyncDepsIds,
|
||||
runtimeRequirements
|
||||
) {
|
||||
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))}`
|
||||
runtimeRequirements.add(RuntimeGlobals.makeOptimizedDeferredNamespaceObject);
|
||||
const mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
|
||||
return `${RuntimeGlobals.makeOptimizedDeferredNamespaceObject}(${moduleId}, ${mode}${
|
||||
asyncDepsIds.length > 0
|
||||
? `, ${JSON.stringify(asyncDepsIds.filter((x) => x !== null))}`
|
||||
: ""
|
||||
];
|
||||
return Template.asString(["{", Template.indent(props), "}"]);
|
||||
})`;
|
||||
}
|
||||
|
||||
class MakeOptimizedDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
|
||||
/**
|
||||
* @param {boolean} hasAsyncRuntime if async module is used.
|
||||
*/
|
||||
constructor(hasAsyncRuntime) {
|
||||
super("make optimized deferred namespace object");
|
||||
this.hasAsyncRuntime = hasAsyncRuntime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string | null} runtime code
|
||||
*/
|
||||
generate() {
|
||||
if (!this.compilation) return null;
|
||||
const fn = RuntimeGlobals.makeOptimizedDeferredNamespaceObject;
|
||||
const hasAsync = this.hasAsyncRuntime;
|
||||
return Template.asString([
|
||||
// Note: must be a function (not arrow), because this is used in body!
|
||||
`${fn} = function(moduleId, mode${hasAsync ? ", asyncDeps" : ""}) {`,
|
||||
Template.indent([
|
||||
"// 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 r = this;",
|
||||
hasAsync ? "var isAsync = asyncDeps && asyncDeps.length;" : "",
|
||||
"var obj = {",
|
||||
Template.indent([
|
||||
"get a() {",
|
||||
Template.indent([
|
||||
"var exports = r(moduleId);",
|
||||
hasAsync
|
||||
? `if(isAsync) exports = exports[${RuntimeGlobals.asyncModuleExportSymbol}];`
|
||||
: "",
|
||||
// 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.
|
||||
'if(mode == 0 || (mode == 3 && exports.__esModule)) Object.defineProperty(this, "a", { value: exports });',
|
||||
"return exports;"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"};",
|
||||
hasAsync
|
||||
? `if(isAsync) obj[${RuntimeGlobals.makeDeferredNamespaceObjectSymbol}] = asyncDeps;`
|
||||
: "",
|
||||
"return obj;"
|
||||
]),
|
||||
"};"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
|
||||
|
|
@ -200,7 +239,10 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = MakeDeferredNamespaceObjectRuntimeModule;
|
||||
module.exports.MakeDeferredNamespaceObjectRuntimeModule =
|
||||
MakeDeferredNamespaceObjectRuntimeModule;
|
||||
module.exports.MakeOptimizedDeferredNamespaceObjectRuntimeModule =
|
||||
MakeOptimizedDeferredNamespaceObjectRuntimeModule;
|
||||
module.exports.getMakeDeferredNamespaceModeFromExportsType =
|
||||
getMakeDeferredNamespaceModeFromExportsType;
|
||||
module.exports.getOptimizedDeferredModule = getOptimizedDeferredModule;
|
||||
|
|
|
|||
|
|
@ -19042,6 +19042,7 @@ declare namespace exports {
|
|||
export let makeDeferredNamespaceObject: "__webpack_require__.z";
|
||||
export let makeDeferredNamespaceObjectSymbol: "__webpack_require__.zS";
|
||||
export let makeNamespaceObject: "__webpack_require__.r";
|
||||
export let makeOptimizedDeferredNamespaceObject: "__webpack_require__.zO";
|
||||
export let module: "module";
|
||||
export let moduleCache: "__webpack_require__.c";
|
||||
export let moduleFactories: "__webpack_require__.m";
|
||||
|
|
|
|||
Loading…
Reference in New Issue