VUE项目-性能优化总结

164 阅读3分钟

1.打包配置层面

vue打包优化/webpack打包优化

1.1使用report分析包中较大的bundle

1.2打包分离 external

一些较大的依赖或插件,利用内网资源或cdn的缓存策略,优化加载时长

 external:{ 
     'element-ui':ELEMENT
      moment:'moment'
      echarts:'echarts'
      }

对于key、value的说明:

++key是包名

import Vue from 'vue',‘vue’就是包名

++value是script引入之后,在window对象上添加的属性

通过script引入vue,会在window对象上添加一个Vue的属性

**body--id='app'下面直接引入对应的script文件,在head中引入elementui样式文件

**需要注意的是,要注意分离打包的度。分离的目的主要是俩:

**a.利用浏览器的请求并发,同时请求几个分开的包,而不是一次请求两个超大的js包。

**b.利用浏览器的缓存机制,将一些不会更改的js包缓存下来,避免每次都去请求最新的包

**但是如果分离的粒度较小,会导致在首页加载资源的请求变多,会造成首页加载延迟

整体配置方面,可以看这篇文章 blog.csdn.net/xzwwjl1314/…

1.3drop_console

生产环境中去掉console信息,避免不必要的内存泄漏的情况

configureWebpack: (config) => {
    if (process.env.NODE_ENV === "production") {
      config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true;
      config.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = true;
    }
  },

1.4开启资源gzip

使用CompressionWebpackPlugin压缩文件形成压缩包,同时服务器要配置允许使用gzip资源,这样就可以做到让浏览器请求加载gzip资源,并在本地解析

const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg|eot|ttf|woff)(\?.*)?$/i;
configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
            const plugins = [];
            plugins.push(
                new CompressionWebpackPlugin({
                    filename: "[path].gz[query]",
                    algorithm: "gzip",
                    test: productionGzipExtensions,
                    threshold: 10240,
                    minRatio: 0.8
                })
            );
          }
      }
用到的属性:
    test:正则表达式,可以用来控制哪些后缀的文件需要打包
    filename:gzip文件的名称[path].gz[query]
    threshold:10240 大于10k
    algorithm:'gzip'压缩方式
    minRatio: 还是不知道啥意思

1.5配置资源缓存节省带宽

协商缓存  强缓存(也叫本地缓存,直接缓存到本地不与服务器通信)返回200from cache)
强缓存 优先于 协商缓存
强: expries--绝对时间    
 cache-control
 max-age:数值,单位秒
     no-cache 不使用本地缓存,使用协商缓存
     no-store 不使用缓存,直接从服务器请求最新资源
     public  被代理服务器与浏览器同时缓存
     private 仅被浏览器缓存
			 
协商:etag-->if-none-match 返回304(Not Modified)
    last-modified-->if-modified-since
        etag判断文件内容是否修改
        last-modified判断上次修改时间
        etag的优点:
          1.文件周期性改变,只是文件信息改变,但是内容不变
          2.文件改变的特别频繁,1s改n次,last-modified最小精确到秒
          3.某些服务器不能精准的得到文见最后修改的时间
        etag的优先级>last-modified

1.6使用按需加载模块

element-ui
按需加载第三方插件,elementUI(需要另外安装babel-plugins-component)
babel.config.js:
    plugins:[
        [
            'component',
            { 
                    'libraryName':'element-ui',
                    'styleLibraryName':'theme-chalk'
            }
        ]
      ]
 import {Button} from "element-ui";
 Vue.use(Button)

echarts
引入主模块
    let echarts =require('echarts/lib/echarts');
    引入折线柱状图等组件
    require('echarts/lib/chart/line')
    require('echarts/lib/chart/bar')
    引入提示框,title,图例
    ...
    Vue.prototype.$echarts=echarts

1.7 路由、组件动态加载

动态路由:
routes:[ 
    { 
        component:()=>import("@/views/normal")

    }
]
//提供一个封装路由懒加载的函数
routes.js:

function load(component) {
    return ()=>import(/* webpackChunkName: "[request]" */`@/views/${component}`)
}

const compA = 'comp/compA'

{
    path: '/case',
    name: 'case',
    component:load(compA) 
}
//这里不仅是路由懒加载,还用到webpack魔法注释,能够将当前组件单独打包到js中,分离打包

动态组件:
<transition name='fade'>
   //动态赋值componentId控制内部加载的组件,结合componentShow控制组件的展示与否,这样就避免在页面一开      始就加载了所有的组件
    <component v-if='componentShow' :is="componentId" />			
</transition>

//js逻辑通过逻辑判断,动态的赋给componentId,避免在一开始加载所有可能的组件然后再一一逻辑判断
 componentId= () => import(`@/components/AreaLaw/Other/index`);

1.8生产环境移除preload与prefetch

去除首页预加载其他页面的css与js,优化首页加载速度 config.plugins.delete('preload')

config.plugins.delete('prefetch')

preload提升资源加载优先级,通过 只是预加载了资源,但是资源加载完成后并不会执行,所以需要在想要执行的地方通过

但是也有一个例外,因为 CSS 的加载也是通过 标签引入的,所以可以在加载之后,onload事件中,修改rel属性

当 onload 事件触发的时候修改 rel 属性的值,使得它由原来的预加载样式变成引入样式

