Vue首屏优化方案小结
作者:muzidigbig
在Vue项目中,引入到工程中的所有js、css文件,编译时都会被打包进vendor.js,浏览器在加载该文件之后才能开始显示首屏。若是引入的库众多,那么vendor.js文件体积将会相当的大,影响首屏的体验。可以看个例子:
这是优化前的页面加载状态:执行 npm run build
打包项目,出来的vendeor.js文件,基本都是1M以上的的巨大文件,没有用户能忍受5s以上的loading而不关闭页面的,如图所示:
当项目在挂载到服务器上,平均都是10S+以上加载出来,好家伙这加载时间,仿佛过了半个世纪,很烦人,心态boom, 开发者甚至都有种想砸电脑的冲动
一、分析下前端加载速度慢原因
第一步:首先安装webpack的可视化资源分析工具,命令行执行:
npm i webpack-bundle-analyzer -D
第二步:然后在webpack的dev开发模式配置中,引入插件,代码如下:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') plugins: [ new BundleAnalyzerPlugin() ]
第三步:最后命令行执行 npm run build --report
, 浏览器会自动打开分析结果,如下所示:
可以看到vue全家桶相关依赖占用了很大的空间,对webpack的构建速度和网站加载速度都会有比较大的影响。单页应用会随着项目越大,导致首屏加载速度很慢,针对目前所暴露出来的问题,有以下几种优化方案可以参考:
二、优化方案
0.初步优化
初步优化,减少全局组件引入(是否放在main.js),按需引入需要的模块(echarts按需引入等),使用轻量级数据库(moment.js 切换 data-fns等)
1.采用异步组件和懒加载的方式
异步组件:
这样做的目的是在首屏渲染时减少加载文件的数量,在需要用到一些组件时才会从服务器获取,而且不会重复请求,可以有效的减少白屏的时间。
路由懒加载:
访问到当前页面才会加载相关的资源,异步方式分模块加载文件,默认的文件名是随机的id。如果在output中配置了chunkFilename,可以在component中添加WebpackChunkName,是为了方便调试,在页面加载时候,会显示加载的对应文件名+hash值,如下图:
{ path: '/Login', name: 'Login', component: () = >import( /* webpackChunkName: "Login" */ '@/view/Login') }
图片懒加载:使用vue-lazyload插件
Vue 图片懒加载 之 Vue-Lazyload-CSDN博客
//引入vue懒加载 import VueLazyload from 'vue-lazyload' //方法一: 没有页面加载中的图片和页面图片加载错误的图片显示 // Vue.use(VueLazyload) //方法二: 显示页面图片加载中的图片和页面图片加载错误的图片 //引入图片 import loading from '@/assets/images/load.jpg' //注册图片懒加载 Vue.use(VueLazyload, { // preLoad: 1.3, error: '@/assets/images/error.jpg',//图片错误的替换图片路径(可以使用变量存储) loading: loading,//正在加载的图片路径(可以使用变量存储) // attempt: 1 })
使用:
<div class="lazyLoad"> <ul> <li v-for="img in arr"> <img v-lazy="img.thumbnail_pic_s"> </li> </ul> </div>
2.webpack开启gzip压缩文件传输模式
gizp压缩是一种http请求优化方式,通过减少文件体积来提高加载速度。html、js、css文件甚至json数据都可以用它压缩,可以减小60%以上的体积。
前端配置gzip压缩,并且服务端使用nginx开启gzip,用来减小网络传输的流量大小。
webpack打包时借助 compression webpack plugin实现gzip压缩,安装插件如下:
npm i compression-webpack-plugin 或 npm install compression-webpack-plugin@6.1.1 --save-dev
在vue-cli 3.0 中,vue.config.js配置如下:
const CompressionPlugin = require('compression-webpack-plugin');//引入gzip压缩插件 module.exports = { plugins:[ new CompressionPlugin({//gzip压缩配置 filename: '[path][base].gz', algorithm: 'gzip', // 压缩算法,官方默认压缩算法是gzip test:/\.js$|\.css$|\.html$|\.eot$|\.woff$/,// 使用gzip压缩的文件类型 threshold:10240,//对超过10kb的数据进行压缩,默认是10240 deleteOriginalAssets:false,//是否删除原文件 minRatio: 0.8, // 最小压缩比率,默认是0.8 }) ] }
启用gzip压缩打包之后,会变成下面这样,自动生成gz包。目前大部分主流浏览器客户端都是支持gzip的,就算小部分非主流浏览器不支持也不用担心,不支持gzip格式文件的会默认访问源文件的,所以不要配置清除源文件。
在nginx中开启gzip:
server{ //开启和关闭gzip模式 gzip on; //gizp压缩起点,文件大于2k才进行压缩;设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。 默认值是0,不管页面多大都压缩。建议设置成大于2k的字节数,小于2k可能会越压越大。 gzip_min_length 2k; // 设置压缩所需要的缓冲区大小,以4k为单位,如果文件为7k则申请2*4k的缓冲区 gzip_buffers 4 16k; // 设置gzip压缩针对的HTTP协议版本 gzip_http_version 1.0; // gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间 gzip_comp_level 2; //进行压缩的文件类型 gzip_types text/plain application/javascript text/css application/xml; // 是否在http header中添加Vary: Accept-Encoding,建议开启 gzip_vary on; }
配置好之后,打开浏览器访问线上,F12查看控制台,如果该文件资源的响应头里显示有Content-Encoding: gzip,表示浏览器支持并且启用了Gzip压缩的资源
3.Webpack 代码分割与优化
模块拆分: 配置Webpack将代码拆分成多个小块,利用Tree Shaking、代码压缩等技术减少代码体积。这将减少初始加载所需的下载时间,提高页面加载速度。
// vue.config.js module.exports = { configureWebpack: { optimization: { splitChunks: { chunks: 'all' } } } };
4.依赖模块采用第三方cdn资源(对于第三方js库的优化,分离打包)
生产环境是内网的话,就把资源放内网,通过静态文件引入,会比node_modules和外网CDN的打包加载快很多。如果有外网的话,可以通过CDN方式引入,因为不用占用访问外网的带宽,不仅可以为您节省流量,还能通过CDN加速,获得更快的访问速度。但是要注意下,如果你引用的CDN 资源存在于第三方服务器,在安全性上并不完全可控。国内的CDN服务推荐使用 BootCDN
目前采用引入依赖包生产环境的js文件方式加载,直接通过window可以访问暴露出的全局变量,不必通过import引入,Vue.use去注册
在webpack的dev开发配置文件中, 加入如下参数,可以分离打包第三方资源包,key为依赖包名称,value是源码抛出来的全局变量。对于一些其他的工具库,尽量采用按需引入的方式。
使用 CDN 的好处有以下几个方面
(1)加快打包速度。分离公共库以后,每次重新打包就不会再把这些打包进 vendors 文件中。
(2)CDN减轻自己服务器的访问压力,并且能实现资源的并行下载。浏览器对 src 资源的加载是并行的(执行是按照顺序的)。
第一步:修改vue.config.js
module.exports = { ... externals: { 'vue': 'Vue', 'vuex': 'Vuex', 'vue-router': 'VueRouter', 'axios': 'axios', 'element-ui': 'ELEMENT', 'underscore' : { commonjs: 'underscore', amd: 'underscore', root: '_' }, 'jquery': { commonjs: 'jQuery', amd: 'jQuery', root: '$' } } ... }
如果想引用一个库,但是又不想让webpack打包,且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals
第二步:在index.html中添加cdn
<link href="https://cdn.bootcss.com/element-ui/2.7.2/theme-chalk/index.css" rel="external nofollow" rel="stylesheet"> </head> <body> <div id="app"></div> <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script> <script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script> <script src="https://cdn.bootcss.com/vue-router/3.0.4/vue-router.min.js"></script> <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script> <script src="https://cdn.bootcss.com/element-ui/2.7.2/index.js"></script> <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script> <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore-min.js"></script> </body>
第三步:去除vue.use相关代码
通过 CDN 引入,在使用 VueRouter Vuex ElementUI 的时候要改下写法。CDN会把它们挂载到window上,可以不再使用Vue.use(xxx)
main.js中 注释掉
// import Vue from 'vue'; // import iView from 'iview'; // import '../theme/index.less';
5.禁止生成map文件
在vue.config.js配置:
module.exports = { productionSourceMap: false, // 生产环境是否生成 sourceMap 文件,一般情况不建议打开 }
在设置了productionSourceMap: false之后,就不会生成map文件,map文件的作用在于:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。也就是说map文件相当于是查看源码的一个东西。如果不需要定位问题,并且不想被看到源码,就把productionSourceMap 置为false,既可以减少包大小,也可以加密源码。
6.去掉代码中的console和debugger
打包之后控制台很干净,部署正式环境之前最好这样做。vue-cli3.0
configureWebpack: config => { if (process.env.NODE_ENV === 'production') { config.optimization.minimizer[0].options.terserOptions.compress.warnings = false config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true config.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = true config.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = ['console.log'] } },
uglifyOptions去除console来减少文件大小
// 安装uglifyjs-webpack-plugin cnpm install uglifyjs-webpack-plugin --save-dev // 修改vue.config.js const UglifyJsPlugin = require('uglifyjs-webpack-plugin') module.exports = { configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { return { plugins: [ //打包环境去掉console.log new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false, drop_console: true, //注释console drop_debugger: true, //注释debugger pure_funcs: ['console.log'], //移除console.log }, }, }), ], } } } }
7. 预渲染配置
使用插件:prerender-spa-plugin
vue.config.js中配置如下:
const PrerenderSpaPlugin = require('prerender-spa-plugin'); const Render = PrerenderSpaPlugin.PuppeteerRenderer; const path = require('path'); configureWebpack: () => { if (process.env.NODE_ENV !== 'production') return; return { plugins: [ new PrerenderSPAPlugin({ // 生成文件的路径,也可以与webpakc打包的一致。 // 下面这句话非常重要!!! // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。 staticDir: path.join(__dirname, 'dist'), // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。 routes: ['/', '/Login', '/Home'], // 这个很重要,如果没有配置这段,也不会进行预编译 renderer: new Renderer({ inject: { foo: 'bar' }, headless: false, // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。 renderAfterDocumentEvent: 'render-event' }) }) ] }; }
提前加载: Vue 3的路由支持预加载功能,可在用户浏览站点时预先加载下一个页面所需的资源。这将确保用户切换页面时的迅速加载和呈现。
const routes = [ { path: '/home', component: () => import('./Home.vue'), meta: { preload: true } }, // 其他路由... ];
8.图片资源的压缩、icon资源使用、雪碧、代码压缩
严格说来这一步不算在编码技术范围内,但是却对页面的加载速度影响很大。对于所有的图片文件,都可以在一个叫tinypng的网站上去压缩一下。网址:tinypng.com/,对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。然后通过操作CSS的background属性,控制背景的位置以及大小,来展示需要的部分。
// 图片压缩设置 chainWebpack: config => { // 图片打包压缩,使用了 --- image-webpack-loader --- 插件对图片进行压缩 config.module .rule('images') .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true }) .end() },
js代码压缩- - - -(webpack 自UglifyJsPlugin插件压缩js文件)
css 代码压缩- - - - (采用optimize-css-assets-webpack-plugin插件来压缩css代码)
9. 前端页面代码层面的优化
合理使用v-if和v-show
合理使用watch和computed
使用v-for必须添加key, 最好为唯一id, 避免使用index, 且在同一个标签上,v-for不要和v-if同时使用
定时器的销毁。可以在beforeDestroy()生命周期内执行销毁事件;也可以使用$once这个事件侦 听器,在定义定时器事件的位置来清除定时器。详细见vue官网
长列表性能优化
- 图片资源懒加载
- 前端接口防止重复请求实现方案-CSDN博客
- 用innerHTML代替dom操作,减少dom操作的次数,优化js性能
- 合理使用requestAnimationFrame动画代替setTimeOut
- 通过创建文档碎片 document.createDocumentFragment()-创建虚拟dom来更新dom
10.解决白屏,体验优化
把上面所有的优化都做完之后,加载速度有了显著提升,但是在网慢的时候还是会有白屏,所以再白屏期间加骨架屏和loading就显得格外重要了。
当我们的js加载完成之后我们的img就会被覆盖了,所以这种效果是特别好的,因为静态资源是在我们的项目当中直接有的,所以加载效率会特别的快,所以尽量让图片的大小变小这样会更好的提高项目效率
到此这篇关于Vue首屏优化方案小结的文章就介绍到这了,更多相关Vue首屏优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!