从 alicloud-console-os 看微前端
yshaojun opened this issue · comments
微前端(或者叫前端微服务)以技术无关、独立部署的特点,成为前端重点关注的技术方向之一。虽然业内对微前端基本要点(比如服务加载、隔离、通信、路由等)的认识趋于一致,但是仍然没有一套完整且公认的解决方案。
本文是读阿里云 alicloud-console-os 的感受,看它是分别选择怎样的方案解决上述问题的。
入口
直接的想法是以 js 为入口,就像个人网站接百度推广那样,但问题是不好处理 css 和 thunk js;以 html 为入口,又需要对 html 进行解析,做起来也比较麻烦。
console-os 使用 json 文件作为入口,这个文件里包含了 css、js 等资源 url 列表,配合 jsonp 的引入方式(下文介绍),显得简单可靠。
加载
之前想到的加载办法是 fetch
到 js 代码,然后用 eval
或者 new Function
执行;fetch
到 css,用 innerHtml
插入到 DOM 里,问题是如果 js 加载其他 chunk js 时,在加载方式又比较混乱。
console-os 使用 jsonp 的方式,在 head
里插入 script
、link
标签,配合子应用打包时最外层包裹的函数:
window.__CONSOLE_OS_GLOBAL_HOOK__(
id,
function(require, module, exports, { window, location, history, document }){
// 子应用代码
}
)
应用就加载即执行了。
隔离
在上述的 __CONSOLE_OS_GLOBAL_HOOK__
函数中,传入了用 Proxy
劫持的 {window,location,history,document}
,以此实现了子应用 js 隔离。这个地方有个有趣的实现,相比 qiankun 的 “快照”,console-os 是为每个子应用创建一个隐藏的 iframe
,然后把这个 iframe
上的全局变量比如 history
传给它!因此子应用的全局操作,一部分就直接落到各自的 iframe
上。
官方 example 里没有实现 css 隔离,不过从示例看,子应用都被限制在各自以 id 为名称的自定义 html 标签里,加上子应用使用同一个 Document
对象,因此很容易套用常规的组件局部样式方案,比如选择器都加最外层 class、自定义属性 data-[hash] 等。
通信
console-os 的父子应用并没有完完全全的隔离开,比如它们仍然共用相同的 Window
、Document
(当然对子应用,以 Proxy
对部分属性做了拦截),所以它们的通信没有天然的障碍。官方在 events 中,直接使用了 EventEmitter
。
路由
console-os 中对子应用的路由进行了隔离,但是目前并未实现完整的路由方案。不过在 console-os 中实现应该不难,宿主获取路由信息,通过事件向子应用广播,子应用以 id 为频道订阅自己的,然后做对应的路由动作;子应用切换路由时,以同样的方式通知宿主做路由变更,应该就行了。
微组件
其他微前端框架中,都是以类似配置或 api 的形式引入子应用,在 console-os 中,提供了组件形式:
function App() {
return (
<div className="App">
{/* 渲染应用 */}
<div className="react">
<Application
id="os-example"
manifest="http://localhost:8081/os-example.manifest.json"
/>
</div>
</div>
)
}
这种方式利于在已有项目中灵活的引入微服务。