智联招聘的微前端落地实践——Widget
ThoughtWorks 在几年前提出了微前端的概念,其核心理念是将前端单体应用在开发阶段拆分成多个独立的工程,并在运行阶段组合成完整的应用。不仅解耦了视图和代码,使得应用可以容纳多种技术栈,还进一步解耦了流程和团队,极大地提高了团队的自主性和协作效率。
智联招聘的大前端架构Ada本身就可以看作一个基于路由的微前端架构,围绕 URL 的研发方式能够灵活地实现页面级别的解耦。而在在视图区域级别,Ada 也引入了专门的微前端实现机制——Widget。
什么是 Widget
Widget 是一种可以独立开发和发布的视图区域,它运行于宿主页面中,并且能够和宿主页面进行双向通信。
在设计 Widget 架构时,我们考虑到 Ada 的多框架支持能力,应当让 Widget 在使用时不受框架的限制,也就是说,使用 Knockout.js 开发的 Widget 可以运行在 Vue.js 的页面中,反之亦然,这就决定了 Widget 的最终形态必须是框架无关的 Plain JavaScript。出于同样的考量,通信机制也不应该受框架所限,而应该制定属于 Widget 的通信 API 规范。
总结一下,Widget 的设计目标是:
框架独立,不受宿主页面技术栈限制;
流程独立,能够独立开发和发布,集成后无需宿主页面再次配合发布;
执行独立,运行逻辑不直接操控宿主页面,而是通过 API 来交换信息;
展现独立,内容和样式均限定在 Widget 视图区域之内,不直接影响宿主页面;
整体架构
为了统一开发体验,Ada 从开发、调试、发布和运行都为 Widget 进行了专门的支持。
在开发阶段,理论上任何能够编译成 Plain JavaScript 的框架都可以使用,Ada 在 Vue.js 等脚手架中内置了对 Widget 的支持,开发者可以使用熟悉的技术开发 Widget,也可以像调试页面一样预览和调试 Widget。
我们在脚手架内核中为 Widget 单独设计了 Webpack 配置,使得基于各种框架开发的 Widget 都能输出成一个独立的 JavaScript Bundle(样式也会构建到同一个 Bundle 中),藉此来保证输出的文件符合 Widget 规范。
就像 Ada 体系里的其他工件一样,每个 Widget 都有一个唯一 URN,宿主页面通过该 URN 来引用 Widget,从而和 Widget 的 JavaScript Bundle 解耦。在发布阶段,Ada 会为 URN 关联最新的输出清单,这样一来,Widget 不但可以脱离宿主页面独立发布,还能进一步实现灰度发布和 A/B 实验。
运行时
Widget 的生命周期包括四个阶段:注册、初始化、运行和销毁,各阶段之间的转换是由 Widget SDK 来负责调度的。
宿主页面使用<script>标签加载 Widget URN 时,Ada Server 会负责调度并返回正确的 JavaScript Bundle,加载完毕后,就会向 Widget SDK 注册自己。
注册完毕之后,宿主页面就可以调用 Widget SDK 的 init 方法,并传递 Widget 名称和父元素 DOM,来决定 Widget 的初始化时机和位置。宿主页面还可以初始化同一个 Widget 的多个实例,并和它们分别进行通信。
Widget 的消息通信机制借用了 Web Worker 的 API 规范,宿主页面可以通过 Widget SDK 的 postMessage 方法向指定 Widget 发送消息,同时通过 onmessage 方法监听 Widget 发来的消息。反过来,Widget 也可以用同样的方式和宿主页面通信。
当宿主页面需要销毁组件时,可以调用 Widget SDK 的 destory 方法,后者会指示 Widge 销毁视图、清理存储,然后再将 Widget 移出事件中心。
开发 Widget
Widget 本质上是一个规范化的 Class,可以使用 Plain JavaScript,也可以融入任何框架,比如借助 Vue.js 来开发 Widget 的代码可能是这样的:
使用 Widget
宿主页面通过<script>标签导入 Widget URN,然后初始化即可:
为了贴合现代 Web 框架组件化的研发习惯,我们为 Vue.js、Knockout.js 和 Weex 提供了 Widget 组件,藉此来简化 Widget 加载和初始化步骤。例如在 Vue.js 中,可以这样加载一个 Widget:
初始化 Widget 之后,就可以与宿主页面进行双向通信了,例如:
实际应用
目前集团内已累计发布了 100 余个 Widget,各条产品线都招到了 Widget 能发挥作用的场景,比如:
Passport 借由 Widget 统一了集团内的所有登录逻辑,能够更好地调整安全策略,业务方通过接入 Widget 即可实现登录功能;
限时推广的 Banner 或隐私通知,常常同时在多个产品中同时展示,且变化频率较高,Widget 能够有效地将其和业务代码解耦;
内部系统在升级时,可以借助 Widget 在视图层面一小块一小块地逐步迁移,从而在用户无感的情况下渐进式地完成整体升级工作;
微前端不止步于 Widget
发布于 2019 年初的 Widget 机制,是我们在微前端领域的第一次尝试,成效令人满意。集团内对 Widget 的广泛应用带来了更多的诉求和灵感激发,未来,我们还会结合业务特点去探索微前端的其他可能性,让架构赋能业务,为用户带来价值。
版权声明: 本文为 InfoQ 作者【智联大前端】的原创文章。
原文链接:【http://xie.infoq.cn/article/710dc3f85bca1323e80e64381】。文章转载请联系作者。
评论