目录
1. 概述
2. 性能优化切入点分析
2.1 vue-router
2.2 打包优化
2.3 压缩技术
3. 性能优化实践
3.1 vue-router优化
3.1.1. 异步加载
3.1.2. 按需加载
3.2 打包优化
3.3 前端工程压缩
Web应用的优化方案一般分为两类:第一类是基于硬件的优化,第二类是基于软件的优化。基于硬件的优化主要包括扩大带宽、负载均衡、服务集群等方式,而这些依托于硬件的提升都需要公司去承担巨额的支付成本。较之而言,对软件的优化以及技术的革新更加具有实际意义。一般来说,一个Web网页,不止包含必要的HTML文件,还包含很多其他的相关资源文件,比如CSS文件、JavaScript文件、图像等等,这些文件一起构成了页面组件。通过Web前端构成元素以及请求响应机制的分析,本方案从vue-router优化、打包优化、压缩技术三个方面给出Vue前端性能的优化方案。
vue-router是Vue官方提供的路由管理器,又称路由懒加载,是指将不同路由所对应的组件划分为不同的代码块,然后只有在访问路由时才会加载相应的组件。这样既可以提高Web项目的加载速度也可以提高页面响应效率。本方案分别从Vue的异步组件和Webpack的代码分割功能两方面对vue-router路由懒加载进行实现。
1. Vue异步组件
在Web应用中,可以将应用分割成比较小的代码块,只在需要的时候从服务器端加载所需模块。Vue为了对代码进行精简,可以让开发者以工厂函数的方式定义组件,而该工厂函数可以异步地对组件定义进行解析。Vue只会在该组件被渲染的时候才去触发该工厂函数,并将结果进行缓存以便将来重新进行渲染。该工厂函数会收到一个resolve回调函数,这个回调函数会在得到服务器命令的时候被调用,也可以调用reject(reason) 方法来表示加载失败。在获取组件的时候,也可以将异步组件和webpack的code-splitting功能一起配合使用,将效果达到最优化。
2. Webpack代码分割
Webpack是当下非常流行的一款代码编译工具,其代码分割功能可以将代码分离到不同的模块中,以便能够并行或按需加载这些模块。进行代码分割不仅可以控制资源加载的优先级,而且还能够获得更小的模块。常见的代码分割方式主要有以下三种:
Web应用打包优化可以优化项目启动速度和性能,进行必要的数据清理,减少打包后的体积。本方案的打包优化思路有以下三点:
Web页面的第一次加载,是在浏览器没有缓存的情况下的,也就是从服务器端通过网络下载到客户端的过程。影响网页加载速度的因素有很多,从硬件上来讲,有服务器端、客户端和网速(带宽)三个方面。硬件因素的改进都是无法简单做到的,可控的因素是减少HTTP请求和减少页面大小。为了减小页面大小,压缩源文件就成了最为重要的一步。几乎所有的Web站点,都会用到JavaScript脚本表和CSS样式表,页面在首次加载的时候,缓存为空,页面中每一个资源文件都要单独进行一次HTTP请求。因此在Web前端开发过程中,为了符合模块化的开发原则,通常会把JavaScript文件和CSS文件各自汇总保存在独立的文件中。除了对相关资源文件进行整合,还应该分别对CSS与JavaScript文件进行压缩,尽量使整个前端页面中的相关文件体积最小化。
vue-router配置访问路由时,组件采用异步加载的方式引入。
√ 推荐的用法:
{
path: '/flowPublicDetail/:id',
name: "flowEformDetail",
component:() => import('../pages/system/flowPublicDetail/index.vue'),
hidden: true,
meta: { title: "flowEformDetail" },
},
× 不推荐的用法:
home: { path: '/', component: Home, hidden: true },
login: { path: '/user/login', component: Login, hidden: true },
1. 按需加载非全局使用的组件库,须组件库支持。
√ 推荐的用法:
import { Row, Col } from 'ant-design-vue';
import { AvicLayout } from "avic-foundation/es/layout";
× 不推荐的用法:
import Antd from 'ant-design-vue'
2. 避免在入口文件 main.js 中全局注册三方组件、组件库,需要的组件、组件库应在具体业务模块引入。
√ 推荐的用法:
// 业务模块
import Button from 'ant-design-vue/lib/button';
import 'ant-design-vue/lib/button/style';
// 或者 ant-design-vue/lib/button/style/css // 加载 css 文件
× 不推荐的用法:
// main.js 入口文件
import Antd from 'ant-design-vue'
Vue.use(Antd)
3. 避免引用应用中不使用的组件。
1. 减少预加载、忽略调试代码。
移除预加载:
chainWebpack: (config) => {
// 移除预加载
config.plugins.delete('prefetch')
}
忽略调试代码,使用UglifyJsPlugin去掉console 可以略微降低文件大小:
config.plugins.push(
// 使用UglifyJsPlugin去掉console 可以略微降低文件大小
new UglifyJsPlugin({
uglifyOptions: {
compress: { drop_console: true, drop_debugger: true },
},
})
);
2. 降低打包后的资源总体积。
使用externals避免将通用三方组件打包到每个应用组件中:
externals: {
"ant-design-vue": "ant-design-vue",
"moment": "moment",
"../moment": "moment",
lodash: "lodash",
"lodash.isequal": "lodash.isequal",
"lodash.differencewith": "lodash.differencewith",
"vue-grid-layout": "vue-grid-layout",
"awe-dnd": "awe-dnd",
"core-js": "core-js",
"element-resize-detector": "element-resize-detector",
sortablejs: "sortablejs",
"v-viewer": "v-viewer",
vue: {
root: "Vue",
commonjs: "vue",
commonjs2: "vue",
amd: "vue"
},
"vue-draggable-resizable": "vue-draggable-resizable",
"vue-upload-component": "vue-upload-component",
vuedraggable: "vuedraggable",
vuescroll: "vuescroll",
xlsx: "xlsx",
vuex: "vuex"
},
Less 文件处理:
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
},
{
loader: "less-loader",
options: {
javascriptEnabled:true,//允许链式调用的换行
sourceMap: true,
lessOptions: {
strictMath: true,
},
},
},
],
},
图片文件处理:url-loader能将小于某个大小的图片进行base64格式的转化处理。
{
test: /\.(png|svg|jpg|gif)$/,
loader: "url-loader?limit=1048576&name=images/[hash:8].[name].[ext]"
},
按需打包moment.js:moment.js 占用空间大的原因在于,moment中包含了大量语言资源文件,我们并不需要这些。通过webpack自身的功能即可在打包时丢弃这些无用的内容:
// 配置需要保留的 moment 插件语言包
config.plugins.push( new MomentLocalesPlugin({
localesToKeep: ['zh-cn'],
}))
3. 分包:将公共组件、较大的资源单独打包,减少首屏加载的资源数量。
使用SplitChunkPlugin插件将公共模块代码提取出来,防止代码被重复打包,拆分过大的js文件,合并零散的js文件。
config.when(true, config => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
vender: {
name: 'chunk-vender',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial',
reuseExistingChunk: true
},
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 20,
minChunks: 3,
chunks: 'async',
reuseExistingChunk: true
},
xlsx: {
name: 'chunk-xlsx',
priority: 100,
test: /[\\/]node_modules[\\/]_?xlsx(.*)/,
},
moment: {
name: 'chunk-moment',
priority: 110,
test: /[\\/]node_modules[\\/]_?moment(.*)/,
},
antd: {
name: 'chunk-antd',
priority: 120,
test: /[\\/]node_modules[\\/]_?ant-design-vue(.*)/,
},
}
});
})
使用compression-webpack-plugin插件对前端工程进行Gzip压缩。修改vue.config.js文件:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
// const isProduction = process.env.NODE_ENV === 'production'
module.exports = {
configureWebpack:{
resolve:{
alias:{
'@':path.resolve(__dirname, './src'),
}
},
plugins: [
// 下面是压缩插件的配置
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 5,
minChunkSize: 100
})
]
}
}
Gzip还需要服务端支持,一般在nginx上做配置。修改nginx配置,在server里添加以下代码,与listen同级:
gzip on;
gzip_comp_level 5;
gzip_min_length 10;
gzip_static on;
gzip_buffers 16 64k;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml font/ttf font/otf image/svg+xml;
gzip_vary on;