Vue 项目性能优化

一、代码优化

1、第三方插件按需引入

以 element-ui 为例,借助 babel-plugin-component

(1)首先,安装 babel-plugin-component

npm install babel-plugin-component -D

(2)然后,将 .babelrc 修改为:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

(3)在 main.js 中引入部分组件:

import Vue from 'vue';
import { Button, Select } from 'element-ui';

Vue.use(Button)
Vue.use(Select)

2、路由懒加载

Vue 是单页面应用,会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大。把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件

const Foo = () => import('./Foo.vue') 
const router = new VueRouter({
 routes: [
   { path: '/foo', component: Foo }
 ]
})

3、图片懒加载

滚动到可视区域后再去加载

vue-lazyload

4、v-for 遍历必须为 item 添加 key,且避免同时使用 v-if

推荐直接处理数据后再调用,比如 filters 筛选。

5、computed 和 watch 区分使用场景

当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;

当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

6、不需要更新的长列表使用 Object.freeze 进行冻结

7、监听事件销毁

created() {
 addEventListener('click', this.click, false)
}, 
beforeDestroy() {
 removeEventListener('click', this.click, false)
}

8、v-if 和 v-show 区分使用场景

v-show 总是会被渲染,只是基于 display 切换显示,适用于需要频繁切换条件的场景。

v-if 适用于很少改变条件,不需要频繁切换条件的场景。

9、keep-alive可以保留组件状态并且避免重新渲染

10、延迟加载(defer)

11、无限列表优化

vue-virtual-scroll-list 和 vue-virtual-scroller

12、服务端渲染SSR 或者 预渲染

如果你的项目的 SEO 和 首屏渲染是评价项目的关键指标,那么你的项目就需要服务端渲染来帮助你实现最佳的初始加载性能和 SEO。

如果你的 Vue 项目只需改善少数营销页面(例如  /, /about, /contact 等)的 SEO,那么你可能需要预渲染,在构建时 (build time) 简单地生成针对特定路由的静态 HTML 文件。prerender-spa-plugin。

二、webpack 优化

1、对图片进行压缩

可以在 webpack.base.conf.js 中 url-loader 中设置 limit 大小来对图片处理,对小于 limit 的图片转化为 base64 格式,其余的不做操作。

对有些较大的图片资源,在请求资源的时候,加载会很慢,我们可以用 image-webpack-loader来压缩图片。

{
 test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
 use:[
 {
   loader: 'url-loader',
   options: {
    limit: 10000,
    name: utils.assetsPath('img/[name].[hash:7].[ext]')
   }
 }, {
 loader: 'image-webpack-loader', options: { bypassOnDebug: true, }
 }
]
}

2、减少 ES6 转为 ES5 的冗余代码

安装 babel-plugin-transform-runtime,babel 版本是6的前提下

修改 .babelrc 配置文件为:

"plugins": [
    "transform-runtime"
]

报错 this.setDynamic is not a function

解决:当前安装的 babel 是7,所以需要设置为"@babel/transform-runtime"

3、将每个页面的第三方库和公共模块提取出来

 optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      automaticNameDelimiter: '~',
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
  • chunks: 可填 asyncinitialall. 顾名思义,async针对异步加载的chunk做切割,initial针对初始chunk,all针对所有chunk。

webpack4 在 vue.config.js 中的用法

configureWebpack: config => {
    config.assign(config, {optimization:{splitChunks:{}})
}

4、优化配置

loader配置

(1)优化正则匹配

(2)通过cacheDirectory选项开启缓存

(3)通过include、exclude来减少被处理的文件。

{ 
// 1、如果项目源码中只有js文件,就不要写成/\.jsx?$/,以提升正则表达式的性能
 test: /\.js$/, 
// 2、babel-loader支持缓存转换出的结果,通过cacheDirectory选项开启
 loader: 'babel-loader?cacheDirectory',
 // 3、只对项目根目录下的src 目录中的文件采用 babel-loader
 include: [resolve('src')]
},

resolve.modules配置

resolve: {
 // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
 modules: [path.resolve(__dirname,'node_modules')]
},

resolve.alias配置

alias: { '@': resolve('src'), },
 // 通过以上的配置,引用src底下的common.js文件,就可以直接这么写
import common from '@/common.js';

resolve.noParse 配置

noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理

想要忽略 jQuery 、ChartJS ,则优化配置如下:

// 使用正则表达式 
noParse: /jquery|chartjs/ 
// 使用函数,从 Webpack3.0.0开始支持 
noParse: (content)=> { 
    // 返回true或false 
    return /jquery|chartjs/.test(content); 
}

三、web优化

1、开启 gzip 压缩

开启后Response Headers显示,Content-Encoding:gzip

https://www.huangyuhong.cn/2020/12/compression-webpack-plugin-%e4%bd%bf%e7%94%a8%e4%b8%ad%e9%81%87%e5%88%b0%e7%9a%84%e9%97%ae%e9%a2%98/

2、使用CPN访问静态资源


参考:https://juejin.im/post/6844903913410314247

https://juejin.im/post/6844903745810104328