webpack使用CommonsChunkPlugin拆包心得

更新于 2018-12-19


动机

  • 将大的vender,拆解为小的模块,提高并行加载速度
  • 避免单一vender过大问题
  • 在多页面应用中,还可细分仅加载页面必要模块

webpack 配置

webpack.chunks.conf.js

var path = require('path')
var webpack = require('webpack')


function getModuleName(module) {
  var sign = 'node_modules';
  var signIndex = module.resource.indexOf(sign);
  var pathSeparator = module.resource.slice(signIndex - 1, signIndex);
  var modulePath = module.resource.substring(signIndex + sign.length + 1);
  var moduleName = modulePath.substring(0, modulePath.indexOf(pathSeparator) );
  moduleName = moduleName.toLowerCase();

  return moduleName
}


// 需要chunks的包列表,支持正则
let chunksPackage = {
  'polyfill': ['babel-polyfill', 'core-js', 'regenerator-runtime'],
  'shim': ['media-match'],
  'axios': ['axios'],
  'anujs': ['anujs'],
  'react-router': ['react-router'],
  'bcsd': ['bcsd', '^rc-'],
  'lodash': ['lodash'],
  'redux': ['^@rematch', 'react-redux', 'redux']
}

exports.chunksWebpackConfig = {
  plugins: [
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    ...Object.keys(chunksPackage).map(packageName => {
      return new webpack.optimize.CommonsChunkPlugin({
        name: packageName,
        chunks: ['vendor'],
        minChunks: function (module, count) {
          return module.resource && chunksPackage[packageName].filter(item => new RegExp(item).test(getModuleName(module)))[0] && count >= 1
        }
      })
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: Infinity,
    }),
  ],
}

exports.htmlWebpackConfig = {
  chunks: ['manifest', 'polyfill', 'shim', 'lodash', 'bcsd', 'react-router', 'anujs', 'axios', 'vendor', 'web'],
}

webpack.dev.conf.js

......
var baseWebpackConfig = require('./webpack.base.conf')
var { chunksWebpackConfig } = require('./webpack.chunks.conf')

module.exports = merge(baseWebpackConfig, chunksWebpackConfig, {
  ......
})

依赖报错

问题: ReferenceError: webpackJsonp is not defined
描述: 页面模块依赖记载顺序问题
解决: 公共模块,必须在项目代码之前引入加载。manifest必须最先加载,因为manifest中保存的是 js 代码的引导逻辑。在 html-webpack-plugin中手动排序。

var { htmlWebpackConfig } = require('./webpack.chunks.conf')

new HtmlWebpackPlugin(Object.assign({}, {
  filename: 'index.html',
  template: 'index.html',
  inject: true,
}, htmlWebpackConfig)),

打包结果

打包生成结果

推荐阅读更多精彩内容