写在前面
我们在上篇的文章中,介绍了Code Splitting,其中有通过SplitChunksPlugin
加同步引入的方式进行代码分割,和通过异步加载的方式让webpack自动帮我们完成代码分割,上篇中,我们也是主要对代码分割的概念和方式做了介绍和操作,其中提到的SplitChunksPlugin
和异步加载只是简单使用了一下,这篇我们将详细学习SplitChunksPlugin
的参数配置和异步加载。
异步加载中的魔法注释
我们再来看这段代码
function getComponent () {
return import('lodash').then(({ default: _ }) => {
var element = document.createElement('div')
element.innerHTML = _.join(['a', 'b', 'c'])
return element
})
}
getComponent().then(element => {
document.body.appendChild(element)
})
其中lodash是一种通过异步引入的,那么webapck在打包的时候就会自动帮我们把代码做分割,我们知道现在lodash会生成一个0.js的文件,其实这是一个ID,那我们想把这个名字换成一个相应的英文名字,那该怎么做呢?这就是魔法注释。我们将动态引入改成下面这样
import(/* webpackChunkName:"lodash" */'lodash')
代表我们将异步引入的文件,打包后生成名为“lodash”的文件
再打包试一下,这时候会发现目录变成了这样
|--dist
|--index.html
|--main.js
|--vendors~lodash.js
(对于一些webapck 低版本v4可能达到预期,这时候,你需要装一个官方的babel插件,让异步加载来支持这种魔法注释(@babel/plugin-syntax-dynamic-import
))
这时候有人就会疑问了“我们明明给他的文件明明是“lodash”为什么打包出来的文件前面加入了一个‘vendors~呢?’”加下来大家就和我一起学习插件SplitChunksPlugin
。
SplitChunksPlugin
在上篇中,我们曾简单用了它一下,体验了一下code splitting,但其实他的配置内容有很多,这里我将对这个插件做详细的配置讲解,这是官网对他的介绍,同学们也可以参考官网SplitChunksPlugin
我们将webpack.common.js
中的optimization
项先改成下面这样,这次再对刚才的项目做打包看一下。
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: false,
default: false
}
}
},
我们发现打包文件中vendors~lodash.js
变成了lodash
。这说明
SplitChunksPlugin插件对于异步加载的模块也是有影响的,无论是我们做同步的代码分割还是异步的代码分割,我们都需要用到这个插件!!
下面就是每一个参数的详解,看官网,这个插件是有一个默认配置如下
splitChunks: {
chunks: "async",
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
我们将vendors和default都置为false,以免对其他配置项进行影响。
chunks:initial
、async
、all
chunks有三个值,意思是我们对哪种代码做分割,有异步,有同步,有所有类型,上面的默认配置中他的值是async
,意思是这个插件只对异步加载的模块生效,下面我们将index.js中的模块改成同步引入
import _ from 'lodash'
var element = document.createElement('div')
element.innerHTML = _.join(['a', 'b', 'c'])
document.body.appendChild(element)
打包一下,大家可以看到,对于同步的模块引入是没有进行代码分割的,下面我们将chunks的值改为all,再打包一下,发现还是没有生效哈,这是因为,当我们将chunks
的值设为all的时候,webpack会知道我们将对同步引入的模块进行打包,但业务代码中各种逻辑的引入其实一般都是同步引入的方式,这样就会给分割带来困难,于是他会跳转到cacheGroups
中查看相关配置,那现在我们先将cacheGroups.vendors
改为官网默认的
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
这时候再打包,发现打包目录变成了下面这样
|--dist
|--index.html
|--main.js
|--vendors~main.js
意思是我们代码分割成功了,看vendors.main.js
中,也是对lodash库的引用。vendors~main.js前面的vendors代表,我们的lodash符合vendors组的要求,所以前缀就变成了这个组的名字,其中的main代表这个库的引入是入口是main.js,也就是其对应的index.js。
cacheGroups.vendors
有时候我们希望我们将所有的类库都打包到一个'vendors.js'的文件中,这时候,我们就可以在vendors.filename
中配置
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
filename: 'vendors.js'
},
这时候打包看一下。文档目录变成了这样
|--dist
|--index.html
|--main.js
|--vendors.js
这样配置的意思是,一旦我们对同步代码做风格,他就会到cacheGroups里面找匹配,一旦匹配了相应的组,就会按照这个组的一些配置做相应的分割,他和chunks
是配合使用的
minSize
当引入的库大于该值时才做代码分割,小于的话就不做大吗风格了,大家可以在这里把minSize
设的特别大来验证一下
cacheGroups.default
这里我们新建一个test.js导出一个特别简单的内容,并将minSize
改为0,来打包测试一下
export default {
name: 'hello webpack'
}
index.js
import test from './test'
console.log(test.name)
现在的内容和你简单,按照上面minsize的配置,我们将其设为0,他是理应会执行代码分割的,但打包发现,他并没有按照预期去执行代码分割,这是因为webpack在打包时,因其满足minsize,又是代码,就会去执行cacheGroups
中的代码,但他又不符合vendors
组的规则(不是node_modules下的内容),所以就没有将其正常风格,这时候我们就需要用到cacheGroups.default
,我们先将官网的默认配置拷贝过来,去掉cacheGroups.default.minChunks
参数,执行打包,我们发现,打包目录变成了这样
|--dist
|--index.html
|--main.js
|--default~main.js
其打包的命名规则和配置规则和cacheGroups.vendors
相同。我们也可以给其设置一个filename。
minChunks
minChunks代表一个模块被应用了多少次的时候才进行代码分割。
maxAsyncRequests
代表同时加载的模块数最大值,这里的默认值是5,假如我们有10个模块文件被分割,这里会将前五个模块分割,其他的就不分割了,一般取默认配置
maxInitialRequests
代表整个网站首页加载的时候,入口文件最大的加载数,如果入口文件引入的模块数大于这个值,其他的将不会被做代码分割,一般取默认配置
automaticNameDelimiter
代表组和文件名之前的连接符
name
设置为true
代表我们在组中设置的文件名有效,一般不改默认配置
cacheGroups.*.priority
代表组的权重,有的模块会同事满足多个组的规则,比如我们现在的lodash就同时满足vendors
和default
两个组的要求,这时候就需要一个权重值来让模块优先执行哪个组的打包。
cacheGroups.**.reuseExistingChunk
默认为true,遇到多个模块相互引用的时候,当一个模块被重复使用,那么将不会重新打包,将使用之前打包的路径
写在最后
本篇也是比较详细的介绍了SplitChunksPlugin
这个插件,其实其内容还远比文章中介绍的多,有兴趣的同学可以去官网再去查阅相关的资料。用好SplitChunksPlugin
你的代码打包将变的效率更高,学习一下吧~