前言
如今各类应用功能越来越多,逻辑越来越复杂,应用体积也越来越大,在这样的趋势下如何进行性能优化是对每个工程师的考验。性能优化可谓仁者见仁智者见智,没有绝对的标准答案,它在不同的场景下会有不同的处理方式。举个例子🌰,给SQL查询条件增加索引是最常见、最简单的SQL性能优化方式。那今天我们就来聊一聊Vue-Cli3下的首屏性能优化。
配置打包分析插件
webpack-bundle-analyzer可以展示当前项目打包总体积和各个分包的体积,我们在build时使用这个插件,好让我们分析并做优化处理。我们在vue.config.js添加以下配置。
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const prodPlugins = [];
const isProduction = process.env.NODE_ENV === 'production' ? true : false;
if(isProduction) {
prodPlugins.push(new BundleAnalyzerPlugin());
}
module.exports = {
// 省略其他默认配置
configureWebpack: {
plugins: [
...prodPlugins
],
}
}
这里我们每完成一次打包,webpack-bundle-analyzer就会自动打开浏览器显示打包结果。
注:Vue-Cli中
configureWebpack是通过webpack-merge合并成最终的webpack配置,chainWebpack是通过webpack-chain来修改Vue-Cli中某个 loader 的配置项。我们可以通过vue inspect --rules、vue inspect --rule <ruleName>来查找Vue-Cli在目标loader的预设选项并做相应修改。
开启Gzip
我们还可以通过compression-webpack-plugin压缩打包完后文件的体积,通过压缩后能降低50%甚至更多的体积,我们现在配置中加入这个插件。
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const prodPlugins = [];
const isProduction = process.env.NODE_ENV === 'production' ? true : false;
if(isProduction) {
prodPlugins.push(new BundleAnalyzerPlugin());
prodPlugins.push(new CompressionWebpackPlugin());
}
module.exports = {
// 省略其他默认配置
configureWebpack: {
plugins: [
...prodPlugins
],
}
}
这个时候我们打包完会在每个文件生成对应的.gz后缀文件(也可以使用正则生成目标.gz文件),那怎么知道我们在使用这些.gz压缩文件呢?这里有两个条件:
1.浏览器需要支持HTTP压缩,可以通过发送的HTTP请求头是否有Accept-Encoding: gzip来查看
2.服务器开启gzip传输,可以通过HTTP响应头是否有Content-Encoding: gzip验证
简单一句话:浏览器和服务器分别有能力接受、传输.gz文件
那我们就使用nginx来开启gzip传输。
# 省略其他配置
http {
# 开启gzip压缩
gzip on;
# 开启静态文件传输,就是我们打包完的.gz文件
gzip_static on;
}
这个时候我们首屏加载时间已有较大缩短,当然我们还可以继续优化。
使用CDN
先简单说明下cdn:CND(Content Delivery Network 内容分发网络),能降低资源请求时间,提高传输性能。CDN为我们做了两件事:
1.让用户访问最近的节点
2.将缓存资源返回给用户(若没有缓存资源则请求后进行资源缓存,下次则直接返回缓存文件)
CDN的本质就是缓存,我们也可以将资源放到自己的CDN网络上。
回到Vue-Cli的优化,那我们为什么要在Vue-Cli中用到CDN?Vue-Cli中默认会将项目中第三方库打包到一起,这个文件就非常大(当然可以通过splitChunks进行分割) 。这些第三方库通常不会频繁改动,我们使用CDN一是能减小项目体积,二是通过CDN提高访问第三方库的效率。那我们就在vue.config.js中添加相应配置。
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const prodPlugins = [];
const isProduction = process.env.NODE_ENV === 'production' ? true : false;
if(isProduction) {
prodPlugins.push(new BundleAnalyzerPlugin());
prodPlugins.push(new CompressionWebpackPlugin());
}
const externals = isProduction ? {
'vue': 'Vue',
'element-ui': 'ELEMENT',
} : {}
const cdn = {
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.11.1/theme-chalk/index.css',
],
js: [
'https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.min.js',
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.11.1/index.js',
]
}
module.exports = {
// 省略其他默认配置
chainWebpack: (config) => {
if (isProduction) {
// 生产环境注入cdn
// 注:这里的html-plugin要根据自己项目的具体情况填,可以通过vue inspect --plugins查看,多页应用需要遍历
config.plugin('html-index')
.tap(args => {
args[0].cdn = cdn;
return args;
});
}
},
configureWebpack: {
plugins: [
...prodPlugins
],
externals
}
}
因为使用了CDN,部分第三方库就不要打包了,所以我们使用externals来在打包生产文件时排除对相应第三方库的打包,externals中的键指的是package.json依赖库的名称,值指的是CDN中对应模块导出的名称。
配合
webpack-bundle-analyzer打包分析插件我们可以将体积大的第三方库使用CDN进行请求
我们还需要在public/index.html添加对应的js/csscdn链接
<!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">
<!-- 引入样式 -->
<% if (process.env.NODE_ENV === 'production') { %>
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>">
<% } %>
<% } %>
<!-- 引入js -->
<% if (process.env.NODE_ENV === 'production') { %>
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<% } %>
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but admin_brm doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>
<% %>中可以写服务端代码,这里使用for循环遍历生成注入的css/js标签
完成CDN的配置,项目打包后的体积、访问时间又会下降很多。
打包文件微调
如果项目中使用模块动态导入,webpack会将它打包成单独的chunk文件,动态导入多则打包成的文件多,有些文件体积又非常小,这导致过多的请求降低首屏加载效率。我们可以使用webpack内置的LimitChunkCountPlugin或者MinChunkSizePlugin进行打包文件微调。
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const prodPlugins = [];
const isProduction = process.env.NODE_ENV === 'production' ? true : false;
if(isProduction) {
prodPlugins.push(new BundleAnalyzerPlugin());
prodPlugins.push(new CompressionWebpackPlugin());
prodPlugins.push(new webpack.optimize.LimitChunkCountPlugin({
// 最大chunk数
maxChunks: 15,
// 最小chunk体积
minChunkSize: 30000
}))
// prodPlugins.push(new webpack.optimize.MinChunkSizePlugin({
// 最小chunk体积
// minChunkSize: 30000
// }))
}
module.exports = {
// 省略其他默认配置
configureWebpack: {
plugins: [
...prodPlugins
],
}
}
maxChunks和minChunkSize可根据项目的实际情况进行调整,这样首屏的HTTP请求数就得到了控制,相对首屏有很多请求数的项目性能会有很好的提升。
总结
Vue-Cli3首屏性能优化的几个要点
- 可以通过引入CDN减小项目的体积
- 减少首屏请求数量减小性能开销
- 压缩静态文件
使用以上几个方法能提升大部分项目首屏的加载性能,若你们有更好的解决方案,欢迎讨论,文章中若有不对的地方,恳请指正。