vue项目打包的时候,如果项目比较庞大,那么将会打出一个很大的包,速度比较慢,这个时候可以考虑拆分,不要把所有的内容都打到一个包里面去。但是在开发环境时使用lazy-loading会影响开发效率,小的项目还好,大的项目特别明显。(不在意效率得也无所谓了)
在浏览上古代码时发现比较大的项目会使用一种开发和生产环境切换的模式控制:
1573111299(1).jpg
1573111361(1).jpg
原理大体是分别配置两个环境的引入文件,利用env变量选择文件。
const _import = require('./_import_' + process.env.NODE_ENV)
这种懒加载代码具体原理在最👇。
当然如图所示这种方法已经被淘汰原因:@/views/下的 .vue 文件都会被打包。不管你是否被依赖。所以这样就产生了一个副作用,就是会多打包一些可能永远都用不到 js 代码。当然这只会增加 dist 文件的大小,但不会对线上代码产生任何的副作用。
现在都使用的是babel的plugins
官方描述:
使用babel 的 pluginsbabel-plugin-dynamic-import-node。它只做一件事就是将所有的import()转化为require(),这样就可以用这个插件将所有异步组件都用同步的方式引入,并结合 BABEL_ENV 这个bebel环境变量,让它只作用于开发环境下,在开发环境中将所有import()转化为require(),这种方案解决了之前重复打包的问题,同时对代码的侵入性也很小,你平时写路由的时候只需要按照官方文档路由懒加载的方式就可以了,其它的都交给bable来处理,当你不想用这个方案的时候,也只要将它从babel 的 plugins中移除就可以了。
具体代码:
首先在package.json中增加BABEL_ENV
"dev": "cross-env BABEL_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"
接着在.babelrc只能加入babel-plugin-dynamic-import-node这个plugins,并让它只有在development模式中才生效。
{
"env": {
"development": {
"plugins": ["dynamic-import-node"]
}
}
}
之后就大功告成了,路由只要像平时一样写就可以了。
{ path: '/login', component: () => import('@/views/login/index')}
下面是我翻阅众多资料讲的较为透彻的一篇对于懒加载的原理解析
路由懒加载:
我们平常使用router可能如下:
import Vue from 'vue'
import Router from 'vue-router'
//***
import ddd from '@/components/ddd'
Vue.use(Router);
export default new Router({
routes: [
//***
{
path: '/ddd',
name: 'ddd',
component: ddd,
meta: {
title: 'ddd'
}
}
]
})
先用import引入,然后在component里面配,这种其实是同步模式,也就是说你这样写,ddd.vue组件里的代码会被打入总包里面。
还有一种和上面类似的同步写法,使用require去写的:
import Vue from 'vue'
import Router from 'vue-router'
//***
Vue.use(Router);
export default new Router({
routes: [
//***
{
path: '/ddd',
name: 'ddd',
component: require('@/components/ddd').default,
meta: {
title: 'ddd'
}
}
]
})
如果要从总包里分出去,就要用到异步加载组件,改造起来也很简单:
import Vue from 'vue'
import Router from 'vue-router'
//***
Vue.use(Router);
export default new Router({
routes: [
//***
{
path: '/ddd',
name: 'ddd',
component: ()=>import('@/components/ddd'),
meta: {
title: 'ddd'
}
}
]
})
改造之后,我们打包的时候就会发现多出来一些js:
vue_router_component_async_2.png
这表示异步路由的内容被单独打包出来了,只在跳转在当前路由的时候加载。
还有一种异步请求的写法:
import Vue from 'vue'
import Router from 'vue-router'
//***
Vue.use(Router);
export default new Router({
routes: [
//***
{
path: '/ddd',
name: 'ddd',
component: (resolve)=>require(['@/components/ddd'],resolve),
meta: {
title: 'ddd'
}
}
]
})
注意()=>import ('./bbb.vue')和(resolve)=>require(['./bbb.vue'],resolve)这两种写法,两者实现异步的机制不一样,内部处理逻辑也不同。
//import()返回promise,利用promise的then执行异步
const fn=()=>import('./ddd.vue');
fn.then(function(item){
console.log(item)
});
//返回不是promise,利用普通的回调执行异步
const fn=(resolve)=>require (['./ddd.vue'],resolve);
fn(function(item){
console.log(item);
});