要求循环队列不损失一个空间全部能得到利用_berial,一个精致的微前端框架

9c328d41d951e6c06f405037c4c27a85.png

halo,大家好,我是 132,前阵子冥思了一会儿微前端,然后周六日趁热打铁,马上写了一个微前端框架,名叫 berial

然后今天是开源的第三天,得到了很多友情赞,昨晚正式发版了,请容我一一道来

微前端的核心和本质

俺之前有发过一篇文章:https://zhuanlan.zhihu.com/p/165002889

微前端产生的原因,说白了是个业务问题,我们的业务项目,分久必合合久必分,一个项目合在一起太久了,等到不好维护的时候,就需要拆分,反之同理,拆的太碎的时候,合在一起更容易维护


微前端的本质是前端路由,不需要和运维童鞋联调,而且自己还能控制生命周期,进行沙箱隔离,甚至可以状态通信


微前端框架大致套路差不多,大概包括下面几个 feature,请容我一一道来

lifeycycles
shadow dom
scoped css
Proxy sandbox
html-loader
global store

lifecycle loop

生命周期的是 single-spa 的核心,berial 内部也复现了一组类似的循环队列

load 阶段(microtask) 
importHtml -> parser -> shadowdom -> proxy sandbox -> bootstrap() 

mount 阶段(macrotask) 
mount() -> umount() -> mount() -> unmount() -> ... 

如上所见,这些生命周期,有的只执行一次,有的会每次执行一次交替,和我们常见的 event loop 非常相似,所以这个机制我们也成为 lifecycle loop

其中,load 阶段, 负责做的事情有点多,大概就是 import html 然后解析出 dom、css、script,然后将 dom 和 css 放到 shadow 中,然后给 script 套一个 sandbox,然后将 lifecycles 收集起来,这所有流程的每一个步骤,都是 promise,所以这是个微任务队列

然后之后的路由切换,就不断调用 mount 和 unmout 钩子,交替调用……


mount 中做渲染工作,比如 React.render(), unmout 同理


最终,berial 实现了一套类似 event loop 的生命周期队列

shadow dom & scoped css


shadow dom 又名沙雕 dom,名副其实的沙雕,钢铁直男,一点也不弯


市面上几乎所有微前端框架都选择弃用沙雕,berial 的话却选择一起沙雕


这会导致很多问题,有时候需要手动改业务逻辑,但也能接受,我们做微前端框架,真的不是为了 0 改动 迁移,如果追求 0 改动,请移步 iframe


所以我认为,消耗一点点迁移成本,换来更好的架构设计,是容许的


用了沙雕之后,scoped css 浑然天成,而且非常硬,根本无法穿透(还是有 hack 办法的)


Proxy & Mutation Observer sandox


js 沙箱机制,是微前端框架另一个机制,微前端的沙箱一般来说是劫持 window


其中一种是快照沙箱,原理是对 window 进行多次遍历,达到激活和失活的效果,但这不适用于 berial,我们企图找到更好的抽象机制

另一种思路是 Proxy,这也是 qiankun,berial 正在使用的思路

其中有人借用了 iframe 的 contentWindow,去得到一个完全不同的 window

https://github.com/aliyun/alibabacloud-console-os/blob/master/packages/core/browser-vm/src/Context.js#L70

但是我认为这是不符合语义的,因为实际上,我们的沙箱是针对 js 的,而其他所有内容,比如 document,其实还是同一个 document

所以我们没必要全部重新实现一遍 window,但是这样就会有经典额逃逸问题

什么是逃逸问题呢,就是在 js 里加载一个新的 js,

const script = document.createElement('script')
document.head.appendChild(script)

这样,在头部添加一个 script,那么这个 script 就会从沙箱逃逸到外部 document 中

其他框架仍然是使用了 Proxy 进行劫持,berial 中使用了 Mutation Observer

我们侦测 document 的变化,如果变化的 target 不是当前沙箱,则对其进行劫持,然后塞回沙箱

html-loader


html-loader 也是 berial 的一个核心,灵感来自 qiankun,其实是一个 parser,然后找到 script 和 style,暴露出来


这部分目前是纯正则,因为这份匹配实际不需要走整套编译流程,相对 case 其实不是很多


有兴趣的童鞋可以尝试读一下,我们未来也会通过这个机制去探讨正则的更优写法和更高性能

global store


用于状态通信的最简机制,也是通过 Proxy 实现的,可以简单方便地在不同 APP 之间通信
然后我们还会自带一个批处理,让用户多次修改状态,mount 阶段都交替一次

different from qiankun?


和乾坤的不同在于,我们原生使用了沙雕,sandbox 的实现也更科学,而且不依赖 single-spa,所有代码都能自己控制,各个机制之间的优化空间更大


berial 虽然是个业务框架,但代码还是会延续我的风格,就是简单直白风,在追求业务的同时,我们还是会花时间研究底层架构的设计改进

webpack5 module federation?

这里真的很有必要提一下 webpack5 的新特性,中文名叫做「模块联邦」,令人稍稍有点沮丧的是,这玩意完全可以实现多个不同技术栈共存,而不需要任何框架

也就是说,如果你没有沙箱隔离需求,只是需要技术栈无关,那完全可以使用 webpack 自带的插件搞定

所以我现在的观点是,对于无法升级 webapck,代码逻辑很乱需要隔离的多技术栈,可以使用 berial / qiankun 这种 runtime 方案

如果是能够使用 webpack5,仅仅只是为了技术栈无关,代码共享,可以直接使用 MF


以上就是最近搞得全部了,最后放一下地址:

github.com/berialjs/be…​github.com


欢迎大家加入组织,未来 berial 也会社区维护下去,大家有啥新想法和玩法可以一起讨论呀

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值