webpack从nodes_modules提取模块

将node_modules中的文件打包到common.js,体积太大,想从中抽取出一个vendor模块,如entry中声明的那样,但是下面的配置并不能从common中抽取中vendor,打包结果是vendor只有1kb,怎么的配置可以实现从common中提取vendor呢?

entry: {
        vendor: ['vue', 'vuex', 'vue-router', 'vuex-router-sync','vue-resource']
}
//plugin
new webpack.optimize.CommonsChunkPlugin({
      name:'common',
      minChunks: function (module, count) {
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
}),
new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    chunks:['vendor','common']
})
阅读 7.7k
1 个回答

Webpack API 确实烂(底层),光看 CommonsChunkPlugin 的文档很难看懂,最好是结合一些实例来使用。

下面是 webpack 自己提供的两个示例

在实际使用中发现上面的配置方式不能完全的提取第三方库的模块。因为代码里可能使用第三方库名加子路径的方式引用模块,例如: require(lodash/throttle),如果我们只在 vendor 的入口模块写成这样 entry: { vendor: ['lodash', ...], ... },那么最终打包出来的 vendor 文件包含 'lodash',而自己的程序打包文件还是包含第三方模块 lodash/throttle,及其相关的依赖。

看官方文档 CommonsChunkPlugin 的参数属性 minChunks 是可以设置为函数的,返回 true 或 false 来决定一个模块是否要提取到这个公共代码块里。例如下面的配置:

{
   ...,

   plugins: [
     new webpack.optimize.CommonsChunkPlugin({
       name: "common", // 可以随便命名,不用与 entry 匹配,但必须设置
       filename: "common.js", // 打包输出文件名称
       minChunks: function(module) {
         return /node_modules/.test(module.userRequest || ''); // 所有 node_modules 下的模块都打包到这个公共代码块中
       },
     })
   ],
   ...
}

如果项目第三方依赖比较多,打包结果也会比较大,还需要进行划分第三方库,例如:划分出 base.js 和 react.js,前者包含一些 polyfill 和基础工具库,后者包含 react 相关的代码,这样打包出来的文件大小会比较适合。关于如何使用 CommonsChunkPlugin 配置可以参考我自己写的一些示例:

  • CommonsChunkPlugin:CommonsChunkPlugin 用法分析和一些示例,只写了提取第三方库的部分

  • react-boilerplate:我自己整理的一个 React 项目模板,可以供进阶用户阅读参考使用,不推荐新手使用

按问题的配置来看,common 会提取所有 node_modules 下的模块,后面的 vendor 没有再设定 minChunks,导致 vendor 不会提取任何模块。可以在设置个函数,然后判断将需要的模块返回 true。例如改成:

entry: {
    ...
}
//plugin
new webpack.optimize.CommonsChunkPlugin({
      name:'common',
      minChunks: function (module, count) {
       // 这里提取所有 node_modules,下面的 vendor 再从中提取 vue 相关的模块
        return /node_modules/.test(module.userRequest || '');
      }
}),
new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    chunks:['common'],
    minChunks: function (module, count) {
       // 这里写匹配你要提取的 vue 相关的模块,会将所有 vue 相关的模块提取到 vendor 里
       // ps:随手写的,自己测试完善
        return /node_modules\/(vue|vuex)/.test(module.userRequest || '');
      }
})

PS:以上都是针对 Webpack1 写的。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题