runtime chunk(运行时代码块)是 Webpack 生成的一小段核心代码,它不包含你的业务逻辑,而是负责:
- 管理模块之间的依赖关系(比如哪个模块对应哪个文件);
- 加载和执行打包后的模块(比如异步加载 chunk);
- 维护模块的缓存和版本映射。
实操案例:从零看 runtime chunk 的生成
1. 准备极简项目结构
plaintext
├── src
│ ├── index.js # 主入口
│ └── utils.js # 工具模块
├── package.json
└── webpack.config.js
2. 编写业务代码
javascript
运行
// src/utils.js
export const add = (a, b) => a + b;
javascript
运行
// src/index.js
// 同步引入 + 异步引入,触发Webpack的模块管理逻辑
import { add } from './utils.js';
console.log('同步调用:', add(1, 2));
// 异步引入(关键:会让runtime逻辑更明显)
setTimeout(() => {
import('./async-module.js').then(({ sayHello }) => {
sayHello();
});
}, 1000);
javascript
运行
// src/async-module.js
export const sayHello = () => console.log('异步模块加载成功!');
3. Webpack 配置(默认开启 runtime chunk)
javascript
运行
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: '[name].bundle.js', // 主bundle
chunkFilename: '[name].chunk.js', // 异步chunk
path: path.resolve(__dirname, 'dist'),
},
optimization: {
// 默认值为'single':将runtime提取为单独的chunk
runtimeChunk: 'single',
splitChunks: {
chunks: 'all', // 分割同步/异步chunk
},
},
};
4. 执行打包 & 查看输出
运行 npx webpack 后,dist 目录会生成 3 个文件:
plaintext
dist/
├── runtime.bundle.js # runtime chunk(核心!)
├── main.bundle.js # 主业务chunk(index + utils)
└── async-module.chunk.js # 异步chunk
5. 核心:runtime.bundle.js 里有什么?
打开 runtime.bundle.js,核心内容(简化后)如下:
javascript
运行
// runtime的核心逻辑:模块映射 + 加载器
(() => {
// 1. 模块ID和文件路径的映射表(关键)
const moduleMap = {
"./src/async-module.js": () => import("./async-module.chunk.js"),
};
// 2. 模块加载器:处理异步import的核心逻辑
window.__webpack_require__.e = (chunkId) => {
// 加载对应的chunk文件(比如async-module.chunk.js)
// 处理模块缓存、依赖解析
};
// 3. 模块缓存管理:避免重复加载
const installedModules = {};
window.__webpack_require__.c = installedModules;
})();
对比:禁用 runtime chunk 的效果
修改 Webpack 配置,将 runtimeChunk: false,重新打包后:
dist目录只有 2 个文件:main.bundle.js、async-module.chunk.js;main.bundle.js里会包含原本runtime.bundle.js的所有逻辑(模块映射、加载器等);- 此时
main.bundle.js= 业务代码 + runtime 代码(即多个 chunk 合并到一个 bundle,对应上一轮你问的场景)。
为什么要单独提取 runtime chunk?
这是最关键的实战价值,用一个场景说明:假设你只修改了 utils.js 里的 add 函数(比如改成 a + b + 1),重新打包后:
main.bundle.js的内容变了 → hash 值会变;async-module.chunk.js没改 → hash 值不变;runtime.bundle.js里的模块映射表没改 → hash 值不变;
用户浏览器缓存中:
- 只会重新加载
main.bundle.js,runtime.bundle.js和async-module.chunk.js会复用缓存;
如果不提取 runtime chunk,main.bundle.js 包含 runtime 逻辑,哪怕只改一行业务代码,整个 main.bundle.js 的 hash 都变,用户需要重新加载全部内容 → 缓存失效,性能变差。
总结
- runtime chunk 本质:Webpack 的 “模块调度器”,包含模块映射、加载逻辑、缓存管理,无业务代码;
- 核心作用:管理打包后模块的加载和依赖,单独提取可提升缓存复用率;
- 表现形式:默认会生成单独的
runtime.bundle.js,禁用则合并到主 bundle 中(多 chunk→单 bundle)。