• Vue首屏优化方案


    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开发模式配置中,引入插件,代码如下:

    1. const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
    2. plugins: [
    3. new BundleAnalyzerPlugin()
    4. ]

    第三步:最后命令行执行 npm run build --report  , 浏览器会自动打开分析结果,如下所示:

     

     可以看到vue全家桶相关依赖占用了很大的空间,对webpack的构建速度和网站加载速度都会有比较大的影响。单页应用会随着项目越大,导致首屏加载速度很慢,针对目前所暴露出来的问题,有以下几种优化方案可以参考: 

    二、优化方案

    0.初步优化

    初步优化,减少全局组件引入(是否放在main.js),按需引入需要的模块(echarts按需引入等),使用轻量级数据库(moment.js 切换 data-fns等) 

    1.采用懒加载的方式

    路由懒加载和组件懒加载:

    访问到当前页面才会加载相关的资源,异步方式分模块加载文件,默认的文件名是随机的id。如果在output中配置了chunkFilename,可以在component中添加WebpackChunkName,是为了方便调试,在页面加载时候,会显示加载的对应文件名+hash值,如下图:

    1. {
    2. path: '/Login',
    3. name: 'Login',
    4. component: () = >import( /* webpackChunkName: "Login" */ '@/view/Login')
    5. }

     

    图片懒加载:使用vue-lazyload插件

    1. //引入vue懒加载
    2. import VueLazyload from 'vue-lazyload'
    3. //方法一: 没有页面加载中的图片和页面图片加载错误的图片显示
    4. // Vue.use(VueLazyload)
    5. //方法二: 显示页面图片加载中的图片和页面图片加载错误的图片
    6. //引入图片
    7. import loading from '@/assets/images/load.jpg'
    8. //注册图片懒加载
    9. Vue.use(VueLazyload, {
    10. // preLoad: 1.3,
    11. error: '@/assets/images/error.jpg',//图片错误的替换图片路径(可以使用变量存储)
    12. loading: loading,//正在加载的图片路径(可以使用变量存储)
    13. // attempt: 1
    14. })

    2.webpack开启gzip压缩文件传输模式

    gizp压缩是一种http请求优化方式,通过减少文件体积来提高加载速度。html、js、css文件甚至json数据都可以用它压缩,可以减小60%以上的体积。

    前端配置gzip压缩,并且服务端使用nginx开启gzip,用来减小网络传输的流量大小。

     webpack打包时借助 compression webpack plugin实现gzip压缩,安装插件如下:

    npm i -D compression-webpack-plugin

    在vue-cli 3.0 中,vue.config.js配置如下:

    1. const CompressionPlugin = require('compression-webpack-plugin');//引入gzip压缩插件
    2. module.exports = {
    3. plugins:[
    4. new CompressionPlugin({//gzip压缩配置
    5. test:/\.js$|\.html$|\.css/,//匹配文件名
    6. threshold:10240,//对超过10kb的数据进行压缩
    7. deleteOriginalAssets:false,//是否删除原文件
    8. })
    9. ]
    10. }

    启用gzip压缩打包之后,会变成下面这样,自动生成gz包。目前大部分主流浏览器客户端都是支持gzip的,就算小部分非主流浏览器不支持也不用担心,不支持gzip格式文件的会默认访问源文件的,所以不要配置清除源文件。

    在nginx中开启gzip:

    1. server {
    2. gzip on;
    3. gzip_buffers 32 4K;
    4. gzip_comp_level 6;
    5. gzip_min_length 100;
    6. gzip_types application/javascript text/css text/xml application/json;
    7. gzip_vary on;
    8. listen 80;
    9. listen [::]:80 ;
    10. 。。。。。。。。

    配置好之后,打开浏览器访问线上,F12查看控制台,如果该文件资源的响应头里显示有Content-Encoding: gzip,表示浏览器支持并且启用了Gzip压缩的资源

     

    3.依赖模块采用第三方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

    1. module.exports = {
    2. ...
    3. externals: {
    4. 'vue': 'Vue',
    5. 'vuex': 'Vuex',
    6. 'vue-router': 'VueRouter',
    7. 'axios': 'axios',
    8. 'element-ui': 'ELEMENT',
    9. 'underscore' : {
    10. commonjs: 'underscore',
    11. amd: 'underscore',
    12. root: '_'
    13. },
    14. 'jquery': {
    15. commonjs: 'jQuery',
    16. amd: 'jQuery',
    17. root: '$'
    18. }
    19. }
    20. ...
    21. }

    如果想引用一个库,但是又不想让webpack打包,且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals

    第二步:在index.html中添加cdn

    1. <link href="https://cdn.bootcss.com/element-ui/2.7.2/theme-chalk/index.css" rel="stylesheet">
    2. head>
    3. <body>
    4. <div id="app">div>
    5. <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js">script>
    6. <script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js">script>
    7. <script src="https://cdn.bootcss.com/vue-router/3.0.4/vue-router.min.js">script>
    8. <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js">script>
    9. <script src="https://cdn.bootcss.com/element-ui/2.7.2/index.js">script>
    10. <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js">script>
    11. <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore-min.js">script>
    12. body>

    第三步:去除vue.use相关代码

    通过 CDN 引入,在使用 VueRouter Vuex ElementUI 的时候要改下写法。CDN会把它们挂载到window上,可以不再使用Vue.use(xxx)

    main.js中 注释掉

    1. // import Vue from 'vue';
    2. // import iView from 'iview';
    3. // import '../theme/index.less';

    4.禁止生成map文件

    vue.config.js配置:

    1. module.exports = {
    2. productionSourceMap: false, // 生产环境是否生成 sourceMap 文件,一般情况不建议打开
    3. }

    在设置了productionSourceMap: false之后,就不会生成map文件,map文件的作用在于:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。也就是说map文件相当于是查看源码的一个东西。如果不需要定位问题,并且不想被看到源码,就把productionSourceMap 置为false,既可以减少包大小,也可以加密源码。

    5.去掉代码中的console和debugger

    打包之后控制台很干净,部署正式环境之前最好这样做。vue-cli3.0

    1. configureWebpack: config => {
    2. if (process.env.NODE_ENV === 'production') {
    3. config.optimization.minimizer[0].options.terserOptions.compress.warnings = false
    4. config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
    5. config.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = true
    6. config.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = ['console.log']
    7. }
    8. },

    uglifyOptions去除console来减少文件大小

    1. // 安装uglifyjs-webpack-plugin
    2. cnpm install uglifyjs-webpack-plugin --save-dev
    3. // 修改vue.config.js
    4. configureWebpack: config => {
    5. if (isProduction) {
    6. .....
    7. config.plugins.push(
    8. new UglifyJsPlugin({
    9. uglifyOptions: {
    10. compress: {
    11. warnings: false,
    12. drop_debugger: true,
    13. drop_console: true,
    14. },
    15. },
    16. sourceMap: false,
    17. parallel: true,
    18. })
    19. )
    20. }
    21. }

    6. 预渲染配置

    使用插件:prerender-spa-plugin 

    vue.config.js中配置如下:

    1. const PrerenderSpaPlugin = require('prerender-spa-plugin');
    2. const Render = PrerenderSpaPlugin.PuppeteerRenderer;
    3. const path = require('path');
    4. configureWebpack: () => {
    5. if (process.env.NODE_ENV !== 'production') return;
    6. return {
    7. plugins: [
    8. new PrerenderSPAPlugin({
    9. // 生成文件的路径,也可以与webpakc打包的一致。
    10. // 下面这句话非常重要!!!
    11. // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
    12. staticDir: path.join(__dirname, 'dist'),
    13. // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
    14. routes: ['/', '/Login', '/Home'],
    15. // 这个很重要,如果没有配置这段,也不会进行预编译
    16. renderer: new Renderer({
    17. inject: {
    18. foo: 'bar'
    19. },
    20. headless: false,
    21. // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
    22. renderAfterDocumentEvent: 'render-event'
    23. })
    24. })
    25. ]
    26. };
    27. }

    7.图片资源的压缩,icon资源使用雪碧

    严格说来这一步不算在编码技术范围内,但是却对页面的加载速度影响很大。对于所有的图片文件,都可以在一个叫tinypng的网站上去压缩一下。网址:tinypng.com/,对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。然后通过操作CSS的background属性,控制背景的位置以及大小,来展示需要的部分。

    1. // 图片压缩设置
    2. chainWebpack: config => {
    3. // 图片打包压缩,使用了 --- image-webpack-loader --- 插件对图片进行压缩
    4. config.module
    5. .rule('images')
    6. .use('image-webpack-loader')
    7. .loader('image-webpack-loader')
    8. .options({ bypassOnDebug: true })
    9. .end()
    10. },

    8. 前端页面代码层面的优化

    1. 合理使用v-if和v-show

    2. 合理使用watch和computed

    3. 使用v-for必须添加key, 最好为唯一id, 避免使用index, 且在同一个标签上,v-for不要和v-if同时使用

    4. 定时器的销毁。可以在beforeDestroy()生命周期内执行销毁事件;也可以使用$once这个事件侦听器,在定义定时器事件的位置来清除定时器。详细见vue官网

    5. 长列表性能优化

    6. 图片资源懒加载

    9.解决白屏,体验优化

     上边已经讲述了优化问题,把 所 有 的 优 化 都 做 完 之 后 , 加 载 速 度 有 了 显 著 提 升,把所有的优化都做完之后,加载速度有了显著提升}把所有的优化都做完之后,加载速度有了显著提升把所有的优化都做完之后,加载速度有了显著提升,但是再网慢的时候还是会有白屏,所以再白屏期间加骨架屏和loading就显得格外重要了。

    1. <body>
    2. //这里亲测有效,放心使用
    3. <div id="app">
    4. // 我们只需要再这里添加loading图或者骨架屏,有人会说怎么控制它的显示隐藏啊,
    5. //不用担心,再项目初始化完成后会自动替换为你的页面。
    6. <div class="self-loading">
    7. 页面正快马加鞭赶来,请耐心等待
    8. div>
    9. div>
    10. body>

  • 相关阅读:
    神经网络(MLP多层感知器)
    一个由Dubbo Thread pool is EXHAUSTED引发的问题排查
    Java开发面试--RabbitMQ专区
    小目标检测文章阅读
    SARScape导入(import sentinel-1)sentinel-1数据的时候报错file inconsistency
    github使用手册
    JDK各版本新增功能
    vue-project-01
    界面组件DevExpress WPF Data Grid哪些功能还能增强?一起来看
    DVWA-JavaScript Attacks
  • 原文地址:https://blog.csdn.net/muzidigbig/article/details/136631881