前言
说起路由懒加载,大家很快就知道怎么实现它,但是问到路由懒加载的原理,怕有一部分小伙伴是一头雾水了吧。下面带大家一起去理解路由懒加载的原理。
路由懒加载也可以叫做路由组件懒加载,最常用的是通过 import() 来实现它。
function load(component) {
return () => import(views/${component}
)
}
然后通过Webpack编译打包后,会把每个路由组件的代码分割成一一个js文件,初始化时不会加载这些js文件,只当激活路由组件才会去加载对应的js文件。
在这里先不管Webpack是怎么按路由组件分割代码,只管在Webpack编译后,怎么实现按需加载对应的路由组件js文件。
一、准备工作
1、搭建项目
想要理解路由懒加载的原理,建议从最简单的项目开始,用Vue Cli3搭建一个项目,其中只包含一个路由组件。在main.js只引入vue-router,其它统统不要。
main.js
import Vue from ‘vue’;
import App from ‘./App.vue’;
import Router from ‘vue-router’;
Vue.use(Router);
//路由懒加载
function load(component) {
return () => import(views/${component}
)
}
// 路由配置
const router = new Router({
mode: ‘history’,
base: process.env.BASE_URL,
routes: [
{
path: ‘/’,
name: ‘home’,
component: load(‘Home’),
meta: {
title: ‘首页’
}
},
]
});
new Vue({
router,
render: h => h(App)
}).$mount(’#app’)
views/Home.vue
利用 webpackChunkName ,使编译打包后的js文件名字能和路由组件一一对应,修改一下load函数。
function load(component) {
return () => import(/* webpackChunkName: “[request]” */ views/${component}
)
}
3、去掉代码压缩混淆
去掉代码压缩混淆,便于我们阅读编译打包后的代码。在vue.config.js中配置
module.exports={
chainWebpack:config => {
config.optimization.minimize(false);
},
}
4、npm run build
执行命令 npm run build ,编译打包后的dist文件结构如下所示
其中Home.67f3cd34.js就是路由组件Home.vue编译打包后对应的js文件。
二、分析index.html
从上面我们可以看到,先用link定义Home.js、app.js、chunk-vendors.js这些资源和web客户端的关系。
ref=preload
rel=prefetch
as=script
然后在body里面加载了chunk-vendors.js、app.js这两个js资源。可以看出web客户端初始化时候就加载了这个两个js资源。
三、分析chunk-vendors.js
chunk-vendors.js可以称为项目公共模块集合,代码精简后如下所示,
(window[“webpackJsonp”] = window[“webpackJsonp”] || []).push([[“chunk-vendors”],{
“01f9”:(function(module,exports,webpack_require){
…//省略
})
…//省略
}])
从代码中可以看出,执行chunk-vendors.js,仅仅把下面这个数组 push 到 window[“webpackJsonp”] 中,而数组第二项是个对象,对象的每个value值是一个函数表达式,不会执行。就这样结束了,当然不是,我们带着 window[“webpackJsonp”] 去app.js中找找。
四、分析app.js
app.js可以称为项目的入口文件。
app.js里面是一个自执行函数,通过搜索 window[“webpackJsonp”] 可以找到如下相关代码。
(function(modules){
//省略…
var jsonpArray = window[“webpackJsonp”] = window[“webpackJsonp”] || [];
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
jsonpArray.push = webpackJsonpCallback;
jsonpArray = jsonpArray.slice();
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;
//省略…
}({
0:(function(module, exports, webpack_require) {
module.exports = webpack_require(“56d7”);
})
//省略…
}))
先把 window[“webpackJsonp”] 赋值给 jsonpArray 。
把 jsonpArray 的 push 方法赋值给 oldJsonpFunction 。
用 webpackJsonpCallback 函数拦截 jsopArray 的 push 方法,也就是说调用 window[“webpackJsonp”] 的 push 方法都会执行 webpackJ