# 前言
前面的章节针对微前端的框架做了简单的介绍,已经可以满足我们初学者的开发了,但是应用之间的通信还是存在问题的,假设我是一个 a 应用,基于 a 应用的某种动作或者某种状态,需要对象 b 应用进行更新,这个时候就需要我们想一个比较合理的方案来解决该问题来
一个好的体系结构是将微前端解耦,并且不需要频繁通信。基于路由的single-spa应用程序本质上需要较少的应用程序间通信。
微前端直接通信的可能有三样东西:
- 方法,组件,逻辑,全局状态
- API数据
- UI状态
# 通信状态
# 方法,组件,逻辑,全局状态
这里,single-spa 官方有提供一个案例,大家可以参考一下:
你可以在不同git仓库或JS包的微前端之间导入或导出方法,组件,逻辑,全局状态:
// @org-name/auth
export function userHasAccess(permission) {
return loggedInUser.permissions.some(p => p === permission);
}
import { userHasAccess } from '@org-name/auth'
// 在 single-spa应用程序中,从不同的微前端导入并使用util函数
const showLinkToInvoiceFeature = userHasAccess('invoicing');
# API数据
这里,single-spa 官方有提供一个案例,大家可以参考一下:
API数据通常不需要在 microfrontend 之间共享,因为每个 single-spa 应用程序控制不同的路由,而不同的路由通常有不同的数据。然而,有时您确实需要在 microfrontend 之间共享API数据。API对象的内存中的JavaScript缓存是一些公司用来解决这个问题的解决方案。对于React用户,这类似于带 Suspense 的数据获取,其中路由的获取逻辑是从使用数据的组件代码中分离出来的。
// 在api实用程序模块内部,您可以在另一个微前端调用导出的函数时延迟获取数据,或者在路由更改时急于获取数据。
let loggedInUserPromise = fetch('...').then(r => {
if (r.ok) {
return r.json()
} else {
throw Error(`Error getting user, server responded with HTTP ${r.status}`)
}
})
export function getLoggedInUser() {
return loggedInUserPromise;
}
import { getLoggedInUser } from '@org-name/api';
// 在app1内部,您可以从“ api”实用程序模块中导入某些内容
getLoggedInUser().then(user => {
console.log('user', user);
});
# UI状态
如果两个微前端经常在彼此之间传递状态,可以考虑合并它们。当你的microfrontend不是孤立的模块时,它的缺点就会被放大
比如“是模态打开的”、“输入的当前值是多少”等等的UI状态,基本上不需要在微前端之间共享。如果您发现自己需要不断共享UI状态,那么您的微前端可能拆分的太多了。考虑将它们合并。
在极少的情况下在需要在 single-spa 应用程序之间共享UI状态,可以使用event emitter来实现。下面是一些event emitter的例子,可能会对你有所帮助。
- Observables / Subjects (rxjs) - 一个微前端发布一个新值到一个可以被其他微前端消费的流对象,它可以向所有的微前端应用暴露出来以便其他应用可以订阅。
- CustomEvents - 浏览器有一个内置的事件发射器系统,允许你触发自定义事件。查看此文档 (opens new window)以获得更多信息。
window.dispatchEvent事件允许任何其他的微前端通过window.addEventListener订阅。 - 其他订阅发布系统。
# 结束语
我目前用的最多的就是 systemjs-webpack-interop ,通过 setPublicPath 一个公共的组件或者状态,然后 import 过去,微前端最主要的概念就是解耦,所以如果出现耦合性太高的业务时,是不建议做应用拆分的
这一章东西其实不多,但是我还是单独拿出来一章来写来,目的是希望大家对于通信的处理写的更简单,更干净一些,不要把太多的工作量放在通信方面,要记住微前端的目的是为了合理的 **解偶