Skip to content

模块分割splitChunks

为什么要分割模块

项目中依赖的第三方库(node_modules下)默认会被打包到一个文件名含chunk-vendors的bundle中,导致单个文件加载非常慢, 所以基础依赖应该单独打包,或者使用externals忽略该类型库的打包,使用cdn单独加载

WARNING

分离出来的bundle必须加入到pages中的chunks,它指定了入口所需要加载的js文件.

除了在cacheGroups声明抽离的模块, 还需要把index模块在chunks中引入, 否则会造成首页白屏

默认配置

js
// ...
plugins: [
  new HtmlWebpackPlugin({
    // ...
    // vue-cli4中配置该项会把下面的chunks直接覆盖掉,所以还需要手动引入index
    // chunk-vendors, chunk-common可以不引入(原因暂未知)
    chunks: [ 'chunk-vendors', 'chunk-common', 'index' ],
    // ...
  }
],
// ...
optimization: {
  splitChunks: {
    // vue-cli4中配置该项会合并下面的默认配置项
    cacheGroups: {
      vendors: {
        name: 'chunk-vendors',
        // 匹配所有第三方模块打包进vendors中
        test: /[\\/]node_modules[\\/]/,
        priority: -10, // 匹配的优先级
        chunks: 'initial'
      },
      common: {
        name: 'chunk-common',
        minChunks: 2, // 超过两次引用的打包进common中
        priority: -20,
        chunks: 'initial',
        reuseExistingChunk: true
      }
    }
  }
}

抽离第三方库的配置参考

js
// vue-cli4下的配置
pages: {
  index: {
    entry: 'src/main.js',
    title: 'vue-cli-framework',
    // splitChunks抽离的模块放这里来
    chunks: ['index', 'vue','element-ui']
  },
},
// ...
// 会通过webpack.merge合并该配置
configureWebpack: {
  performance: {
    // 打包提示
    hints: isProd ? 'warning' : false, // 'warning' or 'error' or false
    maxEntrypointSize: 1024 * 1024, // 入口起点的最大体积超出 1024KB 提示
    maxAssetSize: 1024 * 300 // 生成文件的最大体积超出 300KB 提示
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vue: {
          name: 'vue', // 文件名,打包后会是:name.[contentHash].js
          test: /[\\/]node_modules[\\/]vue[\\/]/, // 目标模块模块
          priority: 10 // 匹配模块的权重,权重越高打包优先级越高
        },
        'element-ui': {
          name: 'element-ui',
          test: /[\\/]node_modules[\\/]element-ui[\\/]/,
          priority: 20 // 模块越大建议优先级越高
        }
      }
    }
  }
}

踩坑

WARNING

index.html 不能存在已注释的ejs模板语法,否则会报错.

js
error 
Template execution failed: TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
  TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
  - index.html:101
    C:/Users/c-zhulj/Desktop/vue-cli-framework/public/index.html:101:79
  - index.html:114 0971.module.exports
    C:/Users/c-zhulj/Desktop/vue-cli-framework/public/index.html:114:3
  - index.js:284
    [vue-cli-framework]/[html-webpack-plugin]/index.js:284:18
  - task_queues.js:97 processTicksAndRejections
    internal/process/task_queues.js:97:5

(splitChunks参考文章)[https://juejin.cn/post/6844903848977367048#heading-0]

(splitChunks参考文章2)[https://jishuin.proginn.com/p/763bfbd65a2c]

(vue-cli4单独打包库参考文章)[https://blog.csdn.net/qq_34295211/article/details/104843142]

建议

如非必要尽量使用cdn加载基础模块. splitChunks配置复杂, 需考虑各种引入因素, 没完全掌握用法打包后的结果也不一定是你预料的.