写在前面
代码分割(code splitting)在webpack打包中,涉及到很多很多的知识点和配置项,这节我们将一点点做详细讲解,说到代码分割,他在工作中的地位可谓是举足轻重,在平时的一些中高级岗的面试中,也经常会问到相关知识点,学习webpack code splitting刻不容缓!
什么是代码分割(code splitting)
环境搭建
我们在package.json中创建一个开发环境下的打包命令
"dev-build": "webpack --config ./build/webpack.dev.js"
如果你将webapck的配置文件都放到了根目录下的build文件夹下,那么还需要修改一个出口配置,没有移动,则不需要。
path: path.resolve(__dirname, '../dist')
环境搭建完毕,下面我们写一点代码,我们先在本地安装个lodash库。
npm install lodash -S
写如下代码,并本地打包
import _ from 'lodash'
console.log(_.join(['a', 'b', 'c']))
代码运行没问题,但我们看main.js会发现,我们的lodash
工具库和我们的业务逻辑代码打包到了一起,假如我们的业务代码有很多很多,那将很让会带来一些潜在的问题
- 当我们的工具库很大,业务代码又很大的时候,这个时候就会导致打包文件很大,加载时间变长
- 当改变业务代码重新打包,又会生成一个很大的打包文件,重新访问页面,又会重载这个很大的打包代码
那么我们如何解决这个问题呢?
尝试优化
我们将工具库代码提出来,在src下新建一个lodash.js,内容如下
import _ from 'lodash'
window._ = _
index.js中我们只保留业务代码
console.log(_.join(['a', 'b', 'c']))
修改webpack.common.js
module.exports = {
entry: {
lodash: './src/lodash.js',
main: './src/index.js',
},
}
这时候我们打包看一下,我们发现在dist目录下会生成两个js文件
|--dist
|-- main.js
|-- lodash.js
|-- index.html
并且在index.html中也是同事引入了两个文件,我们打开index.html看是否代码能正常运行输出,结果是好的,没问题。这样我们通过换了一种打包方式,来做到了优化的目的
- main.js被拆成了lodash.js和main.js,各自有各自的大小。比如之前一共是2Mb,优化后是1mb+1mb,这样我们在访问页面的时候就不用一次加载2mb的内容了,而是分别加载1mb的内容,实践发现,同事加载两个1mb资源,要比一次加载2mb的资源,要快一点。
- 当业务代码发生变化时,只要加载main.js即可,不必再加载lodash.js,这样页面速度很变快。
在项目开发中,我们可能会用到这种把公共资源拆分出来的手段来提升打包的速度和项目的性能,这就是代码分割(Code Spiltting)
在webapck中使用Code Splitting
通过配置实现代码分割(同步加载)
上面我们通过一个例子,介绍了什么是code spiltting,但实现起来是我们手动的做了这样的拆分,实际上,webpack本身是为我们提供了这样的插件方案。下面我们来开一下,怎么在webpack中做代码分割
我们将代码恢复成做手动分割之前,包括webpack中的刚刚的配置
index.js
import _ from 'lodash'
console.log(_.join(['a', 'b', 'c']))
然后再webpack.common.js中加入下面的配置
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
}
},
}
我们暂时将上面的配置理解为“要做代码分割了”,本篇我们主要讲解关于代码的概念,后面我们会详细讲解splitChunksPlugin
这个插件。我先来感受一下,做了上面的配置后,打包发生了什么变化。
打包后的文件变成了这样
|--dist
|--index.html
|--main.js
|--vendors~main.js
我们打开main.js,拉到最下面,并没有lodash,打开vendors.js我们发现,这里将lodash做了提取,我们发现,webpack通过简单的配置,自己就知道,当遇到公用的类库的时候,就会自动的把类库进行拆分,实现了Code Splitting
异步加载
我们上面通过配置,Webpack分析出了lodash这样的类库,并做个相应的代码分割,下面我们再介绍一种方式,我们将index.js做下面的修改
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这个库,等它加载好了,就去创建一个div,并将其挂载到body上,我们现在对上面代码进行打包。打包结构变成了上面这样
(注意,对于一些低版本的webapck4可能会报异步加载的错误,到时候可以去安装babel-plugin-dynamic-import-webpack
并在.babelrc的plugin中做配置就可,这是因为低版本的webpack对这种写法还是实验性的没有完全支持)
|--dist
|--0.js
|--index.html
|--main.js
其中main.js我们拉到最后会发现,只是对index.js做了引用,而0.js中,则是对lodash做了引用。这是因为,对于我们异步引用的代码,webpack也会去做代码的分割。
写在后面
代码分割,其实没有webpack,这个概念也是存在的,通过合理的代码的代码分割,可以使我的的项目性能更高,webpack为我们通过简单的方式实现了代码分割,代替了我们手动去实现。实际上,通过本篇的介绍,大概知道代码分割有两种方式,一种是通过插件配置加同步引入的方式,一种是通过异步加载的方式。因为代码分割的概念比较多,本篇只做总体的概念和方式讲解,后面的文章中会进行详细的插件讲解。