智汇 IT
城启新篇

微前端的代价你算过没有

去年冬天,一个做后台系统的朋友找我喝酒。他说他们前端团队从八个人扩到了二十三个,分成了三个组。听起来是好事对吧。可发版那天,三个组要一起上线。A组改了一个按钮的间距,B组的回归测试没过,C组的代码就卡在流水线上。等到凌晨两点,就为了一个按钮。

他说,我们是不是该上微前端了。

我没直接回答。因为这个问题,我听过太多次。微前端这东西,本质上不是什么新技术。它是被组织问题逼出来的工程妥协。你想把一个大的前端应用拆成几块,让不同的团队独立开发、独立部署、独立上线。听起来很美。做起来,处处是坑。

拆开容易合上难

最早大家用iframe。简单粗暴,天然隔离。样式不打架,JS不冲突,连路由都是各玩各的。但问题也明显。弹窗只能在iframe里面弹,跨iframe通信要靠postMessage,用户体验割裂。你打开一个页面,看到的地址栏是主应用的,里面的内容却是子应用的。刷新一下,状态全丢。

后来有了single-spa。它提供了路由级别的应用加载和卸载。再后来qiankun在single-spa之上做了封装,把HTML Entry、样式隔离、JS沙箱这些东西打包好了。用起来确实方便了不少。你只要注册子应用,配好activeRule,剩下的它帮你处理。

微前端qiankun应用加载与沙箱机制流程图
微前端qiankun应用加载与沙箱机制流程图

但方便是有代价的。qiankun的JS沙箱,本质上是用Proxy拦截window上的属性读写。子应用挂载的时候,沙箱把window代理一遍。子应用卸载的时候,沙箱把改过的属性还原。听起来很干净。实际上呢。如果你用了第三方的图表库,它往window上挂了一个全局变量。沙箱还原的时候,这个变量没了。下次再挂载,图表库发现变量不存在,又初始化一遍。内存泄漏就是这么来的。

这不是qiankun的错。这是沙箱机制的固有矛盾。你要隔离,就要接管所有的副作用。可你永远不知道一个第三方库会往window上扔什么东西。

样式隔离是个玄学

CSS这东西,天生就是全局的。微前端要让多个子应用的样式互不影响,方法有好几种。加前缀,用Shadow DOM,或者运行时动态改写样式规则。

qiankun默认用的是动态改写。子应用加载的时候,它把style标签里的选择器加上一个类似div[data-qiankun-app]的前缀。这样样式只在子应用容器里生效。听起来很聪明。但如果你用了CSS-in-JS,样式是运行时插入的,沙箱就管不到了。还有,如果子应用里有组件库用了body上的样式,前缀加不上,照样污染全局。

Shadow DOM隔离得更彻底。样式和DOM都在一个封闭的阴影树里。但麻烦在于,主应用和子应用的样式没法共享。主应用改了主题色,子应用要重新适配。弹窗、下拉菜单这些挂到body下的组件,会跑到Shadow DOM外面,位置全乱。

微前端样式隔离ShadowDOM与CSS作用域对比图
微前端样式隔离ShadowDOM与CSS作用域对比图

说白了,没有完美的隔离方案。你只能选择性地接受某几种副作用。

模块联邦解决了一部分问题

模块联邦解决了一部分问题
模块联邦解决了一部分问题

Webpack 5的Module Federation是另一个思路。它不是运行时加载子应用,而是把子应用的模块暴露出来,主应用在构建时或者运行时去消费这些模块。

好处是,共享依赖变得容易了。React、Vue这些公共库,配好shared,就不会重复加载。子应用也可以按需暴露组件,不用把整个应用都塞进去。

坏处是,它对构建工具和版本有要求。如果你的项目还在用Webpack 4,或者用的是Vite,Module Federation的支持就没那么顺滑。而且,运行时共享依赖意味着版本必须对齐。主应用用React 17,子应用用React 18,共享的时候就会冲突。要么升级,要么隔离,没有第三条路。

还有个更隐蔽的问题。Module Federation让主应用和子应用在构建时产生了隐式耦合。子应用暴露的模块名改了,主应用如果没同步更新,运行时直接报错。这种错误在开发环境往往发现不了,因为开发时是各自独立构建的。到了集成环境才暴露,排查成本很高。

组织边界比技术方案重要

我见过太多团队,技术选型做得很漂亮,微前端的架子搭得整整齐齐。上线三个月,子应用之间的依赖又缠成了一团。A子应用直接引了B子应用的组件,C子应用偷偷调了D子应用的接口。问起来,都说为了方便。

微前端的前提是组织边界清晰。哪个团队负责哪块业务,哪块业务对应哪个子应用,子应用之间怎么通信,谁来决定通信协议。这些东西如果不提前定好,微前端只是把单体应用的混乱分散到了多个代码仓库里。复杂度没有降低,只是换了个地方藏。

康威定律说,系统架构会反映组织的沟通结构。反过来说,如果你不改变沟通结构,架构也不会真正改变。你把代码拆开了,但团队还是每天站在一起开会,接口还是靠口头约定,那拆了等于没拆。

微前端多团队协作发布流水线示意图
微前端多团队协作发布流水线示意图

什么时候不该上微前端

什么时候不该上微前端
什么时候不该上微前端

如果你的团队不到十个人,前端应用不超过三个模块,别碰微前端。收益太小,成本太高。你花在搭架子、调沙箱、处理样式冲突上的时间,够你把单体应用重构两遍了。

如果团队之间没有独立的发布需求,也别碰。微前端的核心价值是独立部署。如果每次发版还是大家一起上,那微前端带来的只有复杂度。

如果你的技术栈高度统一,全是React,全是同一套构建工具,那也许Module Federation就够了,不需要搞一套完整的微前端框架。

真正需要微前端的场景,往往是这样的:团队规模到了几十人,业务模块之间有明确的边界,发布节奏不一致,技术栈可能还有历史包袱。这时候,微前端是一剂对症的药。

但它也只是药。药有副作用,有疗程,有配伍禁忌。别把它当饭吃。

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:微前端的代价你算过没有
文章链接:https://m.itcdj.com/news/811.html