2020年4月,有赞美业的前端团队历经7个月时间,完成了美业PC架构从单体SPA到微前端架构的设计、迁移工作。PPT在去年6月份就有了,现在再整理一下形成文章分享给大家。
头图
Part 01 “大话”微前端
微前端是什么
背景
目标
达成价值
缺点
Part 02 架构与工程
微前端方案有哪些
架构设计选型注意点
需求分析
设计原则
应用架构图
系统拆分
时序图
前端流程图
Part 03 关键技术
关键技术一览
架构核心
注册中心
代码复用
子应用
Part 04 项目实施
立项前的心路
参考微前端资料
进行PC架构优化计划
风险
迭代立项
进展
后续计划
把这个事情的前因后果讲清楚
想要回答这个问题直接给一个定义其实没那么难,但是没接触过的同学未必理解。所以需要先介绍一下背景,再解释会更容易明白。
web发展1
这张图,展示了软件开发前端后分工的三个时期:
web发展2
现在很多互联网公司的研发团队的工作模式更靠近这种,把整个产品拆分成多个阿米巴模式的业务小组。 在这种研发流程和组织模式下,后端的架构已经通过微服务化形成了拆分可调整的形态,前端如果还处于单体应用模式,不谈其它,前端的架构已经给协作带来瓶颈。 另外 Web 3.0 时代来临,前端应用越来越重,随着业务的发展迭代和项目代码的堆积,前端应用在勤劳的生产下演变成了一个庞然大物。人关注复杂度的能力有限,维度大概维持在5~8左右。单体应用聚合的生产资料太多,带来复杂性的维度太多,也容易引发更多的问题。简而言之,传统的SPA已经没办法很好的应对快速业务发展给技术底层的考验。 我们的产品和前端项目也同样遇到了这个问题。如何解决这个问题呢? 其实后端的发展已经给出了可借鉴的方案,在理念上参照微服务/微内核的微前端架构应时而生。 想要解决这个问题,在吸引力法则的指引下我们遇到了微前端架构,也验证了它的确帮助我们解决了这个难题。
现在给出我们的微前端这样一种定义:
微前端是一种类似于微内核的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单体应用转变为多个小型前端应用聚合为一的应用。多个前端应用还可以独立运行、独立开发、独立部署。
背景
总体来说,臃肿的单体应用模式,给开发人员带来了无法忍受的难处,给快速支撑业务带来了很大的瓶颈,也没有信心应对接下来的业务的继续拓展。对美业PC进行架构调整就是非常迫切和有价值的事情了
一个架构的设计其实对整体的一个权衡和取舍,除了价值和优势之外,也带来一些需要去考虑的影响。
缺点
从全局视角把握成果
微前端
每种方案都有自己的优劣,我们兄弟团队采用了最原始的网关转发配置类似 Nginx 配置反向代理,从接入层的角度来将系统组合,但是每一次新增和调整都需要在运维层面去配置。
而 iframe 嵌套是最简单和最快速的方案,但是 iframe的弊端也是无法避免的。 Web Components的方案则需要大量的改造成本。 组合式应用路由分发方案改造成本中等且满足大部分需求,也不影响个前端子应用的体验,是当时比较先进的一种方案。
综合评估之后我们选用了组合式应用路由分发方案,但是仍然有架构整体蓝图和工程实现需要去设计。
应用架构图
系统拆分
这里拆分需要说明三个点:
时序图
流程图
## Part 03 关键技术
落地中有哪些值得一提的技术细节
我们按项目拆分来结构化讲述,有架构核心、注册中心、子应用、代码复用四篇。 其中包含了这些技术点:
消息通信 消息通信1 消息通信2 消息通信3
路由分发
当浏览器的路径变化后,最先接受到这个变化的是基座的router,全部的路由变化由基座路由 RouterMonitor 掌管,因为它会去劫持所有引起url变化的操作,从而获取路由切换的时机。如果是apps/xxx/#
之前的变化,只会拦截阻止浏览器再次发起网页请求不会下发,没有涉及#之前的url变化就下发到子应用,让子应用路由接管。
主要分为 JavaScript执行环境隔离 和 CSS样式隔离。
JavaScript 执行环境隔离:每当子应用的JavaScript被加载并运行时,它的核心实际上是对全局对象 window 的修改以及一些全局事件的的改变,例如 JQuery 这个js运行之后,会在 window 上挂载一个 window.$ 对象,对于其他库 React、Vue 也不例外。为此,需要在加载和卸载每个子应用的同时,尽可能消除这种冲突和影响,最普遍的做法是采用沙箱机制 SandBox。 沙箱机制的核心是让局部的 JavaScript 运行时,对外部对象的访问和修改处在可控的范围内,即无论内部怎么运行,都不会影响外部的对象。通常在 Node.js 端可以采用 vm 模块,而对于浏览器,则需要结合 with 关键字和 window.Proxy 对象来实现浏览器端的沙箱。
CSS 样式隔离:当基座应用、子应用同屏渲染时,就可能会有一些样式相互污染,如果要彻底隔离 CSS 污染,可以采用 CSS Module 或者命名空间的方式,给每个子应用模块以特定前缀,即可保证不会相互干扰,可以采用 webpack 的 postcss 插件,在打包时添加特定的前缀。 对于子应用与子应用之间的CSS隔离就非常简单,在每次应用加载是,就将改应用所有的 link 和 style 内容进行标记。在应用卸载后,同步卸载页面上对应的 link 和 style 即可。
我们把路由分发、应用隔离、应用加载、通用业务逻辑收纳到到了微前端内核的二方包中,用作各个业务线复用,在内部达成统一约定。
内核流程图
其实大部分公司在落地微前端方案的时候,并有没所谓的注册中心的概念。为什么我们的微前端也会有注册中心这个概念和实际存在呢?选型的思考点也主要来自我们后端的微服务架构。
注册中心
两个原因:
需要一个注册中心的话,我们也有两种方案,一种是自己自研一个专门服务于自己的微前端,虽然可以更加贴合和聚焦,但是作为注册中心,高可用的技术底层要求下的熔断降级等机制必不可少,这些研发难度大成本也高。还有一种是直接应用成熟的提供注册中心能力的开源项目或者依赖公司的已经存在的技术设施组件。
最后我们确定在选用公司内部的基础技术设施的 Apollo 项目,优势有这么两方面。
apollo-basic
1 . 定位:一个子应用构建完是一个带 hash 的静态资源,等待被基座加载。
2 . 怎么做:
a . 打包一个单入口的静态资源,同时暴露全局方法给基座
b . 每次构建生成带 hash 的入口 app.js
c . 获取打包产出生成上传配置
d . 根据环境参数上传到apollo
3 . 体验如何
非常轻量,无须发布,构建即可
apollo页面
微应用发布
1、添加 shared 为远程仓库
git remote add shared http://gitlab.xxx-inc.com/xxx/xxx-pc-shared.git
2、将 shared 添加到 report 项目中
git subtree add --prefix=src/shared shared master
3、拉取 shared 代码
git subtree pull --prefix=src/shared shared master
4、提交本地改动到 shared
git subtree push --prefix=src/shared shared hotfix/xxx
注:如果是新创建子应用 1-2-3-4 ;如果是去修改一个子引用 1-3-4
首先,我们需要明白我们对子应用的定位:
一个子应用构建完后是一个带 hash 的静态资源,等待被基座加载,然后在中心渲染视图,同时拥有自己的子路由
第一步,根据我们的模板新建一个仓库,并置入对应子应用的代码
子应用目录结构
第二步,接入shared以及修改一系列配置文件
第三步,进行开发所需要的转发配置
第四部,运行,并尝试打包部署
开发体验
一个问题从出现到被解决走过的曲折道路
微前端资料
PC架构优化计划1
PC架构优化计划2
PC架构图
kickoff
afterplan
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8