【webpack快速入门】如何利用webpack代码分割,做前端性能优化?
前言
大家好,我是东东吖
,一名前端工程师。上一篇文章我们讲了摇树优化
,今天我们来讲如何通过webpack代码分割(Code Splitting)
,做前端性能优化。在日常开发中,想必大家都遇到过这种场景,那就是首次打开某个网页的速度很慢很慢,慢到白屏,需要等待很长的时间,但是当你打开过一次之后,速度就很快了,这是为什么呢?这是因为当你进入网站的时候,需要加载大量的资源,当带宽有限,就会很慢。那为什么加载第一次很慢,而从第二次起,就很快了呢?那个因为你加载过一次之后,浏览器就会有缓存,不会再次去请求资源,所以就会很快。缓存解决了再次访问的加载速度,那怎么解决首屏的加载速度呢?
初识 Code Splitling
要解决那怎么解决首屏的加载速度,核心问题还是我们的资源打包后太大了,那怎么办呢?我们可以加大带宽,这样我们的资源就会加载很快,但是如果公司没有预算加大带宽,我们该怎么办呢?在打包优化方面,我们可以对代码进行分包。
我们都知道webpack是目前最为流行的项目打包工具之一,当然其他的打包工具也很优秀。当前较为流行的前端框架也推出了基于webpack的脚手架。比如Vue框架使用Vue-cli作脚手架,react框架使用create-react-app脚手架来搭建项目的开发环境。它们都为我们项目的开发带来便利。webpack作为代码打包工具,代码分割便显得尤为重要了,因为代码被分割了,包的体积就小了,加载的速度自然就提升了,今天我们来聊一聊webpack Code Splitling(代码分割/代码分包)。
webpack代码分割有以下两种方式:
-
动态导入
-
按需加载,需要用到某个模块时,再加载这个模块,动态导入的模块会被webpack自动分包,我们在使用vue或者react进行懒加载路由就是用的这种方法。
-
多入口打包
-
适用于传统的多页应用程序,一个页面对应一个打包入口,公共模块单独提取。
动态导入
动态导入,或许我们很多同学都有用到,就是路由懒加载。但是很多同学并不清楚它为啥会提升加载速度,只是从网上了解到他是按需加载,但是其中的细节并不清楚,今天我们就来一探究竟。
平时大家在做项目的时候,都是只有首屏直接引入,其他路由进行的懒加载,那如果我们全部路由都直接引入,会发生什么呢?
我们对上面这种全部直接引入的路由进行打包,我们发现打包后的app.js的体积有3232KB。
这么大的体积,当我们带宽有限的时候,加载速度就会很慢,长时间白屏,让人很难受。据统计,一个网站打开的时间超过3秒,很多人就不想再等待它了,会直接“啪”关掉它,如果不是非用不可,那可能就再也不会打开它了,所有前端性能优化尤为重要,它决定了用户粘度和用户数量。
那如果我们只有首屏直接引入,其他路由利用懒加载的形式呢?
当我们使用懒加载路由之后,无需对webpack做任何配置,webpack会自动进行分包。`
在打包的时候,把各个模块分开进行打包,生产不同的chunk,当进入某个页面的时候,才会加载对应的包,不会全部打包到app.js,app.js的体积就变小了,加载速度自然就变快了。
多入口打包
上诉属于单页应用打包,如果是多页应用我们可以采取多入口打包,多入口打包其实和单入口打包其实是差不多,多入口打包只是要配置不同的入口和出口。
接下来我们来为多页应用打包做准备工作:
我们新先建一个home.html、home.js和about.html、about.js,这两个home和about将作为我们页面,它们都会引用一部分公共的模块,公共的方法common.js,公共的样式common.css。
//home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多入口打包-home页面</title>
</head>
<body>
<h1>多入口打包-home页面</h1>
</body>
</html>
//home.js
import "./common.css"
import { common } from "./common.js"
const home = ()=>{
console.log("home....");
}
home()
common()
//about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多入口打包-about页面</title>
</head>
<body>
<h1>多入口打包-about页面</h1>
</body>
</html>
//about.js
import "./common.css"
import { common } from "./common.js"
const about = ()=>{
console.log("home....");
}
about()
common()
我们再来建home和abpot共同引用的公共模块,公共的方法common.js和公共的样式common.css。
//common.js
export const common = ()=>{
console.log("common方法.......")
}
//common.css
h1{
color: red;
}
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
现在多页应用打包的前置条件已经准备好了,接下来我们将配置webpack多入口打包。
首先,配置多个入口和出口,出口是利用的变量[name],对应的就是入门前面的入口文件名,注释标注的部门是单入口打包的配置,同学们可以对比一下。
entry:{
about:"./src/about.js",
home:"./src/home.js",
},
// publicPath:'dist/' , //注意dist后面的/不能省略
output: {
//打包后出口
path: path.join(__dirname, "dist"), //打包后路径
filename: "[name]_bundle.js", //打包后文件名
},
其次,为home和about页面配置htmlWebpackPlugin
// 用于生成about.html
new htmlWebpackPlugin({
template:'./src/about.html',
filename:"about.html",
}),
// 用于生成home.html
new htmlWebpackPlugin({
template:'./src/home.html',
filename:"home.html",
}),
做好以上配置之后,我们就可以执行打包命令了,当打包后会生成home.html和about.html文件,还有他们对应的js文件home_bundle.js和about_bundle.js。
但是当我们打开home.html和about.html文件,他们两个文件都引用了home_bundle.js和about_bundle.js,
这样可以不行,我们想要的效果是他们各自引用自己对应的文件,那么我们需要为它们各自设置一个chunks,这样它们就能引用自己的js文件了
// 用于生成about.html
new htmlWebpackPlugin({
template:'./src/about.html',
filename:"about.html",
chunks:['about'],
}),
// 用于生成home.html
new htmlWebpackPlugin({
template:'./src/home.html',
filename:"home.html",
chunks:['home'],
}),
再次执行打包命令,观察打包结果
可以发现我们的home和about页面都现在都各自引用了自己的js文件,没有多引用其他的,这样就达到了我们想要的效果。
提取公共模块
你会发现目前我们的多入口打包已经完成了,但是目前还是会存在一些问题,比如我们的公共模块的公共方法common.js和common.css作为公共模块,在home和about中都引用了,他们会被一起打包到他们对应的js文件中,那么会有什么问题呢?
没错,现在的问题就是home_bundle.js和about_bundle.js里面都分别包含一个公共模块的方法和样式,但是其实他们是一摸一样的,如果按现在的状况,应用在启用后,就会加载公共模块加载两次,性能损耗,浪费带宽,那我们该怎么办呢?
其实很简单,我们需要把这公共的方法和样式提取出来,单独引入这些公共模块。
optimization: {
splitChunks:{
chunks:"all",
minSize: 1,
}
},
由于我们的公共模块的文件都比较小,只有1-2Kb,所以我们设置minSize为1KB。
我们再次执行打包命令。
我们会发现,就会多出两个文件,他们就是我们的公共模块被提取出来了,公共的方法和样式会被提取到src_common_js-src_common_css_bundle.js中,并起由于涉及到了css会多出一个css-loader的js文件。
我们再打开home和about页面,他们会引入三个文件,引用各种的模块和单独引入公共的模块。
以上就是如何利用webpack代码分割,做前端性能优化的全部内容,由于我们案例中,共同模块体积比较小,看不出明显的区别,但在实际项目中,当公共模块和第三方包的体积非常大时,提取公共模块在性能上就会体现出具体大差异。
结束
转载自:https://juejin.cn/post/7139438426226425869