启动:
$ npm start
项目文件说明见 ProjectTree.md
。
通过npm-run-all
包启动所有应用,主应用 main-app 采用动态路由嵌入两个子应用:micro-app
和sub-app
。
micro-app
中再次采用动态路由实现子应用内部页面的路由跳转:/one
/two
。
通过window.__POWERED_BY_QIANKUN__
增加路由判断,给子应用匹配统一的路由器前缀/sub
。
这么做是为了保证子应用单独调试时路由匹配正确。
事实上,我们提倡微应用单独开发。
- 主应用路由配置:参考qiankun官网说明
- 微应用路由配置:有必要说明的是,微应用可以通过路由守卫来配置成动态的路径,以便微应用可以单独开发。
// main.js
// 增加路由判断
if (window.__POWERED_BY_QIANKUN__) {
router.beforeEach((to, from, next) => {
// to and from are both route objects. must call `next`.
if (!to.path.includes("/sub")) {
next({ path: `/sub/${name}${to.path}` });
} else {
next();
}
});
}
// ./router/index.js
let prefix = window.__POWERED_BY_QIANKUN__ ? `/sub/${name}/` : "/";
const routes = [
{
path: prefix,
name: "Home",
component: Home,
children: [
{
path: `${prefix}one`,
component: One
}
]
},
{
path: `${prefix}about`,
name: "about",
component: About
}
];
全局的微应用生命周期钩子需要挂载在主应用上,作为registerMicroApps
方法的第二个参数接收。在路由切换时,会销毁当前微应用。
特殊情况下可能想做状态保持,并不想在切换路由时销毁当前微应用。 可参考(qiankun keepalive)
type Lifecycle = (app: RegistrableApp) => Promise<any>;
name | -- | description |
---|---|---|
beforeLoad | Array | 可选 |
beforeMount | Array | 可选 |
afterMount | Array | 可选 |
beforeUnmount | Array | 可选 |
afterUnmount | Array | 可选 |
想要解决的问题:
在主应用(main-app)中:
- 通过
qiankun
提供的initGlobalState
初始化state。 onGlobalStateChange
监听变化
// 主应用状态初始化
// 通讯
const actions = initGlobalState({ // 👈
mt: "init", // 初始化state
msg: "",
sendMsg: ""
});
// 在项目中任何需要监听的地方进行监听
actions.onGlobalStateChange((state, prev) => { // 👈
console.log("main state change", state);
});
// 将action对象绑到Vue原型上,为了项目中其他地方使用方便
Vue.prototype.$actions = actions;
子应用(micro-app)中:
- 接收到主应用的方法并挂载。
export async function mount(props) {
// 设置通讯
Vue.prototype.$onGlobalStateChange = props.onGlobalStateChange; // 👈
Vue.prototype.$setGlobalState = props.setGlobalState; // 👈
render(props);
}
- 变化时更新该数据:
sendMessageToFather(v) {
this.sendMsg = v;
this.$setGlobalState({ sendMsg: v });
}
主应用接收该变化并更新进store管理:
actions.onGlobalStateChange((state, prev) => {
console.log("main state change", state);
_store.commit("updateMsg", state);
_store.commit("updateSendMsg", state);
});
思路同主子应用通信类似:
- 主应用存放组件状态
- 子应用通过
setGlobalState
改变状态 - 需要用到该状态的地方用
onGlobalStateChange
监听
官方提供了loadMicroApp
用来手动触发微应用加载。
handleLoadSubApp() {
this.microApp = loadMicroApp({
name: "sub-app-inpage",
entry: "//localhost:4012",
container: "#content",
props: {},
});
},
handleUnmountSubApp() {
console.log("this.microApp's lifeCycle", this.microApp);
this.microApp.unmount();
},
shadow DOM MDN shadow DOM
两种情况:
- 主应用和微应用部署到同一个服务器(同一个 IP 和端口)
在根目录执行
npm run build
,然后找到主应用main-app
下的dist文件即打包好的文件。
express.js 利用 express-generator 本地模拟node,并测试效果:
根目录下进入 express-app 文件夹
执行 npm start 启动
浏览器打开 localhost:8888 端口
- 主应用和微应用部署在不同的服务器,使用 Nginx 代理访问
- 微应用切换回主应用路由后,主应用页面不加载不显示。
参考文献:
感谢大佬们的无私分享🙏