如何设计实现微前端框架-qiankun

发表于 2年以前  | 总阅读数:336 次

一、自我介绍

大家好,今天由我带来前端早早聊本次微前端专题的最后一场,《如何设计实现微前端框架 - qiankun》。首先呢,我做一个简单的自我介绍。

自我介绍

我叫方涣,在一些平台上,比如知乎和语雀上,用的就是左边这个头像。

我现在是蚂蚁金服体验技术部的一名前端工程师,和有知一起维护和迭代 qiankun。现在也正在做蚂蚁内部新一代的前端运行时平台,正是基于微前端技术的。

qiankun 简介

首先开始之前,我先给大家简单的介绍一下乾坤,大家可以在 <qiankun.umijs.org> 的官网上,看到 qiankun 的介绍和 qiankun 的文档,诚如这张官网截图所示,我们对 qiankun 的一句话定义就是:“可能是你见过最完善的微前端解决方案”,它有以下 3 个特点:

简单。无论你是什么技术栈,你用的是什么 js 框架,你都可以使用 qiankun 来把你的子应用接入到你的框架应用中,接入非常简单,就像接入一个 iframe 系统一样。

完备。我们基于 single-spa 封装了非常多的能力,把你在构建微前端系统中遇到的一些问题,如样式隔离、沙箱、预加载等等这些你需要的能力全部内置到了 qiankun 里面,所以它是一个比较完备的微前端解决方案。

生产可用。到目前为止,已经大概有 200+ 的应用,使用 qiankun 来接入自己的微前端体系。我们在蚂蚁内外受过了大量线上系统的考验,所以它是一个值得信赖的生产可用的解决方案。

qiankun 名字由来

很多人可能会好奇 qiankun 这个名字是怎么来的。实际上源自于这句话:小世界有大乾坤。我们希望在微前端这个小世界里面,通过 qiankun 这个框架鼓捣一个大乾坤

二、QIANKUN 的诞生与设计理念

在第一小节,我会跟大家聊一聊 qiankun 的诞生,关于 qiankun 是怎么来的;然后聊一聊 qiankun 的设计理念,就是 qiankun 怎么看待微前端的,qiankun 认为微前端最重要的是什么?

缘起:一次统一上云战役

qiankun 的源起,实际上是一次统一上云战役,不过这次战役具体是怎么样的并不重要。大家可以看到在这张图里看到我们这次战役所制作的控制台,我们通过红框把它划分成了好几个部分,大家可以看到最顶上的导航头、左边的菜单、右边的帮助引导以及中间的接入产品,这也就是我们子应用的主体。

控制台结构

把控制台抽象一下,它的结构就是这个样子的。

其中顶部的导航头、身份认证和左边的侧边栏、新手引导在内的所有部分加起来就是我们的主应用,或者说是框架应用。而中间那个框也就是应用主体,应用 body 部分,它就是我们接入的一系列子应用,它可能是应用 a、应用 b 、应用 c 等等一系列的应用。

我们把这一系列的应用一起集成到了一个大的控制台应用里面,这就是我们这次所做的事情。而这件事情正好是微前端技术的一个典型应用场景,所以 qiankun 就从这个项目开始了它的第一步。

我们需要一个“友好”的微前端方案

对这个项目而言,我们所需要的微前端方案,可以概括为一个 “友好” 的微前端解决方案,那怎么样算友好的微前端方案呢?我们提炼出两个要求:

  • 技术栈无关。就是说我们的微前端方案不应该限制技术栈,我们不应该要求说我们的子应用是 React 技术栈、Vue 技术栈或者说 Angular 技术栈。除了不应该限制技术栈,我们需要解除应用之间的一些隐性依赖,因为有的时候虽然我们没有限制应用的技术栈,但是我们的应用之间很可能有一些耦合,这些耦合发生在很多方面,我们需要消灭这些耦合,才能做到技术栈无关。
  • 接入简单,用起来就像 iframe 一样。大家知道 iframe 使用是非常简单的,我只要建一个 iframe 标签,把我的页面嵌进去就可以了。如果我们的微前端方案能够做到和 iframe 一样简单,我们就可以尽可能的避免旧应用改造。大家看到在我们之前的那次战役中,也就是我们缘起里,我们需要把非常多的应用接入到框架应用、接入到控制台里,这就涉及到大量的应用改造,而我们希望把应用改造的工作量降到最低,不然的话我们肯定非常疲惫。

