面试题:打包过程中的分包是要用啥完成的,以webpack和vite示例

在打包过程中,分包(Code Splitting) 是一种优化技术,用于将代码拆分成多个较小的文件(chunks),以提高加载性能、优化缓存利用率并减少首屏加载时间。Webpack 和 Vite 分别采用不同的方式实现分包,以下是它们的核心实现方法及示例:


1. Webpack 的分包策略

Webpack 的分包主要通过 splitChunks 配置和动态导入(import())实现。

(1) 默认分包(splitChunks

Webpack 默认会对 node_modules 中的第三方依赖进行分包,生成 vendor.js 文件。
配置示例

复制代码
// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all', // 对所有模块进行分包(包括同步和异步)
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 中的依赖
          name: 'vendors', // 输出文件名
          priority: 10, // 优先级
        },
        common: {
          minChunks: 2, // 被至少 2 个模块引用的代码才会被分包
          name: 'commons',
          priority: 5,
        },
      },
    },
  },
};

效果

  • node_modules 中的依赖会被打包到 vendors.js

  • 公共业务代码会被打包到 commons.js

(2) 动态导入(路由懒加载)

使用 import() 动态加载模块,Webpack 会自动将其拆分成独立的 chunk。
示例(Vue Router)

复制代码
const Home = () => import(/* webpackChunkName: "home" */ './views/Home.vue');
const About = () => import(/* webpackChunkName: "about" */ './views/About.vue');

效果

  • Home.vueAbout.vue 会被拆分成 home.jsabout.js,按需加载5。

(3) 手动分包(DLLPlugin)

对于大型项目,可以使用 DLLPlugin 预打包第三方库,减少重复构建时间:

复制代码
// webpack.dll.config.js
module.exports = {
  entry: { vendor: ['react', 'lodash'] },
  output: { filename: 'dll/[name].js', library: '[name]' },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve(__dirname, 'dist/dll/vendor.manifest.json'),
      name: '[name]',
    }),
  ],
};

使用方式

  • webpack.config.js 中通过 DllReferencePlugin 引用预打包的库:

    new webpack.DllReferencePlugin({
    manifest: require('./dist/dll/vendor.manifest.json'),
    });

优点

  • 减少重复打包时间。

  • 适合大型项目3。


2. Vite 的分包策略

Vite 基于 Rollup,其分包策略通过 build.rollupOptions.output.manualChunks 配置。

(1) 默认分包

Vite 默认会将 node_modules 中的依赖打包到 vendor.js,业务代码单独打包2。

(2) 手动分包

通过 manualChunks 可以自定义分包逻辑:

复制代码
// vite.config.js
export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return 'vendor'; // 所有 node_modules 依赖打包到 vendor.js
          }
          if (id.includes('/utils/')) {
            return 'utils'; // 工具函数单独分包
          }
        },
      },
    },
  },
};

效果

  • node_modules 中的依赖 → vendor.js

  • src/utils/ 下的代码 → utils.js

(3) 按包名分包

如果希望每个第三方库单独分包(如 reactlodash 独立):

复制代码
manualChunks(id) {
  if (id.includes('node_modules')) {
    const pkg = id.split('node_modules/')[1].split('/')[0];
    return `npm.${pkg}`; // 如 npm.react.js、npm.lodash.js
  }
}

优点

  • 更细粒度的缓存优化6。

(4) 动态导入(懒加载)

Vite 支持动态导入,自动分包:

复制代码
const loadModule = async () => {
  const module = await import('./heavyModule.js'); // 自动拆分成独立 chunk
};

效果

  • heavyModule.js 会被拆分成独立文件,按需加载4。

3. Webpack vs. Vite 分包对比

特性 Webpack Vite
分包方式 splitChunksDLLPlugin manualChunks
动态导入 import() + 魔法注释 import()
缓存优化 contenthash [hash]
适用场景 大型复杂项目 中小型项目、快速构建
构建速度 较慢(需分析依赖) 极快(ESM 原生支持)

4. 最佳实践

(1) Webpack 优化建议

  • 使用 splitChunks 分离 node_modules 和公共代码。

  • 对路由使用动态导入(懒加载)。

  • 大型项目可结合 DLLPlugin 预编译依赖3。

(2) Vite 优化建议

  • 使用 manualChunks 精细控制分包。

  • 按包名拆分第三方库(如 reactlodash 独立)。

  • 结合动态导入优化首屏加载68。


总结

  • Webpack :通过 splitChunks 和动态导入实现分包,适合复杂项目。

  • Vite :通过 manualChunks 配置分包,依赖 Rollup,适合现代前端开发。

两种工具的分包核心目标都是减少首屏加载时间、优化缓存,具体选择取决于项目规模和构建需求。