在此之前,我们先谈谈前端项目的性能优化。
优化前端项目无非就是2方面的优化:
一、网络性能优化(重点)
- 减少请求数量(webpack的天职就是打包)
- 减少请求资源大小(压缩gzip,后端会完成)
- CDN加速、负载均衡(运维负责)
二、运行性能优化
- 减少DOM操作
- 减少图片数量
显而易见的,我们前端除了一些游戏、WEBGL项目、有大量DOM操作项目之外,运行性能都不至于太差,所以我们接下来谈论的是webpack对网络性能的优化:
主要从“请求数量”和“请求资源大小”入手,我们知道如果没有脚手架,一般我们自己配置webpack,会把所有内容打包到一个js文件上,这个时候请求数量的确变少了,但是与此同时请求资源的大小也变大了,这就需要我们来衡量了,什么时候需要将某些chunk模块移出去呢?
当我们用到vue-cli的时候我们发现,打包完的文件中,js被分成了三个文件(原理就是我们之前提到过的CommonsChunkPlugin),其中有两个文件是比较大的,一个是app.xxx.js(存放我们写的代码)另一个是vendor.xxx.js(存放从node_modules引入的第三方库)
所以现在问题就转移到变成如何优化app和vendor了(我们讨论的是vue-cli里面webpack打包的优化):
app.xxx.js:
这里的优化就是所谓的“懒加载(按需加载)”了
1. 用 const test = () => import('@/components/test') 代替 import test from '@/components/test'
注意:这个语法糖是需要先安装 babel-plugin-syntax-dynamic-import,
然后配置babel plugins: ["syntax-dynamic-import"] 后才能使用的
分组:在import方法前面加入一个特殊的注释 /*webpackChunkName: "haha233"*/ ,就可以实现分组了
const nav = () => import(/*webpackChunkName: "haha233"*/'../nav/nav')
const haha = () => import(/*webpackChunkName: "haha233"*/'../test/test')
2. 用 const test = resolve => require.ensure([],() => resolve(require('@/components/test'))) 代替 const test = require('@/components/test')
require.ensure(dependencies: String[], callback: function, chunkName: String)
这个是webpack官网提供的方法
分组:在ensure方法最后传相同的组名就可以实现分组了
const test = resolve => require.ensure([], () => resolve(require('@/components/test')),'haha233')
const nav = resolve => require.ensure([], () => resolve(require('@/components/nav')),'haha233')
所谓分组就是,build后发现多出来一个js文件(除了正常的app、vendor和manifest),里面会包含同组模块的内容(例如上面的例子就是 nav和test模块的内容)
上面两点都有特殊的语法,1.要先用箭头函数包裹import('~~~'),2.要用带resolve参数的箭头函数包裹require.ensure然后在第二个参数中用resolve来处理require(‘~~~’)
这两种特殊的语法都是把promise包裹一下,变成vueRouter能接受的形式,实行按路由模块分文件
vendor.xxx.js:
vendor是,vue-cli帮我们配置好的,打包第三方库的文件,当我们引入大量库的时候,这个vendor文件会变得异常巨大,我们就需要主要优化这个文件,减小其大小
我们当然可以用上面两种方法来加载第三方库了,例如JQ
var $ = null import(/* webpackChunkName: "JQ" */'jquery').then(res => {
$ = res
}, err => {
console.log(err)
})
但是对于第三方js库我们一般不这么做,因为上面的方法是异步加载,有些库往往是我们项目代码的依赖,必须先加载完成不能够使用异步加载,因此我们来介绍下其他提取的方法:
1.我们可以用之前提到过的CommonsChunkPlugin
2.当然我们也可以自己动手,很简单,把库手动引入index.html,文件放在项目目录下的static/js下面,完成~
这样提出来的库要注意配置一下.eslintrc.js , 例如提取了jquery出来,应该加入如下配置
globals: {
'$': false
}
不配置的话,eslint-loader编译会报错说 ’$‘ is not defined
说到这里我们又可能会有一个疑问了:我们该什么时候把模块分出来呢?这个问题就关系到了衡量请求数量和请求资源大小对性能影响的平衡点了
我们分开app和vendor来讨论吧
app: 我们自己写的模块来说,我们一般按照路由来分
所以其实上面提到的”懒加载“技巧多用在router.js里面,这样就可以实现到当路由切换到某个组别的时候才去加载这个组的js
vendor: 对于第三方库来说,一般就是考虑大小了,如果库比较笨重最好就提出来了