如果通过 preload 加载了资源,但是又没有使用它,则浏览器会报一个警告

preload与prefetch在加载时候的区别 preload会使资源优先加载,比如:此时,b.js会被优先加载

prefetch则是在浏览器都加载完了相关的js css,也解析完毕了html文件,页面load结束之后,才加载prefetch的相关文件。

preload会下载并解析文件。但prefetch只会下载文件不会解析。 preload是当前页面必须用到的文件。但prefetch大部分不是当前页面需要的,仅仅是之后的页面需要用的资源

但是: 这里有问题

***如果prefetch的文件特别多的话,会阻碍接口的调用的,比如prefetch 10多个文件之后,在调用了页面的接口,这样就会使得页面加载的更慢了。

vue默认是打开preload与prefetch的,所以要关闭这俩,让首页展示的更快些

***再就是如果网速比较慢,但现在确提前prefetch了很多文件,会使页面加载的更缓慢

1.9打包时候分离代码,提取公共代码

splitChunk --结合缓存 blog.csdn.net/ZYS10000/ar…

vue项目直接运行build-report即可

代码分离a:目的:利用浏览器并发加载,减少某个模块的大小,达到减少加载时间的目的
1.9.1 分离方法1:动态加载 import()。动态路由、动态组件。

其中动态路由的rouer可以使用webpack魔法注释
function load(component){ 
    return ()=>import(/* webpackChunkName: "[request]" */                  /* webpackPrefetch: true */`@/views/${component}`
    )
}
//webpackChunkName: "[request]是解析之后js文件名称  
//webpackPrefetch: true */ 设置组件预加载。在浏览器空闲的时候加载路由,不会阻碍页面load。
//不过动态路由本身就应该用到的时候去加载,所以可以不去配置。

1.9.2分离方法2:通过splitChunks

 1.9.2.1 chunks:三个参数

all(动态引入静态进入都会分离打包,并只会生成一个相关bundle文件) 

async(只打包动态加载的模块) 

initial(只打包静态引入的资,并且生成了多个bundle文件)


1.9.2.2 cacheGroups:
单独分离某个模块
    vendors: {
    name: `app-chunk-vendors`,
    test: /[\\/]node_modules[\\/]/,
    priority: -10,//优先级
    chunks: 'all'
    },
    echarts: {
        chunks: 'all',
        name: `echarts`,
        test: /echarts|zrender/,
        priority: 10,
    }
echarts的priority需要大于vendors的,否则不能分离出来

//完整的一个配置:
chainWebpack: (config) => {
      if (process.env.NODE_ENV === "production") { 
            config.optimization.minimize(true);
      }
    config.plugins.delete("prefetch");
    config.plugins.delete("preload");
    config.optimization.splitChunks({
      chunks: "initial",
      cacheGroups: {
            vendors: {
              name: `app-chunk-vendors`,
              test: /[\\/]node_modules[\\/]/,
              priority: -10,
              chunks: 'all'
            },
            echarts: {
              chunks: 'all',
              name: `echarts`,
              test: /echarts|zrender/,
              priority: 10,
            },
            // default: {
            //   //如果有一个文件被用了两次,会被打包成一个单独的文件
            //   minChunks: 2,
            //   filename: "common_[id].js",
            //   //优先级 一般是负数
            //   priority: -10,
            // },
      }
      // cacheGroups: {
      //   vendors: false,
      //   common: false
      //  }

    });    

},

**关于prefetch的配置

    // vue.config.js
    module.exports = {
      chainWebpack: config => {
            // 移除 prefetch 插件
            config.plugins.delete('prefetch')

            // 或者
            // 修改它的选项:
            config.plugin('prefetch').tap(options => {
              options[0].fileBlacklist = options[0].fileBlacklist || []
              options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
              return options
            })
      }
    }

2.代码层面

2.1 接口请求层面

合并请求,防止页面请求过多的请求

2.2 使用虚拟列表优化无限滚动的长列表

2.3 使用文档碎片document.createDocumentFragment()

2.4 for循环一定要加上key值,减少diff算法时间

2.5 关于回流重绘

    减少回流重回的次数 通过style.cssTest+=统一修改
    切换类名统一修改样式

浏览器会将多次的回流放在一个队列中,但是如果获取dom元素的布局信息,就会强制清空队列进行回流。所以可以缓存dom布局信息

2.6 防止浏览器内存泄漏

2.6.1 给滚动事件、输入seggest事件等频繁触发的事件添加节流、防抖
2.6.2 生产环境一定要去掉console.log,打印信息过大也会造成内存泄漏
2.6.3 第三方插件使用完成后,一定要销毁实例(echarts--despose),避免游离的dom节点
2.6.4 event-bus监听函数,在destoryed生命周期要关闭(emitemit---on---$off)
2.6.5 localstorage中不要存放过大的数据量,优化性能
2.6.6 在页面destory的时候,也要移除window上的全局事件
2.6.7 读取了dom元素的信息存入到了变量中,在使用完成后,要将变量置为null,避免游离的dom节点

2.7 图片懒加载、列表的无限滚动

都会用到交叉管理器 intersectionObserver 列表的无限滚动要注意padding-top padding-bottom进行元素占位,否则滚动的时候会出现抖动问题 vue框架对性能优化所做的配置操作

vue-config.jpg