Code Splitting

webpack4 最大的改动就是废除了CommonsChunkPlugin 引入了 optimization.splitChunks
如果你再webpack4中使用了weppack3的CommonsChunkPlugin 会出现以下报错: 
(运行配置文件 webpack3.config.js)Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks

代码分割(Code Splitting)的理念

首先搞明白: webpack里的代码分割是个什么鬼? 它允许你将一个文件分割成多个文件。其原因是基于浏览器会缓存你的代码这一事实。每当你对某一文件做点改变,访问你站点的人们就要重新下载它,包括依赖。如果你将(这些依赖)分离成单独的文件,访问者就无需多次重复下载它们了。

使用webpack生成一个或多个包含你源代码最终版本的“打包好的文件”(bundles),(概念上我们当作)它们由(一个一个的)chunks组成。

作用

提取公用代码的作用:
减少代码的冗余
提高用户的加载速度
单页面减少下载,多页面可以使用缓存

下面就开始介绍splitChunks的内容。

配置项

module.exports = {
 //...
 optimization: {
  splitChunks: {
   chunks: 'async', 
   minSize: 30000,
   minChunks: 1,
   maxAsyncRequests: 5,
   maxInitialRequests: 3,
   automaticNameDelimiter: '~', 
   name: true,
   cacheGroups: {}
  }
 }
}
复制代码


  • chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async
  • minSize: 表示在压缩前的最小模块大小,默认为30000
  • minChunks: 表示被引用次数,默认为1
  • maxAsyncRequests: 按需加载时候最大的并行请求数,默认为5
  • maxInitialRequests: 一个入口最大的并行请求数,默认为3
  • automaticNameDelimiter: 命名连接符
  • name: 拆分出来块的名字,默认由块名和hash值自动生成
  • cacheGroups: 缓存组。缓存组的属性除上面所有属性外,还有test, priority, reuseExistingChunk
    • test: 用于控制哪些模块被这个缓存组匹配到
    • priority: 缓存组打包的先后优先级
    • reuseExistingChunk: 如果当前代码块包含的模块已经有了,就不在产生一个新的代码块

默认情况

首先webpack会根据下述条件自动进行代码块分割:

  • 新代码块可以被共享引用,或者这些模块都是来自node_modules文件夹里面
  • 新代码块大于30kb(min+gziped之前的体积)
  • 按需加载的代码块,并行请求最大数量应该小于或者等于5
  • 初始加载的代码块,并行请求最大数量应该小于或等于3

块打包默认情况下只会影响按需加载模块,因为对初始块也进行优化打包会影响HTML中的script标签数,增加请求数。

例如:

模块全部是同步引入

 // indexA.js
 import React from 'react'
 import ReactDOM from 'react-dom'
 import _ from 'lodash'

 console.log(_.join(['a', 'b'], '~'))

 ReactDOM.render(
  <div>SplitChunk</div>,
  document.getElementById('root')
)
复制代码


默认情况只会影响按需加载模块,所以所有内容全部被打包到一起了。

有模块动态导入

// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import(/* webpackChunkName: "async-jquery" */ 'jquery').then(component => {
 console.log(component)
})

console.log(_.join(['a', 'b'], '~'))

ReactDOM.render(
 <div>SplitChunk</div>,
 document.getElementById('root')
)
复制代码


这里jquery使用动态导入,打包结果中可以看到jquery被单独打包了

chunks

chunks的取值是有initial, async, all。默认情况下是async

注意点:

initial 模式下会把异步和非异步模块分开打包。而 all 会把异步和非异步同时进行打包。也就是说moduleA在indexA中异步引入,indexB中同步引入, initial 下moduleA会出现在两个打包块中,而 all 只会出现一个。

cacheGroups

使用cacheGroups可以自定义配置打包块。

// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import $ from 'jquery'

// indexB.js
import React from 'react'
import ReactDOM from 'react-dom'
import('lodash')
import $ from 'jquery'

// webpack.config.js
optimization: {
 splitChunks: {
  cacheGroups: {
  commons: {
   name: 'commons',
   chunks: 'initial',
   minChunks: 2
  }
  }
 }
}
复制代码

根据开头介绍webapck分割条件,一些公共模块被打包进了commons,自定义打包块的优先级是0,所以现在公共模块会被打包进commons,而不是上述提到的默认打包块vendors(优先级为负)。

但是这边为什么lodash为什么没打包在一起呢?可以回顾下initial和all的区别。接下来实验下all的效果。

// indexA, indexB同上
// webpack.config.js
optimization: {
 splitChunks: {
  cacheGroups: {
   commons: {
    name: 'commons',
    chunks: 'all',
    minChunks: 2
   }
  }
 }
}
复制代码

结果在预期中,lodash被打包在一起了。

提取第三方库

最后看下之前CommonsChunkPlugin常用的分离部分第三方库功能。这边你可以想一下怎么操作。

上面已经提到了设置 chunks: initial || all 都可以提取出第三方库。但是它是把所有第三库提取出来,所以我们在只提取react和react-dom的情况下,需要自定义一个cacheGroup。

// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import $ from 'jquery'

// webpack.config.js
entry: {
 indexA: path.join(__dirname, 'src/indexA.js')
},
optimization: {
 splitChunks: {
  chunks: 'all',
  cacheGroups: {
   vendors: {
    test: /react/,
    name: 'vendors'
   }
  }
 }
}
复制代码

我们去重写了vendors打包块,只打包匹配react的模块,所以达到了之前CommonsChunkPlugin的功能。

最后

mainfast(文件与文件之间的关联代码)
老版本打包中,文件之间的关联代码在各关联文件中,当修改其中一个文件时,关联代码可能会发生改变,导致没修改过的文件的hash值也跟着改变,并且会导致文件内存变大
用runtimeChunk解决以上问题
将文件与文件之间关联的代码放到runtime.js文件中

runtimeChunk: { name: 'runtime'},
//等价于
runtimeChunk:'runtime'
复制代码


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值