Vue-Cli3首屏性能优化

2,908 阅读5分钟

前言

如今各类应用功能越来越多,逻辑越来越复杂,应用体积也越来越大,在这样的趋势下如何进行性能优化是对每个工程师的考验。性能优化可谓仁者见仁智者见智,没有绝对的标准答案,它在不同的场景下会有不同的处理方式。举个例子🌰,给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 --rulesvue 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
	],
  }
}

maxChunksminChunkSize可根据项目的实际情况进行调整,这样首屏的HTTP请求数就得到了控制,相对首屏有很多请求数的项目性能会有很好的提升。

总结

Vue-Cli3首屏性能优化的几个要点

  • 可以通过引入CDN减小项目的体积
  • 减少首屏请求数量减小性能开销
  • 压缩静态文件

使用以上几个方法能提升大部分项目首屏的加载性能,若你们有更好的解决方案,欢迎讨论,文章中若有不对的地方,恳请指正。