技术栈无关

这也正是 qiankun 所认为的微前端的核心价值。后面 qiankun 面临的很多技术选择和最终的实现方式,都是出于技术栈无关的出发点的。当我们思考:“在很多的解决方案中,哪个方案被 qiankun 最后所选用”的时候,我们会想哪个方案是最技术栈无关的,最技术栈无关的方案,往往就是 qiankun 最后所选择的方案。

“技术栈无关”为什么重要

这里举一个例子说明,假如我们要做一个统一控制台,我们不妨就把控制台叫做 ABC,然后控制台需要接入三个不同的项目:项目 A 是一个月前新建的,还处在积极迭代中。项目 B 可能是一年前建的,现在已经缺乏维护。当然最难的可能是项目 C,它可能是一个的三年前项目,现在已经无人维护了。

我列出这几个项目的技术栈,大家会发现它们之间有很大的不同,可能项目 A 现在用着最新的 React 版本,用着最新的技术栈,甚至超前的用了 Webpack5 作为打包工具;与此同时,项目 B 可能就是大家一年前的主流技术选型,而项目 C 已经是非常旧的技术栈了。在这种情况下,如果我们微前端方案是技术栈相关的,那就势必得把项目 B 做升级,得把项目 C 做改造,而这样的成本很多时候是我们在做 ABC 这个项目的时候无法接受的。再者随着时间的正常推移,项目 B 也会变成无人维护的状态,项目 A 技术栈也终归会陈旧。

所以只有做到技术栈无关,才能保证在过了很久之后,我们的统一控制台 ABC,还是能够安稳的继续维护下去,还是能够安稳的接入新的项目。

玉伯有一段话是这么点评微前端的:微前端的前提还是得有主体应用,然后才有微组件或微应用,解决的是可控体系下前端协同开发问题。这里开发问题有两部分:一部分是空间分离带来的协作,另一部分是时间延续带来的升级维护。空间分离带来的协作,需要微前端方案能够提供独立开发、独立部署的特性,来处理协作问题。而时间带来的延续其实是需要我们做到技术栈无关,做到随着时间的推移,当我们技术栈陈旧的时候,还是能够正常的接入我们的框架应用。

“技术栈无关”的价值

可能大家都比较熟悉阿里使命:让天下没有难做的生意。而技术栈无关的价值,也正是 qiankun 口号:让天下没有短命的控制台。

  • 我们不限制接入前端的技术栈,做到接入范围广。
  • 我们能够做到向后兼容,能兼容年久的应用。
  • 在这个技术栈无关的架构下,我们也能做到向前兼容,这个架构是稳定的、面向未来的。

三、QIANKUN 的技术实现与选择

简单的讲了一下 qiankun 所坚持的理念之后,我们接着来聊一聊 qiankun 具体的技术实现和最终选择使用什么方案来实现微前端。

微前端框架面临的两大共性问题

实际上所有的微前端框架都面临这两大共性问题。当你解决了这两大问题之后,你的微前端框架的运行时,就已经基本可用了。

  • 问题一是应用的加载与切换。包括路由的处理、应用加载的处理和应用入口的选择。
  • 问题二是应用的隔离与通信。这是应用已经加载之后面临的问题,它们包括 JS 的隔离(也就是副作用的隔离)、样式的隔离、也包括父子应用和子子应用之间的通信问题。

应用路由与 Future State

首先我们来看应用路由的问题。在微前端体系结构下,路由的划分往往是如图这个样子的,这也是一种比较简单的方案。

