前言
在一些大型项目中,前端代码在build之后得到的产物有时会非常大,大大影响我们应用上线后的用户体验。Webpack作为当下非常流行的打包工具(作者使用Webpack5),站在前端的角度,去减少build产物体积将是一个绕不开的话题,旨在提升我们Web应用的性能。本文讲根据作者实践经验,分享几种十分有效的优化方式,能够在短时间内得到高成效。
分析打包结果
我们在解决问题之前需要先分析问题,这里我们使用webpack-bundle-analyzer插件对构建产物进行分析。他是一个专门用来分析打包结果的可视化插件工具,以清晰的图像方式呈现,能够辅助我们去分析优化点。首先使用包管理器对插件进行安装。
npm i webpack-bundle-analyzer -D
我这里使用的是vue-cli,打开vue-config.js。将webpack-bundle-analyser插件引入并合并到webpack默认配置中。(推荐分文件维护开发环境和生产环境的做法)
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
};
执行npm run build命令,会自动打开一个网页,看到类似如下的效果。其中最大的chunk-vendors.js里边主要是node_moudules,主要是我们打包后依赖的第三方库;右边主要是以main.js为入口打包src后的代码。
这就是webpack-bundle-analyser插件对打包结果的可视化展现,其中2.92MB是代码打包后的大小。打包后的dist文件有足足26.6MB(包括图片等资源)。
对此情况展开分析,可以发现:
- ElementUI、lodash库占有很大空间,都被打包进去了,这部分代码是可以放在cdn去管理的,可以解放我们打包后的代码。
- 该应用有多个页面,如果直接加载岂不是没有必要,可以使用分包的方式处理。
- 页面中存在一些图片资源,占总体积的90%以上,这部分需要制定策略,将一部分较小的图片转化成base64格式。
使用CDN
CDN叫做“内容分发网络”,如果放定制的资源到CDN上一般是要收费的,领导一般对成本比较敏感,没有太大的必要可以不选择这种方式;比较建议的是一些相对稳定的免费CDN,一些公共开放的资源如Vue、Vuex、Vue-Router、ElementUI、lodash、axios可以使用,能够加速资源的访问。
CDN服务器一般有专门的厂商维护,具有较高的稳定性,有些支持HTTP2协议,我们使用CDN一定程度上能够吃到一些传输效率的福利。
寻找CDN
寻找CDN一定要寻找安全可靠的,我这里使用BootCDN,属于人气很高的免费CDN加速服务。接下来去寻找Vue、Vuex、ElementUI这些地址。可查看package.json对应寻找,尽量寻找带.min后缀的,压缩后的js体积更小。
引用CDN
找到对应的CDN后,复制标签粘贴到public/index.html中。注意:
- public/index.html在打包中会被webpack识别,被html-webpack-plugin读取,因此可以借助模板引擎提供的判断,只需在生产环境被引入。
<!DOCTYPE html>
<html lang="">
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link href="https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet">
<% if(NODE_ENV === 'production') { %>
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.14/theme-chalk/index.min.css" rel="stylesheet">
<% } %>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<% if(NODE_ENV === 'production') { %>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.6.2/vuex.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.5.1/vue-router.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.14/index.min.js"></script>
<% } %>
</body>
</html>
- 使用script引入静态js,会在全局注册对象,像Vue.use/install这类方法在生产环境中就不再适用,因此需要做一些兼容。
if (!window.VueRouter) {
Vue.use(VueRouter)
}
if (!window.Vuex) {
Vue.use(Vuex)
}
if (!window.ELEMENT) {
Vue.use(ElementUI)
}
忽略资源打包
既然用CDN的方式引用了,那么在webpack打包时就不再需要将这些依赖加入任务中,需要忽略这些依赖。找到webpack配置,加入externals。(这里简单区分一下环境,建议分文件管理)
const WebpackCommonConfigs = {
transpileDependencies: true,
};
// 生产环境
if (process.env.NODE_ENV === 'production') {
module.exports = defineConfig({
...WebpackCommonConfigs,
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
],
externals: {
vue: 'Vue',
'element-ui': 'ELEMENT',
vuex: 'Vuex',
'vue-router': 'VueRouter',
}
}
});
} else { // 开发环境
module.exports = defineConfig({
...WebpackCommonConfigs,
});
}
然后我们build一下,发现我们引用CDN后将外部依赖相关代码从2.92MB减小到283.03KB,体积减小了1000%,效果非常明显,可见第三方依赖库体积有多庞大。
页面分包处理
我们这里的策略是路由懒加载,目的是让页面和页面之间分成不同的chunk动态加载,在A页面时不用去读取B页面相关的资源,提升性能也提升用户体验。怎么做呢?非常简单!去寻找router中每个注册页面或子页面,将其改写成以下形式。
component: () => import('./general/Index.vue')
执行build不难看出,不同页面被打包成了不同的css和js, 目的达成!
可以使用注释让webpack识别,从而去自定义打包后的chunk名。
component: () => import(/* webpackChunkName: "general" */'./general/Index.vue')
图片资源优化
- 对静态图片资源进行压缩,提升渲染速率。
- 设置小于200kb的图片转化为Base64格式,减少小图片形成的多请求的情况。
图片压缩
这里使用image-webpack-loader,安装后将配置注入到vue-config.js中,设置匹配文件名、jpeg和png压缩质量等配置。
module: {
rules: [{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 60,
},
pngquant: {
quality: [0.65, 0.70],
speed: 4
},
}
},
],
}]
}
Base64转化
对小于200KB的图片转化Base64。
module: {
rules: [
{
test: /\.(gif|png|jpe?g|svg)$/i,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 200 * 1024 // 小于200kb大小的图片转base64格式
}
},
generator: {
filename: "img/[hash:7][ext]"
}
},
]
}
移除源码地图
再次查看dist目录,发现打包过后的js都存在一个对应的.map文件,这种文件叫做源码地图,用来反解析被处理过的代码。当build后,webpack会对代码进行合并、压缩、混淆等,可读性变得极差,有源码地图就能够反向解析压缩后的代码,以便于调试定位有问题的代码。
生产环境中,源码地图的存在不仅会使打包体积增大,更重要是会威胁到应用的安全性。去掉源码地图的方法极其简单,将devtool设为false就可以了。
configureWebpack: {
devtool: false,
}
总结
经过上述优化,我们打包再看看大小,发现dist大小只有11MB了,从26.6MB优化到了11MB,用数据量化就是减少了240%的体积。
利用performance工具查看LCP(最大内容绘制)参数,这个指标是用户能够看到的最大内容。为了使数据更加合理,我从大约30条同环境下数据中选择的中位数。最终经过计算得出LCP提升了28%,究其原因,主要是对静态图片做了压缩和Base64转化,在图片过大导致渲染时间长的问题上得到了较大的提升。因为页面较为简单,所以提升的幅度有限。能够控制在2.5s之内,是LCP指标定义的良好范围。
打包优化,减少包体积的方法远远不止这些,还有像Gzip压缩、代码删减、兼容性策略等。实际应用中,上述方法可谓工作量不大且效果明显,性价比很高。 看到这里,如果对您有帮助的话可以点个关注哦!当然如果有什么好的意见或者建议也可以在评论区交流或者私信。
标签:Vue,CDN,webpack,js,Webpack,体积,打包,页面 From: https://blog.csdn.net/mayuhao0000/article/details/143991216