vue项目上线前必做的优化(提升七倍!)

1,964 阅读7分钟

前言

本文项目地址,走过路过赏个star呗
项目的优化是一个老生常谈的问题,在面试中也会经常被问到,它关系到用户的体验效果,试问用户加载一个页面太久,又有谁会愿意使用项目呢?那么如何对项目进行优化呢?仔细观看本文一定会有收获的。(有需求的大佬可以选择目录进行挑选观看~)

  • 一:build打包时移除所有的console
  • 二:通过Nprogress添加页面顶部加载进度条效果(小细节)
  • 三:通过chainWebpack自定义打包入口
  • 四:通过externals加载外部CDN资源(重要
  • 五:路由的懒加载
  • 六:Gzip压缩

一:build打包时移除所有的console

在我们执行build命令进行项目打包时,项目中可能会报如下警告:

这是因为eslint规范不允许我们在项目中输出console代码,但是我们需要在项目的生产阶段输出console来检测代码的正确性,发布阶段不需要console,我们便需要安装依赖 babel-plugin-transform-remove-console和进行配置:

npm install babel-plugin-transform-remove-console --save-dev  //安装依赖

在项目的babel.cofig.js进行配置:

// 这是项目发布阶段需要用到的babel 插件
const prodPlugins = [] //定义一个数组来将发布阶段需要的babel插件push进去
if (process.env.NODE_ENV === 'production') {
  prodPlugins.push('transform-remove-console')
}

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ],
    // 发布产品时候的插件数组
    ...prodPlugins
  ]
}

这里我们判断项目是否在发布阶段来选择把清除console的babel插件push到数组中并使用就行了。

二:通过Nprogress添加页面顶部加载进度条效果(小细节)

在我们进入页面后,每次访问对应的路由组件我们都希望更好的用户体验,所以我们可以通过安装 nprogress依赖实现用户每次访问路由时在页面的顶部都加载一个进度条效果来达到用户更好的视觉感受。

 npm install --save nprogress  //安装依赖

main.js引入

// 导入 Nprogress和对应的css
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
// 在request 拦截器中 展示进度条 Nprogress.start()
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'// 配置请求的根路径
axios.interceptors.request.use(config => {

  Nprogress.start()  //启动进度条
  config.headers.Authorization = window.sessionStorage.getItem('token')
  return config
})
// 在response 拦截器中 隐藏进度条 Nprogress.done()
axios.interceptors.response.use(config => {
  Nprogress.done()  //结束进度条
  return config
})

这里需要注意的是因为我们每次访问不同的路由都会发起一个axios请求,我们只需要在用户发起请求后的axios的请求拦截器中来启动Nprogress,在axios响应拦截器中结束Nprogress便可达到效果。

箭头指示的蓝色加载条便是效果

三:通过chainWebpack自定义打包入口

在默认情况下,vue项目的开发阶段和发布阶段都是共同使用一个打包入口文件src/main.js,但是往往我们需要将开发过程发布过程进行分离,来指定不同阶段的入口文件以便后续项目的优化,所以我们便需要在src目录下建立两个入口js文件(名字自取),我这里是取得语义化的名字main-dev.jsmain-prod.js并在项目的根目录下创建一个vue.config.js放以下代码来更改默认的入口文件

module.exports = {
  chainWebpack: config => {
    // 模式为 production 时选择 main-prod.js作为入口文件
    config.when(process.env.NODE_ENV === 'production', config => {
      config.entry('app').clear().add('./src/main-prod.js')
    })
    // 模式为 development 时选择 main-dev.js作为入口文件
    config.when(process.env.NODE_ENV === 'development', config => {
      config.entry('app').clear().add('./src/main-dev.js')
    })
  }
}

四:通过externals加载外部CDN资源

在项目中我们难免会import引入一些样式表或者js文件(axios,vue,vue-router...)例如:

这些依赖包最终会打包合并到同一个文件中,从而导致打包成功后,单文件体积过大的问题(如下图)

图中的js/chunk-vendors.js文件便是import的文件打包后的单文件,可以看到后面有一个!表明打包后的文件过大,解决方法是通过externals引入CDN的方法来加载外部资源,这里我小小的说明一下externals的机制

当在vue.config.js文件中声明了externals节点时,webpack打包时不会将externals声明的依赖包来进行打包,而是会在全局去找对应的CDN资源来引入第三方包从而减少打包后打个文件体积过大的问题

//在vue.config.js 的发布阶段加上代码进行externals声明

    // 模式为 production 时选择 main-prod.js作为入口文件
    config.when(process.env.NODE_ENV === 'production', config => {
      config.entry('app').clear().add('./src/main-prod.js')

      // 通过externals加载外部CDN资源
      config.set('externals', {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios',
        lodash:'_',
        echarts: 'echarts',
        nprogress: 'NProgress',
        'vue-quill-editor': 'VueQuillEditor'
      })
    })

