- 美团 https://tech.meituan.com/2019/12/26/meituan-bifrost.html
- 阿里 https://qiankun.umijs.org/zh/
前言: 虽然不想搞轮子 ,但是 要吹牛,不搞点轮子 也不好意思得
demo 项目 https://gitee.com/qlaiqyc_572/mins-web
目前两种方案 ,
第一种:使用 system.js 对 子项目进行 加载umd 对象 然后addRouter
第二种:公用全局变量 进行注册 保存,(通过xhr 请求JS)
Vue-Route https://router.vuejs.org/zh/api/#router-addroutes
注意 坑 ,刷新的情况
1. 使用 system.js 进行模块加载
let { default: webApp } = await System.import(url)
2. 使用 router.addRouter 进行路由加载
router.addRouter(webApp.router)
3. 问题:怎么处理 loading 状态,怎么更新路由设置
解决方法: 和我们经常遇见的 路由权限一样 只需要 重置 路由 进行添加
// 重置路由
const createRouter = ()=>{
return new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
}
const router = createRouter();
router.Qclear =()=>{
router.matcher =createRouter().matcher;
};
//路由监听 子项目处理的清空,subPro 是子项目 加载前的loading 模块 ,类似与打开小程序下载资源前的的 loading 状态
async routeEvent(router,subPro){
let {subWebs} = this.data,$t = this;
//更新路由
const updateRoute = async (subWebs)=>{
router.Qclear();//清空路由
let newRoute = [];
subWebs.forEach(curr=>{
if(curr.load) {
newRoute = newRoute.concat(curr.webApp.routes)
}else{
newRoute.push({ path: "/"+curr.path, name: curr.path, component:subPro})
}
});
router.addRoutes(newRoute,{replace:true});
}
//处理初始化路由
await updateRoute(subWebs);
//监听路由变化 判断 是否进行加载
router.beforeEach((to, from, next) => {
let {subWebs} = $t.data,index = -1;
subWebs.forEach((curr,cindex)=>{
if(curr.path == to.name)index = cindex;
});
next()
if(index == -1){return}
(async ()=>{
let curr = subWebs[index];
//判断是否加载
if(!curr.load){
//延时 看loading 效果
await new Promise(resolve => {
setTimeout(()=>{
resolve();
},3000)
})
//加载 -- 这里 就有思考了,(服务端渲染的加载情况 ,是否引入第三方加载工具,System.js 还是自己写)
// - 服务端渲染的情况 是否是在服务端进行加载 /还是在客户端进行loading 加载
// - 暂做 在客户端进行加载的情况 ,服务端 有空再搞
let { System } = window;
// eslint-disable-next-line no-unused-vars
let { default: webApp } = await System.import(curr.form);
curr.load = true;
curr.webApp = webApp;
subWebs[index] = curr;
$t.data.subWebs = subWebs;
await updateRoute(subWebs);
}
next(to.path);//当前的导航被中断,然后进行一个新的导航
})()
})
},
基本第一步 就完了 看看:展示状态
缓存路由:是使用 Qcenter 种的全局变量进行 保存
//配置 处理
data: {
//保存主路由的基本信息
main: {},
//子项目配置
subWebs:[
//load:===是否加载 webApp 异步路由保存在缓存里面
{path:'web',desc:"子项目-01",form:'/web/main.js',port:"8081",load:false,webApp:{}}
]
},
待优化:
小结总结:基本功能虽然实现了,但是仍旧需要 多考虑 多想想, 项目的配置 怎么才能更简单,怎么才能更高效
代码世界:有句话,很好,约定大于配置 -----简单而言 就是 遵循 某些规范 尽量少BUG
原则上: 各个模块大部分数据都是独立的 ,很少是需要公用的(常见的 token, 登陆用户信息,配置信息)
Vuex 的 store.registerModule 注册子模块的所有model
所有子项目 的模块,都注册到主项目上面 ,进行统一处理 命名规则 为 子项目名称
主项目 获取子项目 种的值 (有未加载的情况 需要进行判断)
子项目获取 主项目的 值
1. 问题:由于子项目的store 注册到 主项目,在子项目 种获取值 就有区别,原因是公用了 store
解: 约定 ,在子项目 devClient 开发时 主动创建根目录 ,取值的时候 都在 创建的目录下,打包时 和 dev 时 去掉 根目录,然后 进行取值(没办法 ,暂时想不到其他方法了)
注: 子项目 store 的取值问题需要约定
- 基本约定 (那些变量 不能 使用 设置关键字 关键词 列入 windows 中绑定 相同变量)
- 咋处理呢,qiankun 的做法是 用哪个加载哪个,不用了就卸载掉,这样就完成了隔离
由于项目的都是基于 Vue 的所以使用 EventBus 就可以了,全局公用一个BUS,都是走公共方法里面提取的哈(前提是)
1. 创建文件 bus.js
import Vue from 'vue';
export default new Vue();
2. 引用js 绑定事件 触发事件
import Bus from '~/commons/bus.js';
//绑定事件
Bus.$on('showTips', target => {
...
console.log(target);
...
});
//触发事件
Bus.$emit('showTips', data);
之前就很多地方都说了 不同环境,再在这里统一说一下
子项目
package.json
"scripts": {
"dev": "vue-cli-service serve --mode development",// 本地协同 开发环境
"devClient": "vue-cli-service serve --mode devClient",// 本地 单独开发环境
"build": "vue-cli-service build --mode production"
"lib": "vue-cli-service build --target lib --name index src/main.js" //正式打包
},