这个方式其实是我在上家公司的时候体验过,觉得确实很有意思。
所以这里来逆推一下实现方式。
解决了什么痛点
1.开发一个模块,需要启动2-3个项目
在微前端的开发过程中,如果我们要在主应用中看效果,我们至少需要启动一个主应用,和一个待开发模块,如果项目具有登陆机制,我们还需要启动一个登陆模块。
换句话说,为了开发一个模块,我们需要至少启动三个项目。
2.数据耦合的情况下,无法单独启动项目调试
3.特定环境下出现的bug
可能某些bug依赖特定的数据,在测试环境出现了但在本地运行或开发环境运行正常。
如何解决
在成功发布一个版本以后,配置需要在特定条件下
触发加载的本地模块
,从而将线上服务的某些模块,代理到本地启动的模块,进行开发调试。
如何实现
前面几篇讲到,注册的配置信息其实是可以从远端拉取的,那么只需要有一个配置的地方,我们就可以动态修改这个配置列表。
换句话说,我们可以通过一些代码,配合需要配置列表,进行代理。
1.预设特定条件
比如我们预设一个特定条件:
环境为development或beta环境
且
成功读取远程配置列表
且
浏览器localStorage中存在名为developer的值
2.使用可热更新读取的配置表,例如nacos提供
举个例子:
构造一个对象,key表示开发者名字,value为需要代理到本地的数组,item的name为代理模块名称,entry表示入口地址,填写本地的运行地址就行。
1 2 3 4 5 6 7
| { xingwu:[{ name:'sub-login', entry:'//localhost:3002' }] }
|
3.修改主应用代码
3.1 main.js
改造前
1 2 3 4 5 6 7 8 9 10 11 12
| import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; import store from './store';
import register from './micro/index';
import '@/micro/store';
createApp(App).use(store).use(router).mount('#app');
register();
|
改造后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; import api from './api';
import register from './micro/index';
import '@/micro/store';
createApp(App).use(store).use(router).mount('#app');
const isDevelopment = () => process.env.VUE_APP_ENV_CONFIG === 'development' || process.env.VUE_APP_ENV_CONFIG === 'beta'; if (isDevelopment) { api.getDeveloper().then((response) => { window.subApps = response; }).finally(() => { register(); }); } else { register(); }
|
改造需要的注意点就是注册时机
1.判断环境是否是development环境或beta环境。
这个可以根据配置.env文件中的环境变量属性,在不同环境执行不同mode打包做到。
2.如果加载成功,把加载好的结果存起来。
3.如果加载失败,也得继续注册,不然页面直接挂了。
3.2 subapps
改造前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import router from '@/router/index';
const baseUrl = process.env.BASE_URL;
const subapps = [ { name: 'sub-login', entry: process.env.VUE_APP_SUB_LOGIN, container: '#sub-apps', activeRule: `${baseUrl}sub-login`, props: { routeBasePath: '/sub-login', mainRouter: router, }, }, { name: 'sub-user-manage', entry: process.env.VUE_APP_SUB_USER_MANAGE, container: '#sub-apps', activeRule: `${baseUrl}sub-user-manage`, props: { routeBasePath: '/sub-user-manage', mainRouter: router, }, }, ];
export default subapps;
|
改造后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import router from '@/router/index';
const baseUrl = process.env.BASE_URL;
const subapps = [ { name: 'sub-login', entry: process.env.VUE_APP_SUB_LOGIN, container: '#sub-apps', activeRule: `${baseUrl}sub-login`, props: { routeBasePath: '/sub-login', mainRouter: router, }, }, { name: 'sub-user-manage', entry: process.env.VUE_APP_SUB_USER_MANAGE, container: '#sub-apps', activeRule: `${baseUrl}sub-user-manage`, props: { routeBasePath: '/sub-user-manage', mainRouter: router, }, }, ];
const developer = localStorage.getItem('developer'); if (window.subApps && developer) { const tmpArray = window.subApps[developer]; if (tmpArray) { tmpArray.forEach((item) => { subapps.forEach((app) => { if (app.name === item.name) { app.entry = item.entry; } }); }); } } export default subapps;
|
比如上面,我在远端定义了一个开发者xingwu
我只需要再在浏览器的localStorage手动添加一个developer:xingwu
就可以触发匹配,将我指定的模块,加载本地启动的模块,代理到本地。
而其他所有用户所有模块,均不受影响。
就这样,完美解决了上面提出的痛点。
最后给大家看一下效果。