Vue项目性能优化之路由懒加载
为什么路由要懒加载?
Vue Router官网有说明:
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
是的,一个项目如果比较大的话,打包之后的app.xxxx.js也会比较大,这样可能会造成首屏渲染比较慢,有的甚至会白屏好几秒。如果我们能够将组件分割出来,只有当路由被访问的时候,才去加载对应的组件,这样可以适当减轻渲染负担,达到性能优化的目的
如何实现?
结合 Vue 的异步组件和 Webpack 的代码分割功能,实现路由组件的懒加载。
Vue 异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如把 webpack 2 和 ES2015 语法加在一起,我们可以写成这样:
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
Webpack 代码分割
在 Webpack 2 中,我们可以使用动态 import语法来定义代码分块点 (split point):
import('./Foo.vue') // 返回 Promise
结合这两者,这就是如何定义一个能够被 Webpack 自动代码分割的异步组件:
const Foo = () => import('./Foo.vue')
在路由配置中,只需要像往常一样使用 Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
遇到的问题
由于我的项目使用的是动态路由,在 import 的路径中需要加入变量,以下写法的结果是 i 会取最后一次的值+1(因为 () => import(@/views/${menus[i].name}
) 是个异步方法),所以menus[i].name就报错了:
let i, tmp = [], len = menus.length;
for (i = 0; i < len; i++) {
tmp.push({
path: menus[i].path,
component: () => import(`@/views/${menus[i].name}`),
...
})
}
很显然,将 i 定义在for循环作用域里就可以解决问题了:
for (let i = 0; i < len; i++) {
tmp.push({
path: menus[i].path,
component: () => import(`@/views/${menus[i].name}`),
...
})
}
然后,我重新打包项目,出现了很多个js,说明代码已经分割成功了,接着启动项目,在浏览器的开发者模式下点击Network可以看到页面加载完成所需的时间是Load:1.34s:
分割之前Load为2.39s,现在足足快了约1s耶!Amazing~