共计 4151 个字符,预计需要花费 11 分钟才能阅读完成。
我最早是在 2016 年接触到微前端的,过后社区里以介绍概念居多,在实际计划,尤其是在业务落地方面利用的比拟少。起初,随着计划逐步成熟,社区里对于微前端的探讨越来越多。
明天,咱们先从概念、关键技术原理层面来对微前端进行具体阐明。后续会有专门的文章来介绍微前端的实践经验。
什么是微前端
微前端的概念来源于微服务,其整体的架构思路是将前端利用分解成一些更小、更简略的可能独立开发、测试、部署的利用,之后将这些利用组成整体,在用户看来依然是内聚的单个产品,用户体验是统一的。
从概念上看,微前端架构由主利用和子利用两个局部组成,子利用负责具体的业务实现,主利用负责子利用的加载和卸载,即生命周期治理。
从概念延长开来,咱们不难发现,应用微前端,能够取得如下收益:
- 子利用独立开发、部署,技术栈无关
拆分当前,子利用领有独立的代码仓库、独立的开发部署流程,甚至能够自在的应用任何技术栈进行开发。由此,咱们能够在组织架构层面造成不同的团队来负责不同的业务模块,各个团队之间绝对独立自主,互不烦扰。 - 增量降级,多技术体系共存
对于很多大型的组织,他们的产品通常都经验了长期的迭代,性能简单,同时技术栈通常也比拟老旧。应用微前端当前,借助于独立的子利用,能够取得增量降级的能力。既能够实现新性能应用新的技术栈,同时与老技术栈共存。又能够对老性能进行逐渐迭代降级,小步快跑。 - 产品层面的自由组合
借助于微前端,咱们能够对各个子利用自在的进行高低线。换句话说,咱们能够依据产品须要,自在的将不同的子利用组合成新的产品。
技术剖析
在微前端架构下,有主利用和子利用两个根本角色。子利用负责具体的业务逻辑,主利用负责调度子利用。思考到主利用的特殊性性能,为了保障整个框架的可用性,通常主利用不负责任何业务逻辑。
路由与子利用加载
因为主利用负责调度子利用,因而主利用须要具备路由治理和资源加载能力。所谓路由治理,就是主利用中须要保护一个路由表,当页面路由发生变化的时候,主利用能够晓得以后须要启动哪个子利用。这个路由表能够是动静的,也能够是动态的。
晓得启动哪个子利用之后,主利用就须要加载子利用的资源。通常有两种资源加载形式:
- JS Entry。
通常将子利用的所有资源打包成一个入口文件,在 single-spa 的很多样例中就应用了这种形式。 - HTML Entry。
子利用构建输入的是一个 HTML 文件,主利用通过加载这个 HTML 文件实现子利用的加载。
相比较而言,JS Entry 的计划限度更多一些,比方要求将图片、款式等所有资源打包成一个 JS Bundle,构建的包太大,也无奈利用浏览器的并行加载能力。同时,子利用还须要与主利用约定好要挂载的节点,主利用要提前初始化好,或者子利用自行创立,防止挂载失败或者抵触。
HTML Entry 很好的防止了 JS Entry 的问题。实质上,HTML 文件充当的是利用动态资源表的角色。主利用加载了 HTML 当前,浏览器会自行下载子利用的各种资源。同时,因为构建产物是 HTML,子利用具备与独立利用开发时统一的开发体验。当然,HTML Entry 也存在毛病,比方要多一次申请,先加载了 HTML 能力晓得加载哪些资源。
在加载完子利用的资源当前,主利用就能够启动子利用,实现页面渲染了。那么该如何启动子利用呢?主利用须要与子利用之前制订一个接口标准,比方在 single-spa 中就指定了 bootstrap
、mount
、unmount
和 unload
四个办法。子利用裸露这四个办法给主利用,主利用通过这四个办法来治理子利用的申明周期。
隔离
解决了路由和子利用加载的问题,实践上说咱们曾经实现了微前端的外围能力。然而,在理论的工程实际中,咱们还须要解决很多的细节问题。其中最大的一部分就是如何做好子利用间的隔离。比方如何防止子利用间的款式抵触。
抛开现有的微前端计划,如果让咱们从头开始实现一套微前端架构,将独立开发部署的各个子利用组合起来。置信大多数同学都会首先想到 iframe。其实咱们就能够通过 iframe 来了解微前端架构中的种种技术细节。
iframe 自带的款式、环境隔离机制使得它具备人造的沙箱能力,然而 iframe 也有很多人造的缺点,比方事件无奈冒泡到顶层,路由跳转无奈与主利用同步,与主利用通信简单繁琐等。
咱们能够参考 iframe 的设计思维,来设计如何对子利用进行隔离。一个传统的 iframe 具备四层能力:文档的加载能力、HTML 的渲染能力、独立执行 JavaScript 的能力、隔离款式的能力。
文档的加载能力和 HTML 的渲染能力在后面主利用加载子利用资源的时候,咱们曾经做了阐明。
咱们当初来说说如何实现独立的 JavaScript 运行环境和款式隔离。
沙箱(sandbox)
通常,子利用在运行期间会有一些污染性的副作用产生,比方全局变量、全局事件、定时器、网络申请、localStorage、全局 Style 款式、全局 DOM 元素等。为了保障利用可能稳固的运行且互不影响,须要提供平安的运行环境,可能无效地隔离、收集、革除利用在运行期间所产生的副作用,也就是沙箱的设计指标。
有两种沙箱的设计思路。一种是快照模式,另一种是虚拟机(virtual machine)模式。
快照模式
所谓快照模式,就是将启动子利用之前,对以后环境打一个快照,子利用退出之后,再从新加载这个快照来复原环境。
在实现层面,咱们能够针对每一种副作用设计一个 save
办法保留以后状态,在设计一个 load
办法来加载保留的状态。
框照模式的缺点是对操作的程序要求十分严格,当页面有多个子利用的时候,快照沙箱就会有多个实例存在,此时不同程序的 save
和 load
会产生问题。
VM(虚拟机)模式
虚拟机想必大家都据说过,是一种计算机系统的仿真器,通过软件模仿具备残缺硬件零碎性能的、运行在一个齐全隔离环境中的残缺计算机系统。应用虚拟机就跟应用实在的计算机一样。
NodeJS 中也提供了 VM 模块,不过不同于传统的 VM,它并不具备虚拟机那么强的隔离性,并没有模仿残缺的硬件零碎,仅仅将指定代码搁置了特定的上下文中编译并执行,无奈用来执行不可信起源的代码。
上面的代码展现了 NodeJS 的 VM 模块的根本用法:
const vm = require('vm');
const x = 1;
const context = {x: 2};
vm.createContext(context); // 将 context 对象高低文化
const code = 'x += 40; var y = 17;';
// `x` and `y` 在上下文中是全局变量
// 初始状态下, x 的值为 2,因为 context.x 得值是 2
vm.runInContext(code, context);
console.log(context.x); // 42
console.log(context.y); // 17
console.log(x); // 1; y 为未定义
参考 NodeJS 中 VM 模块的设计,以及 JavaScript 词法作用域的个性,能够设计出 VM 沙箱,不过与传统的 VM 差别也同样存在,它并不能执行不可信的代码,因为它的隔离能力仅限于将其运行在一个指定的上下文环境中。
let code = `(function(document, window){/* 代码逻辑 */})`
(new Function('document', 'window', code)(fakeDocument, fakeWindow))
针对后面提到的子利用运行产生的全局变量、全局事件等种种副作用,咱们能够针对性的做解决,提供新的执行上下文。比方,用新的 window 对象用来隔离全局变量,用新的 document 来收集创立的 dom 对象,style 款式,script 标签等。全局事件、localStorage 等都能够一一进行解决。
上面借助于 Proxy
,咱们能够轻松的对以后的执行上下文进行劫持,创立新的执行上下文。上面的代码展现了如何劫持 window 对象。
const varBox = {};
const fakeWindow = new Proxy(window, {get(target, key) {return varBox[key] || window[key];
},
set(target, key, value) {varBox[key] = value;
return true;
}
});
const code = `(function(window) {
window.a = '111';
console.log(window.a);
})`;
const fn = new Function('window', code);
fn(fakeWindow);
VM 模式的沙箱,能够无效的解决子利用之间、奴才利用之间各种副作用的无效隔离问题。qiankun 的沙箱模式就是 VM 模式。
款式隔离
尽管说,VM 模式的沙箱能够收集子利用运行过程中产生的款式,而后在子利用卸载的时候去除款式,然而思考到子利用的 dom 构造最终还是要并入到主利用的 dom 树中去,VM 沙箱无奈防止主利用的款式烦扰到子利用的款式的问题。
这时候,咱们就须要借助于一些其余伎俩,比方在奴才利用中都应用 css modules 来缩小款式抵触。
Shadow Dom
如果不思考兼容性,Shadow Dom 是子利用款式隔离的一个绝佳抉择。
咱们把子利用放到 Shadow Dom 中,能够原生实现子利用间的款式隔离。然而 Shadow Dom 自身也有诸多限度,很多依赖库还不反对 Shadow Dom。比方埋点检测,事件处理等。
咱们这里仅是将 Shadow Dom 作为补充技术计划来进行阐明。
qiankun 官网也将在将来的版本中逐渐弃用 Shadow Dom。
须要留神的问题
技术畛域有句话叫“没有永远的银弹”。本文结尾咱们介绍了应用微前端能够取得的很多收益,当初咱们来讲讲微前端带来的问题。
- 整个产品的复杂度从代码转移到了基础设施
咱们须要有一套利用注册、治理的零碎,并要和现有的利用公布流程对接。同时还要围绕微前端计划构建一整套的根底工具,比方开发调试工具,埋点监控零碎等。 - 减少了学习和了解老本
子利用或多或少要理解一些微前端计划的技术原理,能力带来更好的开发和产品体验。
常见面试知识点、技术解决方案、教程,都能够扫码关注公众号“众里千寻”获取,或者来这里 https://everfind.github.io。