我们主应用加载了应用 A 和应用 B。这个时候对于主应用来讲,我就有两个路由 /a/*/b/* 。在路由 A 下我会加载应用 A,在另一个路由 B 下加载应用 B。

那当我在路由 /b/list 下重刷页面的时候会发生什么过程?实际上我需要先加载我的主应用,我的主应用检测到这是一个 /b/ 打头的路由,于是它知道我应该去加载应用 B,随后去加载了应用 B。到了此时应用 B 接管了路由,它发现后面的路由是 /list ,于是它显示出 /list 的正确页面,总体上就是这么一个过程。

如果你没有做一些处理的话,在最早加载主应用的时候,就会面临 404 和路由报错,因为这个时候应用 B 的路由系统并没有加载进来,你并不知道 /list 需要显示什么。这实际上是懒加载就会面临的问题。早年 Angular 社区把这个问题叫做 Future State。要解决这个问题,比较简单的方式就是我们去劫持一下路由系统,做一些改造,同样的,通过借助像 react-router 之类的路由库,你也可以选用它的动态路由方案,这些都是可以的。

社区已有的成熟方案

在 qiankun 这里,我们就直接选用了社区成熟的方案 Single-SPA。Single-SPA 已经劫持的路由,帮我们做好了加载这件事情,也帮我们做好了路由切换这件事情,在这个方面我们就没有自己造轮子了。

应用接入:协议接入

同时由于我们使用了 Single-SPA,它顺便帮我们解决另一个问题:就是应用接入的问题。

什么样的一个应用能够成为子应用,能够接入到我们的框架应用里?由于我们需要技术栈无关,所以我们希望接入是一个 协议接入。只要你的应用实现了 bootstrapmountunmount 三个生命周期钩子,有这三个函数导出,我们的框架应用就可以知道如何加载这个子应用

这三个钩子也正好是子应用的生命周期钩子。当子应用第一次挂载的时候,我们会执行 bootstrap 做一些初始化,然后执行 mount 将它挂载。如果你是一个 React 技术栈的子应用,你可能就在 mount 里面写 ReactDOM.render ,把你的 ReactNode 挂载到真实的节点上,把应用渲染出来。当你应用切换走的时候,我们会执行 unmount 把应用卸载掉,当它再次回来的时候(典型场景:你从应用 A 跳到应用 B,过了一会儿又跳回了应用 A),这个时候我们是不需要重新执行一次所有的生命周期钩子的,我们不需要从 bootstrap 开始,我们会直接从 mount 阶段继续,这就也做到了应用的缓存。

App Entry 抉择

在这个方面,qiankun 还面临着另一些选择,其中一个就是 App Entry 选择,也就是如何设计子应用的加载入口,在这个问题上,我们有两个地方需要面临抉择:一个是什么时候去组合,另一个是加载子应用的入口是什么。

组合时机选择

在组合时机的选择上,我们有两个选择:第一个是在构建时,把主子应用打包在一起,着实际上就是一种多包的方案。这个方案它的好处是构建的时候可以做公共依赖的提取,但是它的缺点在于我们把主子应用构建方案和工具都耦合在一起了,这非常不灵活地,这样也没办法做到动态加载。所以在绝大部分情况下,我们都会选择运行时去组合,就是运行的时候才去动态的加载子应用,把它加载、渲染到框架应用里。

应用入口选择:HTML Entry

那我们子应用的入口又如何选择?qiankun 在这里选择的是 HTML,就是以 HTML 作为入口。

大家看了刚才的分享,其实已经清楚了:加载子应用用的时候,我们实际上是需要提供一份资源列表,在这份资源列表里,我们可能列出了这个子应用使用了哪些 JS,有哪些 CSS。

但是 qiankun 的第一选择其实是 HTML 入口,就是提供一份 HTML 文件。因为这份 HTML 中其实包含了子应用的所有信息。它包含网页的结构,包含了一些元信息。大家可以看到在这份 HTML 里我们有 CSS、JS 链接、有应用要挂载的根路由 root 的 DOM。这些信息是非常全面的,比单纯你拿 JS 和 CSS 组成一份资源列表作为入口,要清晰和完整得多。同时 HTML Entry 这样的设计,也使得我们在接入一些老旧应用的时候,更加简单。

应用入口选择

这里做一个简单的对比,用了 HTML Entry 可以把子应用和主应用更加的解耦了。但是如果你是选择资源列表或者 JS 作为子应用的入口,那么子应用挂载的时候,DOM 节点往往需要和主应用作一个约定,这就产生了一定程度的耦合。

应用隔离:JS沙箱

实际上刚才那些抉择完了之后,尤其是当我们借用了 Single-SPA 能力之后,我们已经基本解决了应用的加载与切换。我们接下来要解决的另一块事情是应用的隔离和通信。

首当其冲就是应用的隔离问题,隔离问题最开始我们就是要做 JS 的隔离。在这个问题上,有的时候你不隔离其实也可以运行的,只不过不隔离,直接裸用 Single-SPA 的话,一旦应用之间的发生了冲突,你的应用很可能就跑不下去了,所以 JS 沙箱大部分情况是必要的。

再 qiankun 沙箱的实现里,我们会有两个环境:一个代表的是外部的部分,就是我们的全局环境 Global Env,指的是你框架应用所运行的全局环境。而子应用加载的时候,实际上是应该跑在一个内部的沙箱环境里面,就是这张图上所表示的 Render Env。

沙箱实现思路有两条:其中最经典的实践思路其实是快照沙箱

快照沙箱就是在应用沙箱挂载和卸载的时候记录快照,在应用切换的时候依据快照恢复环境,

当我子应用加载、启动了之后,此时的环境其实就是 Render Environment,是内部沙箱环境里,这个时候我记录一下当时的快照状态。而在我最后子应用 unmount 的时候,我把当前的环境和记录的快照进行一个对比,把它恢复回原来的全局状态。这就是说当我应用挂载了又卸载了,这个过程走了一遍之后,我当前整个 Windows 运行环境恢复成原来的样子,应用内部所做的修改,在它卸载的时候就会被恢复,这是快照沙箱思路。

举个例子,假如我们在 A 应用运行时,追加了一个全局变量,我们说 window.a = 123 ,这个时候 window.a 就变成了 123 ,但是在应用 A 卸载之后,快照还原, window.a 会被重新删除,你在全局环境中并不会继续看到 a 变量

快照怎么打?其实也有两种思路:

一种是直接用 windows diff。把当前的环境和原来的环境做一个比较,我们跑两个循环,把两个环境作一次比较,然后去全量地恢复回原来的环境。

另一种思路其实是借助 ES6 的 proxy 就是代理。通过劫持 window ,我们可以劫持到子应用对全局环境的一些修改。当子应用往 window 上挂东西、修改东西和删除东西的时候,我们可以把这个操作记录下来。当我们恢复回外面的全局环境的时候,我们只需要反向执行之前的操作即可。比如我们在沙箱内部设了一个新的变量 window.a = 123 。那在离开的时候,我们只需要把 a 变量删了即可。

快照沙箱这个思路也正是 qiankun1.0 所使用的思路,它相对完善,但是缺点在于无法支持多个实例,也就是说我两个沙箱不可能同时激活,我不能同时挂载两个应用,不然的话这两个沙箱之间会打架,导致错误。

所以说我们把目光又投向了另一条思路,我们让子应用里面的环境和外面的环境完全隔离。就如图所示,我们的 A 应用就活在 A 应用的沙箱里面,B 应用就活在 B 应用的沙箱里面,两者之间要不发生干扰,这个沙箱的实现思路其实也是通过 ES6 的 proxy,也通过代理特性实现的。

应用隔离:样式隔离

无论是刚才的快照沙箱还是另外的代理沙箱,其实都可以解决 JS 之间的副作用冲突。解决完 JS 之后,我们接下来解决的是 CSS 之间的冲突。

在微前端框架里所面临的样式冲突器就两种:一种是主子应用样式冲突,你的主应用和你的子应用两者之间样式会发生冲突,另一种是子应用之间样式冲突,当你挂载了应用 A 又挂载了应用 B 的时候,这两个应用是平级的,它们之间样式也会发生冲突。

样式隔离:Dynamic Stylesheet

qiankun 所做的第一件事情其实是动态样式表。当你从子应用 A 切换到子应用 B 的时候,这个时候需要把子应用的样式表 A 的样式给删除,把子应用 B 的样式表给挂载。这样就避免了子应用 A 的样式和子应用 B 的样式同时存在于这个项目中,就做到了最基本的隔离。当你从应用 A 切到应用 B 的时候,你的样式也会自然的从应用 A 的样式切换到应用 B 的样式,我们会自动的帮你做应用样式的删除和加载。当然这样做只仅仅能够保证你在单应用模式下(就是同时只能有一个应用活跃的情况下)保证子应用和子应用之间的样式不会冲突。

当然动态样式表实现之后,我们还是没有解决主应用和主应用之间的样式冲突。实际上这个问题最好的手段还是通过一些工程化的手段来解,比如说 BEM,就是说大家约定一下,你应用 A 样式就统一加一个 a- 的前缀,应用 B 样式就统一加一个 b- 的前缀,你的框架应用也统一加个前缀。大家通过一些约定(比如约定大家都加上一个应用名的前缀)来避免冲突,这是非常有效的一个方案。尤其是主子应用之间的冲突,大部分情况下你只要保证主应用的样式做好改造,保证主应用的样式是很具象的规则,不会跟子应用冲突,那主子应用之间的冲突其实也解决了。不过这种方案终归是依赖约定,往往容易出纰漏。

样式隔离:工程化手段

当前 css module 其实非常成熟一种做法,就是通过编译生成不冲突的选择器名。你只要把你想要避免冲突的应用,通过 css module (在构建工具里加一些 css 预处理器即可实现)就能很简单的做到。css module 构建打包之后,应用之间的选择器名就不同了,也就不会相互冲突了。

css-in-js 也是一种流行的方案,通过这种方式编码的样式也不会冲突,这几个方案实现起来都不复杂,而且都非常行之有效。所以绝大部分情况下,大家手动用工程化手段处理一下主子应用之间的样式冲突,就可以解决掉样式隔离的问题。

样式隔离方案:Shadow DOM

当然来到 qiankun2.0 之后,我们追加了一个新的选项,叫作严格样式隔离,不知道大家有没有使用过。

其实严格样是隔离代表 Shadow DOM。Shadow DOM 是可以真正的做到 CSS 之间完全隔离的,在 Shadow Boundary 这个阴影边界阻隔之下,主应用的样式和子应用的样式可以完完全全的切分开来。

但是绝大部分情况下,你还是不能无脑的开启严格样式隔离的。原因之前的同学也已经提到过一些了,比如说你在使用一些弹窗组件的时候(弹窗很多情况下都是默认添加到了 document.body )这个时候它就跳过了阴影边界,跑到了主应用里面,样式就丢了。又比方说你子应用使用的是 React 技术栈,而 React 事件代理其实是挂在 document 上的,它也会出一些问题。所以实践里当你开启 Shadow DOM 之后,当你的子应用可能会遇到一些奇怪的错误,这些错误需要你一一的去手动修复,这是比较累的一个过程。

我们提供了 Shadow DOM 这么一种样式隔离方式。但是实际使用中还是工程化的手段最为可靠、最为简单。当然在允许的情况下,大家还是可以去尝试开启严格样式隔离,毕竟这才是真正的隔离。

样式隔离 RFC:runtime css transformer

qiankun 还收到过一个提案,让我们可以动态运行时地去改变 css。

如图,比如说原来子应用里面的样式是这个样子,那转换之后,我们可以把它前面加一个限定,我们规定只有在 data-qiankun-app1 这个子应用里面(这个 div 就是包裹子应用的最外层的容器), .main 这条样式才能真正的生效。通过这样一个运行时的转换,我们也能够达到样式隔离的目的。当然这个方案的问题在于这个转换不是那么好做,首先我们增加了一定的运行时开销,其次对于一些媒体查询,对于一些动画很可能会出一些意料之外的情况。这个 RFC 至今至今没有合并,不知道大家对此有什么看法?欢迎来到 PR 下发表你的见解。

在我们通过 JS 沙箱解决 JS 之间的副作用;通过不管用工程化手段也好,动态样式也好,或者说开启 Shadow DOM,解决掉 CSS 冲突之后,我们就要考虑应用之间的通信问题了。

应用通信:基于 URL

其实有一种最朴素的通讯方案,就是基于 URL。前端有一种设计叫做 URL 中心设计,就是说你的 URL 完全决定了你页面展示出来是什么样子。

假如我的应用里有一个列表,有一个分页,当你点下一页的时候,是不是就产生了一个在第二页的 query 参数?你可能会把这个参数同步到路由上,这样你把这个链接分享给别人的时候,别人就能看到跟你一样的页面。

我们其实完全可以把这种路由翻译成看作是一个函数调用,比如说这里的路由 b/function-log,query 参数 data 是 aaa ,我们可以把这个路由 URL 理解为我在调用 B 应用的 log 函数,这就像一次函数调用一样。当我们从应用 A 跳去应用 B,对应路由发生变化的时候,就是触发了一次函数调用,触发了一次通信。

所以路由实际上也有通信的功能。这种通信方式是完全解耦的,但是缺点就是比较弱。

应用通信:发布/订阅模型

另一种应用间通信的模型就是我们可以挂一个事件总线。应用之间不直接相互交互,我都统一去事件总线上注册事件、监听事件,通过这么一个发布订阅模型来做到应用之间的相互通信。

有趣的是,我们什么框架都不需要引入,什么第三方库都不需要引入,这里我们有一个天然的事件总线:window 的 CustomEvent 。我们可以在 window 上监听一个自定义事件,然后在任意地方派发一个自定义事件,我们可以天然的通过自定义事件来做到应用之间相互通信。

应用通信:基于 props

第三种方案其实是基于 props ,这也是我们比较熟悉的模式了。

大家写过 React 或 Vue 都会知道,我们在写一个 input 的时候,会把 valueonChange 两个 props 都传给了底下的输入框。这里我们也可以同样做,我们主应用是可以传递一些 props 给子用的。我们把 stateonGlobalStateChange (就是监听函数),还有我们的 onChange (就是 setGlobalState )三个都传给子应用。我们基于 props 也就可以实现一个简单的主子应用之间通信。

那当我们这样子实现了主子应用之间通信之后,我们子应用与子应用之间通信怎么做?让大家都跟主应用通信就行了。子应用和子应用之间就不要再多加一条通信链路了,我们大家都基于 props 和主应用通信,这样也能解通信问题。

应用通信

qiankun 本身在 2.0 的时候提供了最简单的基于 props 通信的 API。

在我们提供 API 之前,就有非常多的同学来问我们应该应用和应用之间怎么通信?我们当时都没有给出具体的解决方案,给出具体的 API 或者给出具体的实践和引导。实际上在你的应用需求、复杂度不同的时候,你应该相应的自己挑选自己适合的应用间通信方案。

对 qiankun 来看,qiankun 关注的是你应用和应用之间是不是技术栈无关的,也就是说应用和应用之间的耦合是不是尽可能弱的。从这个角度来讲,如果我们基于自定义事件来做通信,那是一个非常弱的耦合。我不依赖什么特殊的东西,我只是借用了浏览器原生 API,技术实现总线,当我脱离它的时候,我的应用也是能够自己独立的工作的。而如果我们约定一个 window 上的全局变量,或者说我们做了一个全局 Redux,大家都去这个数据源消费数据,这个时候这个方案就可能是一个比较强耦合的方案。

具体用什么样的通信方案,还是需要根据大家的实际情况和面临的业务场景自行决定。

qiankun 没有解答的工程与平台问题

大家可以看到 qiankun 帮你做了很多事情,但是这个事情并没有帮你一揽子全部做完,并不是用了 qiankun 之后,就完全地一劳永逸地解决了微前端的所有麻烦。#克军 在 D2 的微前端的专场分享的时候,有提到过微前端的整个大图,他把整个微前端体系分层了非常多的模块,qiankun 所帮你解决的这一块实际上是微前端的运行时容器,这是整个微前端工程化里面的一个环节。

从这个角度来讲,qiankun 不算是一个完整的微前端解决方案,而是微前端运行时容器的一个完整解决方案,当你用了 qiankun 之后,你能解决几乎所有的微前端运行时容器的问题,但是更多的一些涉及工程和平台的问题,

你的版本管控、配置下发、监控发布,安全检测、等等这些怎么做,都不是 qiankun 作为一个库所能解答的。这些问题还是得看大家的具体情况,来选择自己适合的解决方案。这也需要在微前端这方面做一些基础设施建设的投入,才能比较好的解答工程问题与平台建设问题。

四、QIANKUN 的发展与未来

聊了一下 qiankun 具体的一些技术实现的方案选择,最后一节聊一下 qiankun 的发展情况,与 qiankun 未来会做成什么样子。

qiankun 历程回顾

先做一个简单的历程回顾。

  • qiankun 是在去年 6 月份发布的 1.0 版本,那个时候全平台的官宣文章可能是你见过最完善的微前端解决方案。
  • 在去年 12 月的时候,在 D2 技术论坛上,在微前端专场里面,大家可以找到有之的演讲,标准微前端架构在蚂蚁的落地实践。
  • 今年 4 月份的时候,我们发布了 2.0 版本。在这两篇文章和演讲中,大家可以更详细的了解到 qiankun 设计的一些思考和 qiankun 的落地实践。
  • 到今天为止,qiankun 大概已经累积了 5.1k star。我们也受到了来自 Single-SPA 团队的肯定,我们也被非常多的团队,比如说像之前的飞猪团队选用为他们微前端体系中里面的一环。

微前端的两种形态

实际上在最早 qiankun 1.0 发布的时候,我们就觉得微前端是有两种形态的。

在我们缘起所解决的业务场景里面,在 qiankun 第一次出场的时解决其实是一个单实例的场景。我们控制台上同时运行的只有一个应用,我们会从应用 A 切换到应用 B,从应用 B 切换到应用 C,但我们不会同时把应用 A 和应用 B 都挂载在页面上,这是一种单实例的场景。

实际上我们觉得微前端还是有一种多实例场景。你在一个页面里完全可以挂载多个微应用,你可以同时把应用 A、应用 B、应用 C 和应用 D 合计 4 个应用全部在同一个页面里。

这个时候就面临一个问题,应用和组件有什么区别?这也很像之前的几位同学所提到的,weiget 或者微模块,因为在这种情况下子应用往往是没有自己的路由的,与路由无关,它确实在某种程度上很像一个组件,页面的这一部分是一个组件或者说是一个微应用,表现出来的差距并不大。

那怎么样说你是一个组件,又怎么样说你是一个微应用?对我们来说,我们认为能独立开发,独立部署,自己是能够独立完成一些功能的,其实就是一个微应用。它和 weiget 或者说微模块能做到的事情是类似的,两者之间并没有明确的界限,比如说你完全可以把一个组件升格为一个应用,或者把一个应用做成一个组件,这看你的具体场景和选择。

qiankun@2.x 定位转变

当我们 qiankun2.0 决定支持多应用多实例场景的时候,实际上 qiankun 的定位也在悄然发生一定的转变,这也正是 qiankun2.0,没有改特别多的 API 保持了大部分兼容兼容的,却说是一次重大的变化的原因。

我们原先是一个基于路由的微前端框架,而现在实际上可以说是一个微应用加载器。你可以用 qiankun@2.x,更灵活的加载微应用,我们提供了组件化的加载能力,用来支持做更复杂的应用编排,并且支持更多的微前端应用场景。

qiankun@2.x 加载微应用

我们给大家看一下代码:如何用 qiankun2.0 来加载一个微应用。

我们提供提供了一个新的 API loadMicroApp ,通过这个 API 可以加载一个微应用。我们可以简单的基于该 API 封装一下,封装出一个 MicroApp 的 React 组件。当我拿到 MicroApp 组件之后,我们就可以很简单的使用它。

比如说我们可以和 react-router 这样的路由库一起使用,我们可以选择在某一个路由上挂载组件,这个场景下就跟单实例的场景非常像,跟 qiankun@1.x 一样,是一个路由级别的使用场景。另外一种用法是我们是可以把它当做一个组件使用,我们可以同时在一个页面里挂载应用 A 挂载应用 B,我们可以在一个场景里挂载多个应用,这是一种组件级的使用。

那从单实例的场景转到了多实例的场景,有什么用武之地?

微应用:混合研发

有一个场景是混合研发。

现在随着前端的发展,其实很多人都在思考通过低代码提效的问题,我们已经有一些比较成熟的低代码平台了,比如说像云凤蝶,你可以靠拖拖拽拽,做出一个好用的中后台页面,也有一些配置式的平台,就是你依靠配置一些 json、配置一些数据,你就可以生成前端页面

但是与此同时,我们也存在着低代码平台无法支持的一些,只能用 ProCode 来支撑的一些场景。很可能你一个应用中同时存在着两种场景,那这个时候你就可以把他们视为是不同的两个微应用。LowCode的微应用和 ProCode 的微应用。你可以把两者同时放在一个项目里面,通过 qiankun 去加载两者来做到一种混合研发。这样你可以同时享受 NoCode 或者 LowCode 的快速开发,又可以享受 ProCode 的完整能力,一旦你发现低代码不符合你的需求的时候,你可以无缝地切换到 ProCode,留有后路。

书籍推荐

最后一个环节是向大家推荐一本书,我今天推荐的这本书是《松本行弘的程序世界》。通过这本书大家可以深入地理解程序设计背后的故事。

QA

我们的评论区非常火爆,提了非常多的问题。因为时间的关系,我们只有 4 个机会,大家可以关心一下自己的问题是不是被回答到。

请教方涣:qiankun 框架是否不关心不参与处理微应用之间可能存在的共同依赖,怎么解决公共依赖的问题?

qiankun 本身是没有帮助处理公共依赖的。这个事情上,可以通过一些构建时候的工具来解决,比如说像简单的 externals 和一些库,或者说你可以尝试 Webpack5 的联邦模块,或者说是用一些 import map 之类的特性来做这件事情。qiankun 这方面也在探索路上,包括我们也再想自己如何和 Webpack5 的联邦模块结合,我们后续可能会出一些有关这方面的实践。如果你有好的实践欢迎提出来跟大家分享。但是同时我们有另一种观点,你真的需要把这些依赖提出来吗?很多时候你的应用之间的依赖库的版本不同,这些不同的你可以认为依赖库其实也是应用的一部分,你把它提出去之后,其实也是造成了你应用之间的一些耦合。

请教方涣:是否有对于子应用服务异常时,主应用的容灾机制的推荐方法?

这个我觉得是取决于具体场景和业务诉求的。因为子应用异常:一种可能是你代码就写错了,子应用挂了。这种情况下你主应用可能只能感知到子应用出一些异常故障,你知道这个子应用挂了,你可以做一些上报,或者尝试做一些恢复。还有可能你是想做一些监控实践,你想捕获子应用里面运行时的一些错误情况,它是否发生了一些不到崩溃程度的一种报错,你希望把它记录下来。这方面其实 qiankun 本身是不关注这个的,你完全可以自己来实现这些逻辑。

请教方涣:目前 qiankun 是如何在原有的老项目中引入的?比如说主应用的路由是如何对接的?现在的样式应该是如何隔离?

你的场景应该是已经有一个应用 A,然后你想通过 qiankun 把应用 B 作为一个子应用引入到你的应用 A 中。在这个场景下,其实比较简单的方式是你在应用 A 里面,就是你的主应用里面,单独分配一个路由给应用 B。因为 qiankun 实际上是主应用加载了之后,去检查匹配子应用是否激活。如果子应用激活,我们就会把子应用挂载,然后再去把路由交给自己的子应用。所以这个场景下最简单的方式就是分配一个路由给你的子应用。

样式隔离的问题,其实刚才讲了。可以有两种方式:一种是使用一些工程化的手段,不管是约定前缀,或者说使用 css module 做一些改造都可以避免主子应用之间的样式冲突。你也可以尝试去开启严格的样式隔离,使用Shadow DOM 的方式来让子应用样式真正地做隔离,但是这个时候你的子应用可能会遇到一些新的问题需要你解决。

请教方涣:qiankun 的子应用是 jQuery 的老项目,老项目中图片的地址是相对路径,加载图片时地址的域名和端口却变成了主应用的地址,应该怎么解决?

这个问题可以到 Github 上提个 issues 帮你看一看。

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/sxmsWEq3xy8Hw-0w9cluug

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237228次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录