你需要知道的微前端
什么是微前端
来源
微服务的思想和概念⼀开始是为了解决后端服务不断扩展带来的⼀系列例如项⽬过⼤导致的复杂度不可控、难以维护、单⼀进程 容错率低,故障可能在进程内扩散导致服务全局上的不可⽤、扩展困难等等的问题。 ⽽随着前端的不断发展,越来越重的前端⼯程也⾯临着同样的问题,于是便⾃然⽽然地将微服务的思想应⽤到了前端,所以便有 了微前端的概念。
概念
微服务与微前端,都是希望将某个单⼀的单体应⽤,转化为多个可以独⽴运⾏、独⽴开发、独⽴部署、独⽴维护的服务或者应⽤ 的聚合,从⽽满⾜业务快速变化及分布式多团队并⾏开发的需求。 如果要⽤⼀句话来概括,微前端就是将前端应⽤分解成⼀些更⼩、更简单的能够独⽴开发、测试、部署的⼩块,⽽在⽤户看来仍 然是内聚的单个产品的技术或思想。
微前端是一种类似于微服务的架构,是一种由独立交付的多个前端应用组成整体的架构风格,将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的应用,而在用户看来仍然是内聚的单个产品。
特点
微前端的核⼼是解决巨⽯应⽤,它的主要特点有:
- 耦合性更低,更简单的代码库的代码库,微前端的架构让开发者们可以更容易编写和维护更⼩、更简单、更容易开发的项⽬
- 技术栈⽆关,每个不同的服务/应⽤都可以使⽤不同的技术栈
- 可以增量升级,⽀持渐进式重构,先让新旧代码和谐共存,再逐步转化旧代码,直到整个重构完成。
- 每⼀个⼦应⽤都具备独⽴开发,持续部署,独⽴运⾏,独⽴维护的能⼒
- 单⼀职责,每个⼦项⽬只做和⾃⼰相关的业务⼯作,各⼦项⽬之间不存在依赖关系,保持隔离
当下系统开发现状
老项目
- 所使⽤的技术栈落后、较为⼩众或学习成本过⾼
- 基于原⽣
js
/jquery
开发 且架构复杂的⼤型应⽤,组织、耦合混乱,不敢乱动,牵⼀发动全身 - 项⽬强⾏混⽤多种技术栈,采⽤
react
、angular
、jq
、vue
框架混合开发,功能复杂繁多,导致项⽬结构复杂、代码量巨⼤ - 重构不彻底的代码,经历了重构-烂尾,然后⼜重构-⼜烂尾的神仙项⽬
- 项⽬⾥⾯部分模块是反编译出来的代码以及第三⽅的代码
- 你应该如何保证在逐渐重构的同时,既要保证中间版本能够平滑过渡,同时⼜要持续交付新的功能
保证项目维护迭代
- 如何确保这套技术⽅案在 3~5 年内还 葆有⽣命⼒,不会在 3、5 年后变成⼜⼀个遗产项⽬?
项目变大,变复杂不断带来的问题
- 过于复杂
- 开发速度缓慢
- 需要更多的开发人员来维护
- 从代码的提交到实际部署的周期越来越长。很容易出现问题
- 难以交付可靠的单体应用
- 需要长时间依赖某个可能已经过时的技术栈,并且框架难以升级更新
价值
- 兼容遗留系统
- 可以与时俱进,不断引⼊优秀的新技术/新框架
- ⽀持局部/增量升级,避免项⽬每次发布都是全量发布,即使是上线⼀个⼩模块,也可能导致整个项⽬挂掉
- 代码简洁、解耦、更易维护
- ⼦应⽤间可以⾃由组合拆分
- 技术栈⽆关,各⼦应⽤的开发团队可⾃⾏采取熟悉的技术栈进⾏开发,降低开发时间和成本
- 微前端可以采⽤组件或者服务的⽅式进⾏团队间的技术共享
- 每个应⽤可以独⽴部署,独⽴运⾏,拥有故障隔离
使用微前端可能遇到的问题(缺点)
- 重复依赖
- 团队之间容易分裂
- 操作复杂
- 性能处理的挑战性
- 拆分的粒度越小,便意味着架构变得复杂、维护成本变高
- 技术栈一旦多样化,变意味着技术栈混乱,系统变得更复杂,更难维护
- 管理版本复杂、依赖复杂
实现方式
中后台应用由于其应用生命周期长(动辄 3+ 年)等特点,最后演变成一个巨石应用的概率往往高于其他类型的 web 应用。而从技术实现角度,微前端架构解决方案大概分为两类场景:
- 微前端架构有两种架构模式:
- 基座模式:通过⼀个主应⽤,来管理其它应⽤。设计难度⼩,⽅便实践,但是通⽤度低。
- ⾃组织模式:应⽤之间是平等的,不存在相互管理的模式。设计难度⼤,不⽅便实施,但是通⽤度⾼。
目前流行的微前端方案有哪些
- 路由分发式
用 nginx 做代理转发
http {
server {
listen 80;
server_name care.seewo.com;
location /web/edu/ {
proxy_pass http://admin-care-dev.test.seewo.com/web/edu/;
}
location /web/home {
proxy_pass http://admin-care-dev.test29.seewo.com/web/home/;
}
location /web/user {
proxy_pass http://admin-care-dev.test298.seewo.com/web/user/;
}
location /web/profile {
proxy_pass http://admin-care-dev.test298.seewo.com/web/profile/;
}
location / {
proxy_pass /;
}
}
}
适⽤场景:
- 不同技术栈之间差异⽐较⼤,难以兼容、迁移、改造
- 项⽬不想花费⼤量的时间在这个系统的改造上
- 现有的系统在未来将会被取代
- 系统功能已经很完善,基本不会有新需求
优点:
- 框架⽆关
- 独⽴开发、部署、运⾏
- 应⽤间百分百隔离
- 实现简单
缺陷:
- 应⽤间的彻底隔离会导致复⽤⾮常困难
- 例如每个应⽤的导航栏如果想在其他系统中复⽤将⾮常困难
- ⽤户体验⾮常差,每个独⽴应⽤只在跳转之后加载,时间较⻓,容易出现⽩屏
- 如果后续有同屏多应⽤拓展的需求将会⾮常困难
- iframe
适用场景:
- 不考虑 seo
- 不在意交互
优点:
- 框架无关
- 独立开发、部署、运行
- 应用之间绝对隔离
- 实现简单
缺点:
- 一个 iframe 等于打开一个新网页,js/css 等重复加载,无法释放造成内存泄漏
- iframe 和主页共享连接池,而浏览器对相同域的链接有限制,会影响页面的并行加载,阻塞主页的资源加载
- 对移动端及其不友好
- 无法 seo
- 体验不好
- 前端微服务化(主要)
前端微服务化,是微服务架构在前端的实施,每个前端应⽤都是完全独⽴(技术栈、开发、部署、构建独⽴)、⾃主运⾏的,最后通 过模块化的⽅式组合出完整的前端应⽤. ⽤这个办法可以⼀个⻚⾯上同时存在⼆个及以上的前端应⽤在运⾏。⽽不像上⾯的路由分发式⽅案,⼀个⻚⾯只有⼀个应⽤。
- 微件化
基于web components
需求场景
- 只有一个主项目,主项目只有一个
html
入口,子项目通过主项目来按需加载; - 菜单栏、登录、退出等功能都从子项目剥离,写在主项目里,再有相关改动只需修改主项目,包括错误监控、埋点等行为,只需处理一个主项目,子项目不再需要处理;
- 子项目原本需要加载的公共部分(如
vue
、vuex
、vue-router
、ivew/element
、私有npm
包等),全部由主项目调度,配合webpack
的externals
功能通过外链的方式按需加载,一旦有一个子项目加载过,下一个子项目就不需要再加载,这样一来每个子项目的dist
文件里就只有子项目自己的业务代码(最终子项目包的体积缩小了 80%,只有几十 k),项目实际加载速度快了很多,肉眼可见; - 子项目并没有重新开发,只是进行了一些改造,接入了微前端这套架构,所以新需求 X 的开发成本也极大的降低了,接入功能同时可供未来新增子项目使用;
优缺点
优点
- 与时俱进,不断引入新技术/新框架
- 局部/增量升级
- 代码简洁、解藕、更易维护
- 独立部署
- 组织更具扩展能力,团队独立自治
- 技术栈无关/版本无关
缺点
- 重复依赖
- 团队分裂
拆分
- 按照业务拆分
如:⼀个电商后台,包括商品管理、商家管理、物流管理等。 优势是独⽴出每个业务项⽬,可以让整个项⽬结构清晰。
- 按照权限拆分
如:⼀个运营后台,管理员和普通运营看到的⻚⾯是不⼀样的。 优势是独⽴出不同的权限项⽬,可以突出每个项⽬的使⽤范围。
- 按照变更的频率拆分
如:⼀个项⽬中,包含很少改动的祖传项⽬和经常改动的业务项⽬。 优势是 1.独⽴出变更频繁的项⽬,可以避免频繁更新可能导致整体项⽬挂掉的⻛险。 2.独⽴出很少改动的项⽬,可以让我们在核⼼业务上⼤展拳脚
- 按照组织结构拆分
⼀个功能复杂的项⽬后台,由多个团队共同开发⽽成。 优势是独⽴出不同团队的项⽬,可以避免开发冲突,部署冲突等问题。
- 跟随后端微服务划分
如:后端已经做了不同模块的微服务划分,前端可以直接按照后端来就⾏了。 这种⽅式有利于前后端保持统⼀
微应用的拆解没有具体规则,但是以下规则应该可以给你在进行系统拆分时提供一些依据。
-
“尽量减少彼此的通信和依赖“ ,微前端的通信交互、链接跳转等操作所带来等成本其实是很大的,所以在拆分的时候尽量“完全独立,互不依赖”
-
微应用的拆分的时候切忌“盲目细致拆分” ,过度拆分会导致 “做的很牛逼,但是没有用的困局”,微应用的拆分并不是一步到位的,我们要根据实际情况逐步拆分。如果一开始不知道应该划分多细,可以先粗粒度划分,然后随着需求的发展,逐步拆分。
- 如:现在有一个售后管理系统,我们按业务线拆分为:客服管理,库存管理,物流管理,未来客服管理需求功能持续庞大再拆解为:智能客服、电话客服、在线客服。而这些客服,又可以嵌入供应商管理中心,商品管理中心 等项目使用。
-
在拆分的时候我们应该尽量考虑未来场景:渐变式技术栈迁移,前端应用聚合、多系统业务复用,如何做业务解耦和代码复用。
-
应用之间应该尽量解耦,子应用的事情就应该由子应用来做。
- 如:子应用的一些标识,如:路由前缀,应用名称,根节点容器名称,依赖库的使用
- 需要明确什么是子应用应该维护的,什么是父应用应该维护的,如果什么资源都一股脑的使用父应用下发,则会导致应用之间耦合严重。
建议按照业务域来做拆分
- 保持核心业务的独立性,把无关的子业务拆分解耦。业务之间开发互不影响,业务之间可拆解微应用,单独打包,单独部署。
- 业务关联紧密的功能单元应该做成一个微应用、反之关联不紧密的可以考虑拆分成多个微应用,判断业务关联是否紧密的标准:看这个微应用与其他微应用是否有频繁的通信需求。
- 如果有可能说明这两个微应用本身就是服务于同一个业务场景,合并成一个微应用可能会更合适。
- 分析平台差异,平台差异大可以根据平台特性拆分
- 分析页面结构,如果结构清晰,可以根据结构拆分
- 分析产品业务,将产品逻辑耦合度高的功能合并到一起
问题
主项⽬和⼦项⽬的样式是否需要复⽤? 项⽬权限,是分开还是在统⼀管理? 应⽤之间如何进⾏通信?
社区框架
- single-spa single-spa.js.org/
- qiankun qiankun.umijs.org/zh 蚂蚁
- icestark micro-frontends.ice.work/ 淘宝
- micro-app zeroing.jd.com/micro-app/d… 京东
- garfish www.garfishjs.org/ 字节
- emp emp2.netlify.app/ 欢聚时代
- wujie wujie-micro.github.io/doc/ 腾讯
选型参考
参考点
未来迭代
稳定性
该方案是否经历了社区的考验,有较多的成熟案例,同时保持较高的 活跃性
可拓展性
支持定制化开发,提供较高的可拓展能力,同时成本可以在接受范围内
可控性
发生问题后,能够在第一时间内进行问题排查,以最快的响应速度来处理问题,修复的方案是否会依赖于外部环境
基座主应用
选择基座的模式?
- 通用中心路由基座式:只有公共功能的主应用(菜单栏、登录、退出…)不包含任何业务逻辑
- 特定中心路由基座式: 一个含业务代码的项目作为基座,所有新功能作为子应用引入
运行方式
- 作为子应用一起运行,不需要有登陆页,菜单栏等页面布局,路由的设计(如何做)
- 单独部署使用与上相反
- 菜单的权限系统
微应用
qankun
- 保证技术栈统一 、微应用之间完全独立,互不影响。
- 友好的“微前端方案“,与技术栈无关接入简单、像
iframe
一样简单 - 改造成本低,对现有工程侵入度、业务线迁移成本也较低。
- 和原有开发模式基本没有不同,开发人员学习成本较低。
- qiankun 的微前端有 3 年使用场景以及
Issue
问题解决积累,社区也比较活跃,在踩坑的路上更容易自救
注意:
- 子应用需要支持跨域
history
可以省很多事
微前端需要注意的问题
- 样式隔离
developer.mozilla.org/zh-CN/docs/…
www.ruanyifeng.com/blog/2019/0…
- js 沙箱隔离
- 父子通信
微前端场景下,我们认为最合理的通信方案是通过 URL
及 CustomEvent
来处理。但在一些简单场景下,基于 props
的方案会更直接便捷,因此我们为 qiankun
用户提供这样一组 API
来完成应用间的通信
react 基座接入 webpack 子应用
- 复杂度中等,子应用简单修改
- 整体对于
react
、vue
项目表现良好 - 基本
webpack
打包都相似,表现良好
接入 vite 子应用
vite
+react
- 官方暂不支持,有第三方解决方式勉强能用,不保证好的开发体验
- 需要关闭沙箱隔离机制,伴随样式污染等问题
问题:
- 乾坤暂不支持
vite
(官方未正面回复,框架原因) - 使用
vite-qiankun
插件勉强可以使用但样式不能够隔离会出现样式污染(貌似框架的坑) - 开发阶段和生产阶段两个不同的配置,开发阶段不能使用
react
插件,且页面需要引入react
(显式/可以用ts
的配置规避) - 静态资源开发阶段不显示需要设置
server
代理 - 由于
qiankun
采用html Entry
,localStrage
、cookie
可共享
micro-app
优点:
- 简单:只需一行代码,实现微前端,如此简单;(那得是
webpack
) - 无关技术栈:任何框架皆可使用;
- JS 沙箱;
- 样式隔离;
- Qiankun 微前端框架的优势他都有;
注意:
- 子应用需要支持跨域
- history 可以省很多事