再在index.html里面引入CDN资源(友情提示:需要CDN资源可以去对应的官网找,并且要找稳定的CDN,要不然项目会影响

这时候呢我们执行打包命令可以惊奇地发现原来的chunk-vendors.js文件(1.8MB->106.6KB)的体积大大减少了(对比优化前总资源与现在总资源确实有七倍)

五:路由的懒加载

当打包项目时,JavaScript包体积会变得很大(如上图的159KB的app文件),当我们进入项目的首页时,所有的路由便已经加载完毕,我们希望只有当我们点击对应的组件时才会显示,这时我们可以选择路由懒加载的形式来通过路由被访问的时候才会加载组件,这时候就减少了用户第一次访问页面所需要加载的组件,提高性能。
安装依赖

npm install --save-dev @babel/plugin-syntax-dynamic-import

并在babel.config.js声明插件

// 这是项目发布阶段需要用到的babel 插件
const prodPlugins = []
if (process.env.NODE_ENV === 'production') {
  prodPlugins.push('transform-remove-console')
}

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk'
      }
    ],
    // 发布产品时候的插件数组
    ...prodPlugins,
    '@babel/plugin-syntax-dynamic-import'  //声明路由懒加载的插件
  ]
}

router的配置文件index.js中进行配置

// import Login from '@/components/Login.vue'
// import Home from '@/components/Home.vue'
// import Welcome from '@/components/Welcome.vue'

// 这样引入实现路由懒加载
const Login = () => import(/* webpackChunkName: "login_home_welcome" */ '@/components/Login.vue')
const Home = () => import(/* webpackChunkName: "login_home_welcome" */ '@/components/Home.vue')
const Welcome = () => import(/* webpackChunkName: "login_home_welcome" */ '@/components/Welcome.vue')


// import Users from '@/components/user/User.vue'
// import Rights from '@/components/power/Rights.vue'
// import Roles from '@/components/power/Roles.vue'

const Users = () => import(/* webpackChunkName: "Users_Rights_Roles" */ '@/components/user/User.vue')
const Rights = () => import(/* webpackChunkName: "Users_Rights_Roles" */ '@/components/power/Rights.vue')
const Roles = () => import(/* webpackChunkName: "Users_Rights_Roles" */ '@/components/power/Roles.vue')

// import Cate from '@/components/goods/Cate.vue'
// import Params from '@/components/goods/Params.vue'

const Cate = () => import(/* webpackChunkName: "Cate_Params" */ '@/components/goods/Cate.vue')
const Params = () => import(/* webpackChunkName: "Cate_Params" */ '@/components/goods/Params.vue')

// import GoodsList from '@/components/goods/List.vue'
// import Add from '@/components/goods/Add.vue'

const GoodsList = () => import(/* webpackChunkName: "GoodsList_Add" */ '@/components/goods/List.vue')
const Add = () => import(/* webpackChunkName: "GoodsList_Add" */ '@/components/goods/Add.vue')

// import Order from '@/components/order/Order.vue'
// import Report from '@/components/report/Report.vue'

const Order = () => import(/* webpackChunkName: "Order_Report" */ '@/components/order/Order.vue')
const Report = () => import(/* webpackChunkName: "Order_Report" */ '@/components/report/Report.vue')

上面的代码注释的地方是之前引入路由的方法,往下就是路由懒加载的方法,我这里是通过将几个路由组件起了同一个webpackChunkName名字来表示打包时会将这几个路由组件一起打包。 重新build之后的效果:

可以看到打包后分成了自己定义的很多webpackChunkName名字的js文件,说明我们成功了!

六:GZIP压缩

gzip是一种压缩技术,他可以将原来的内容压缩成之前的三分之一甚至更小,这样用户浏览页面的速度将会快很多,增加极好的用户体验。gzip压缩页面需要浏览器和服务器两者都支持,大多浏览器都支持这项技术(chrome、Firefox、Safari...),所以不用担心,主要是服务端怎么使用。 首先我们需要安装依赖:

npm i compression -S //安装compression

因为我这里服务端框架用的是express,所以我拿它做个示范:

const express = require('express')
const app = express()
const compression = require('compression') //导入
const https = require('https')
const fs = require('fs')

// 这一行代码要写在静态资源托管之前
app.use(compression())   //使用
app.use(express.static('./dist'))
...

话不多说,上图示范: before:

later

从上面两张图可以明显的看到chunk-vendors的体积从85.8KB变为现在的244B,加载时间也从143ms35ms速度提升了四倍,可见gzip技术确实是页面性能优化的一种有效方式。

总结

其实项目的优化有很多种,代码优化、webpack优化、技术优化等,本文只涉及到一些,还有一些比如:根据情况选择v-if或者v-show,样式全局使用、图片webp格式,懒加载,serviceWorker设置离线缓存...
本人大三菜鸡生一枚,文章可能存在一些不太合理的描述,希望各位巨佬能多多指教~