Webpack 提取公共代 CommonsChunkPlugin

5,123 阅读4分钟

背景 

如果不提取公共部分会有什么后果? 

  1. 相同资源重复加载引用,浪费用户流量以及服务器成本;

  2. 每个页面需要加载的资源太多,导致网页首页加载缓慢; 

提取之后有什么优点? 

  1. 相同资源只打包加载一次,减少网络传输流量,降低服务器压力; 

  2. 页面加载速度加快,提交用户体验; 

具体用法 

思路 

  1. 根据项目使用的技术栈,把所有页面都要使用到的基础库提取出来,形成一个`base.js`,这个文件包含技术栈运行所需要的所有基础环境依赖;(只要技术栈不变,基本可以持久缓存) 

  2. 剔除所有公共基础依赖代码之后,再从所有页面中把都依赖的公共代码提取出来,形成一个`common.js`; 

  3. 再为每个页面生成一个独立的文件,那这些文件就不再包含`base.js`、`common.js`的代码,只包含各个页面独立的业务代码; 


定义与概念 

CommonsChunkPlugin用于提取公共代码,根据配置,把基础库以及业务逻辑公共代码抽离提取出来,减少资源重复引用; 

CommonsChunkPlugin 对单入口文件不能提取公共的代码,只能提取webpack runtime的环境代码;提取的对象是

配置参数

name: ''

提取公共代码的文件名

names: string[]

names中配置的是入口名,不是路径,如果这里配置的名字与 入口chunk(输出文件名,在entry中设置或在动态输出)中的对应起来,则直接提取,如果没有在entry中同名,则创建一个包含webpack运行环境的环境代码,并作为抽离内容,把运行环境从提取入口中抽离出来;

chunks: string[]

chunks 配置的是提取公共代码的源,即需要在哪些入口中提取公共的代码;我的理解是这里如果自由配置的话,应该是要在入口chunk那里选择需要提取的入口(这个不知道对不对,因为我如果直接引用文件路径的话,效果没看到)

如果不设置这个值,所有入口chunk,都会作为提取的对象

filename: string

common chunk 文件名模版,如果不设置,则不修改原来的文件名(也不会修改在name/names中配置的名字,但是如果配置了,优先使用)

minChunks: number | Infinity | function(module, count) => boolean

number  一个模块被提取之前,必须要在 入口chunks中出现的至少次数;

Infinity  默认是对所有chunk进行提取;

function(module, count) => boolean  自定义提取的规则

minChunks取值需大于2,小于chunks的长度(即chunks配置项的长度或所有入口的长度)

minSize: number

在公共模块创建之前,所有 公共模块的最小大小

children: boolean

如果设置为 true,所有 公共chunk 的子模块都会被选择;一般不设置这个值,毕竟我们值为了对公共代码的抽离,而不是想要全部抽离;不过这个也要针对不同的项目来处理,毕竟配置这个东西也是很自由的;

async:boolean|string

这个暂时没有研究出来是什么.....

具体配置

这个的配置一点也不复杂,主要是要根据实际情况进行配置比较复杂,情况一般分成下面几种

  1. 项目是单入口应用还是多入口应用,这决定你是否合适使用CommonsChunkPlugin  

  2. 对哪些入口chunk进行提取,这决定了 nameschunkschildren配置项的设置

  3. 提取的粒度,这决定了minChunksminSize配置项的设置

基本上根据上面几条,然后配置entry以及plugin就OK了,抽取的思路文章开头也提到了,所以就不列举各种情况了

// 提取公共代码主要修改的范围如下,
// manifest 的提取是把webpack启动运行部分代码,把部分代码抽离出来,
// 那每次业务代码有修改时,并不会影响到这个文件的hash,那就可以持久化在浏览器,减少用户加载的流量
module.exports = {  
  entry: {    
    main: ['./src/index.js'],    
    vendor: ['react']  
  },  
  plugins: [    
    new webpack.optimize.CommonsChunkPlugin({      
      names:['vendor', 'manifest'],          
      children: false,     // 是否对所有源chunks的子模块都包含          
      minChunks: 2,        // 提取代码的粒度          
      // chunks: [],       // 需要提取公共代码的源chunks     
    }),  
  ]
}