blockPromise(options)
-
功能:生成用于加载 chunk 的 Promise 表达式。
-
用途 :支持异步模块(如
import()
)在 runtime 中正确加载 chunk。 -
逻辑:
- 如果没有 block 或 block 对应的 chunkGroup 为空,返回
Promise.resolve(...)
。 - 获取 block 所属的 chunkGroup,并筛选出没有 runtime 且有 ID 的 chunk。
- 若只需加载一个 chunk,生成
__webpack_require__.e(chunkId)
表达式。 - 若有多个 chunk,生成
Promise.all([...])
包含多个ensureChunk
调用。 - 自动收集
RuntimeGlobals.ensureChunk
和可能的RuntimeGlobals.hasFetchPriority
到 runtimeRequirements 中。
- 如果没有 block 或 block 对应的 chunkGroup 为空,返回
asyncModuleFactory(options)
-
功能:生成异步模块的工厂函数代码。
-
用途:用于代码分割中异步模块的运行时代码生成。
-
逻辑:
- 获取异步 block 的依赖对应模块。
- 调用
blockPromise
获取 chunk 加载表达式。 - 创建工厂函数(实际调用
__webpack_require__
载入模块)。 - 若 chunk 加载是异步的,使用
.then(factory)
包裹;否则直接返回工厂函数。
syncModuleFactory(options)
-
功能:生成同步模块的工厂函数代码。
-
用途:用于普通(非异步)模块的运行时加载工厂。
-
逻辑:
- 获取依赖模块。
- 构建
(() => __webpack_require__(moduleId))
的函数形式。
defineEsModuleFlagStatement(options)
-
功能 :生成标记
exports.__esModule = true
的语句。 -
用途 :兼容 ESModule 模式,确保
import
与require
之间正确识别模块类型。 -
逻辑:
- 添加对
RuntimeGlobals.makeNamespaceObject
和RuntimeGlobals.exports
的依赖。 - 返回调用
__webpack_require__.r(exports)
的代码。
- 添加对
js
class RuntimeTemplate {
/**
* @param {object} options options 配置项
* @param {AsyncDependenciesBlock | undefined} options.block 异步模块块(如 import())
* @param {string} options.message 注释信息
* @param {ChunkGraph} options.chunkGraph Chunk 图结构(模块和 chunk 的依赖关系)
* @param {RuntimeRequirements} options.runtimeRequirements 存储运行时代码所需依赖
* @returns {string} 返回用于异步模块加载的代码字符串
*/
blockPromise({ block, message, chunkGraph, runtimeRequirements }) {
// 如果 block 不存在,直接返回一个已完成的 Promise
if (!block) {
const comment = this.comment({ message });
return `Promise.resolve(${comment.trim()})`;
}
// 获取该 block 所对应的 chunk group(一个或多个 chunk 的集合)
const chunkGroup = chunkGraph.getBlockChunkGroup(block);
// 若 chunkGroup 不存在或为空,也返回已完成 Promise
if (!chunkGroup || chunkGroup.chunks.length === 0) {
const comment = this.comment({ message });
return `Promise.resolve(${comment.trim()})`;
}
// 过滤掉包含 runtime 的 chunk,并只保留有 id 的 chunk
const chunks = chunkGroup.chunks.filter(
chunk => !chunk.hasRuntime() && chunk.id !== null
);
// 添加注释信息,包括 chunkName
const comment = this.comment({
message,
chunkName: block.chunkName
});
// 如果只需加载一个 chunk
if (chunks.length === 1) {
const chunkId = JSON.stringify(chunks[0].id);
// 添加 ensureChunk 到运行时依赖(__webpack_require__.e)
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
// 获取 fetch 优先级(用于 HTTP/2 优化)
const fetchPriority = chunkGroup.options.fetchPriority;
if (fetchPriority) {
runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
}
// 返回加载单个 chunk 的表达式
return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${
fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
})`;
}
// 如果有多个 chunk 需要加载
else if (chunks.length > 0) {
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
const fetchPriority = chunkGroup.options.fetchPriority;
if (fetchPriority) {
runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
}
/**
* @param {Chunk} chunk 单个 chunk
* @returns {string} 返回 ensureChunk 加载语句
*/
const requireChunkId = chunk =>
`${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${
fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
})`;
// 返回 Promise.all([...]) 加载多个 chunk 的表达式
return `Promise.all(${comment.trim()}[${chunks
.map(requireChunkId)
.join(", ")}])`;
}
// 无 chunk 时,返回已完成 Promise
return `Promise.resolve(${comment.trim()})`;
}
/**
* 生成异步模块的工厂函数
* @param {object} options 配置项
* @param {AsyncDependenciesBlock} options.block 异步模块块
* @param {ChunkGraph} options.chunkGraph chunk 图
* @param {RuntimeRequirements} options.runtimeRequirements 存储运行时代码依赖
* @param {string=} options.request 请求路径
* @returns {string} 返回模块工厂函数代码
*/
asyncModuleFactory({ block, chunkGraph, runtimeRequirements, request }) {
// 获取该 block 中的第一个依赖
const dep = block.dependencies[0];
// 获取该依赖对应的模块
const module = chunkGraph.moduleGraph.getModule(dep);
// 生成 ensureChunk 调用代码(可能是 Promise.resolve 或 ensureChunk)
const ensureChunk = this.blockPromise({
block,
message: "",
chunkGraph,
runtimeRequirements
});
// 生成模块工厂函数 (() => __webpack_require__(moduleId))
const factory = this.returningFunction(
this.moduleRaw({
module,
chunkGraph,
request,
runtimeRequirements
})
);
// 返回最终的异步模块工厂 (() => Promise.then(() => require(id)))
return this.returningFunction(
ensureChunk.startsWith("Promise.resolve(")
? `${factory}`
: `${ensureChunk}.then(${this.returningFunction(factory)})`
);
}
/**
* 生成同步模块的工厂函数
* @param {object} options 配置项
* @param {Dependency} options.dependency 模块依赖
* @param {ChunkGraph} options.chunkGraph chunk 图
* @param {RuntimeRequirements} options.runtimeRequirements 存储运行时代码依赖
* @param {string=} options.request 请求路径
* @returns {string} 返回模块工厂函数代码
*/
syncModuleFactory({ dependency, chunkGraph, runtimeRequirements, request }) {
// 获取该依赖对应的模块
const module = chunkGraph.moduleGraph.getModule(dependency);
// 生成模块工厂 (() => __webpack_require__(moduleId))
const factory = this.returningFunction(
this.moduleRaw({
module,
chunkGraph,
request,
runtimeRequirements
})
);
// 再次包一层返回函数(用于构建 factory 的引用)
return this.returningFunction(factory);
}
/**
* 返回将 __esModule 标志注入到 exports 对象的语句
* @param {object} options 配置项
* @param {string} options.exportsArgument exports 对象变量名
* @param {RuntimeRequirements} options.runtimeRequirements 存储运行时代码依赖
* @returns {string} 代码语句字符串
*/
defineEsModuleFlagStatement({ exportsArgument, runtimeRequirements }) {
// 添加运行时对 __webpack_require__.r 和 exports 的依赖
runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
runtimeRequirements.add(RuntimeGlobals.exports);
// 返回 __webpack_require__.r(exports); 语句
return `${RuntimeGlobals.makeNamespaceObject}(${exportsArgument});\n`;
}
}
module.exports = RuntimeTemplate; // 导出 RuntimeTemplate 类