Webpack 实现代码分割主要有哪几种方式?
在 Webpack 中,实现代码分割(Code Splitting)主要有以下 三种核心方式,此外还有一些配套的优化手段:
1. 入口起点(Entry Points):手动配置分割
这是最原始也是最直接的代码分割方式。通过在 webpack.config.js 的 entry 属性中配置多个入口文件,Webpack 会为每个入口生成一个单独的 bundle。
- 适用场景:多页面应用(MPA)或需要明确拆分主入口的场景。
- 配置示例:javascript
// webpack.config.js module.exports = { entry: { index: './src/index.js', another: './src/another-module.js', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist'), }, }; - 缺点:
- 如果入口文件之间包含重复的模块(例如都引用了
lodash),这些模块会被重复打包到各自的 bundle 中。 - 不够灵活,无法根据运行时代码逻辑动态加载。
- 如果入口文件之间包含重复的模块(例如都引用了
Webpack 5 补充:可以通过
dependOn选项在入口之间共享模块,避免重复打包:javascriptentry: { app: { import: './src/app.js', dependOn: 'shared' }, shared: 'lodash', }
2. 动态导入(Dynamic Imports):按需加载(最推荐)
通过代码中的动态语法来实现运行时(Runtime)的代码分割和按需加载。Webpack 会自动将动态导入的模块拆分为独立的 chunk。
适用场景:路由懒加载、弹窗/大组件按需加载、第三方重型库(如图表库)延迟加载。
语法实现:使用符合 ECMAScript 提案的
import()语法。代码示例:
javascript// 当事件触发时才去加载 lodash 模块 button.addEventListener('click', () => { import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => { // 使用 lodash 的逻辑 console.log(_.join(['Hello', 'webpack'], ' ')); }); });(注:注释
/* webpackChunkName: "lodash" */称为魔术注释(Magic Comments),用于指定生成的 chunk 名称)优点:
- 极大减少首屏加载时间(减少 Initial Bundle 体积)。
- 实现了真正意义上的“按需加载”。
3. 防止重复 / 抽取公共代码(SplitChunksPlugin)
Webpack 内置了 SplitChunksPlugin 插件(Webpack 4+ 引入,取代了旧版的 CommonsChunkPlugin)。它可以自动或根据配置策略将公共依赖或 node_modules 中的第三方库抽离成独立的 chunk。
- 适用场景:提取第三方库(Vendor Chunk)、提取多页面或动态导入之间的公共代码。
- 配置示例:javascript
// webpack.config.js module.exports = { // ... optimization: { splitChunks: { chunks: 'all', // 对所有类型的 chunk(同步/异步)生效 cacheGroups: { // 提取 node_modules 中的第三方库 vendors: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: -10, // 优先级 }, // 提取被引用 2 次以上的公共模块 default: { minChunks: 2, priority: -20, reuseExistingChunk: true, // 复用已存在的 chunk }, }, }, }, }; - 优点:
- 避免重复打包。
- 利于浏览器长期缓存(第三方库代码很少变动,拆分后可持久缓存)。
进阶优化手段(配合代码分割使用)
除了上述三种主要方式,Webpack 还提供了预加载技术,进一步提升分割后的代码加载体验:
- Preload(预加载):声明当前导航下可能马上需要的资源。javascript
import(/* webpackPreload: true */ 'CriticalChunk'); - Prefetch(预获取):声明将来在其他页面/未来某个时刻可能需要的资源,浏览器会在空闲时静默下载。javascript
import(/* webpackPrefetch: true */ 'FutureChunk');
总结比较
| 方式 | 触发时机 | 适用场景 | 主要目的 |
|---|---|---|---|
| 入口起点 (Entry) | 编译时 | 多页面应用 (MPA) | 分隔业务入口 |
动态导入 (import()) |
运行时 (按需) | 路由懒加载、组件懒加载 | 减小首屏体积,提高加载速度 |
| SplitChunksPlugin | 编译时 (自动) | 第三方库 (node_modules)、公共代码 |
消除重复代码、利用浏览器缓存 |