基于本文回答
0
评论

Webpack 实现代码分割主要有哪几种方式?

在 Webpack 中,实现代码分割(Code Splitting)主要有以下 三种核心方式,此外还有一些配套的优化手段:


1. 入口起点(Entry Points):手动配置分割

这是最原始也是最直接的代码分割方式。通过在 webpack.config.jsentry 属性中配置多个入口文件,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 选项在入口之间共享模块,避免重复打包:

javascript
entry: {
  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 还提供了预加载技术,进一步提升分割后的代码加载体验:

  1. Preload(预加载):声明当前导航下可能马上需要的资源。
    javascript
    import(/* webpackPreload: true */ 'CriticalChunk');
  2. Prefetch(预获取):声明将来在其他页面/未来某个时刻可能需要的资源,浏览器会在空闲时静默下载。
    javascript
    import(/* webpackPrefetch: true */ 'FutureChunk');

总结比较

方式 触发时机 适用场景 主要目的
入口起点 (Entry) 编译时 多页面应用 (MPA) 分隔业务入口
动态导入 (import()) 运行时 (按需) 路由懒加载、组件懒加载 减小首屏体积,提高加载速度
SplitChunksPlugin 编译时 (自动) 第三方库 (node_modules)、公共代码 消除重复代码、利用浏览器缓存
右滑查看面试常问