微前端概述

百家 作者:51CTO技术栈 2022-06-20 19:25:04

本文由浅到深地对微前端进行了概括性介绍,读者可以了解到微前端的概念、微前端的特点与价值、微前端的实现方案、一个微前端框架应具备的功能,以及微前端的适用场景。读者可以多关注下本文提到的各个开源的优秀的微前端实现方案,通过对比及借鉴来实现一套适合自身业务的微前端方案。



PART 01

微前端是什么




传统的分而治之的策略已经无法应对现代 Web 应用的复杂性,因此衍生出了微前端这样一种新的架构模式,与后端微服务相同,它同样是延续了分而治之的设计模式,不过却以全新的方法来实现。微前端是一种由独立交付的多个前端应用组成整体的架构风格,将前端应用分解成一些更小、更简单的,能够独立开发、测试、部署的应用,并且在用户看来仍然是内聚的单个产品。





PART 02

微前端的特点与价值




2.1 独立与自治


独立开发、独立部署、独立自治代码库,从而可提升构建效率、改善交付效率。


2.2 技术栈无限定


技术栈自主性有利于多个不同技术栈的团队协同合作,技术栈的可平滑迁移也对旧有业务的不断迭代和技术升级带来较大的便利性。


2.3 颗粒化解耦与可组合


在大型的前端工程中,对于颗粒化解耦有很高的要求,常基于不同维度划分,例如业务类型颗粒化、技术服务类型颗粒化等等。各个微前端颗粒的可组合性又让多个可交付系列产品有很好的颗粒一致性和整体定制差异化,并能极大减少业务重复开发的资源浪费。




PART 03

微前端实现方案




3.1 iframe


从浏览器原生的方案来说,iframe 不从体验角度上来看几乎是最可靠的微前端方案了,主应用通过 iframe 来加载子应用,iframe 自带的样式、环境隔离机制使得它具备天然的沙盒机制,但也是由于它的隔离性导致其并不适合作为加载子应用的加载器,iframe 的特性不仅会导致用户体验的下降,也会在研发在日常工作中造成较多困扰,以下总结了 iframe 作为子应用的一些劣势:


  • 使用 iframe 会大幅增加内存和计算资源,因为 iframe 内所承载的页面需要一个全新并且完整的文档环境;

  • 由于 iframe 与上层应用并非同一个文档上下文,所以:



  • 无法预加载缓存 iframe 内容;

  • 无法共享基础库进一步减少包体积;

  • 事件通信繁琐且限制多。


3.2 Module Federation/EMP(构建时确定依赖关系)


3.2.1 Module Federation:


多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署。


Module Federation提供了能在当前应用中远程加载其它服务器上应用的能力,基于此可以实现一个去中心化的应用部署群,每个应用是单独部署在各自的服务器,每个应用都可以引用其它应用,也能被其它应用所引用。通过new ModuleFederationPlugin配置被远程引用时的路径(exposes)、远程引用的应用、与其它应用之间可以共享的第三方依赖(shared)等。


由上可知,通过shared以及exposes可以将多个应用引入同一应用中进行管理,从而实现微前端架构。


3.2.2 EMP


EMP是一个基于Webpack5Module Federation搭建的微前端解决方案。通过cdn加载微应用,可以动态更新微应用,微应用只需要部署一次便可以提供给任何基于Module Federation的应用使用。每个微应用间都可以引入其它的微应用,无中心应用的概念。可以选择只加载微应用中需要的部分。每一个应用都可以进行状态共享。


3.3  single-spa/qiankun/icestark/garfish(运行时确定依赖关系)


1.single-spa


Single-spa是一个用于前端微服务化的JavaScript前端解决方案,实现了路由劫持和应用加载(通过监听url change事件,在路由变化时匹配到子应用并进行渲染),其本身没有处理样式隔离和js执行隔离。其实,single-spa是一个子应用加载器与状态机的结合体。推荐阅读微前端框架之single-spa 从入门到精通


2.qiankun


qiankun是一个基于single-spa的微前端实现库。HTML entry接入方式。在主应用中注册微应用,当微应用信息注册完之后,一旦浏览器的url发生变化,便会自动触发qiankun的匹配逻辑,所有activeRule规则匹配上的微应用就会被插入到指定的container中,同时依次调用微应用暴露出的生命周期钩子(bootstrap、mount、unmount)。如果微应用不是直接跟路由关联的,也可以使用手动加载微应用的方式。


3.icestark


icestark通过微应用入口字段的配置进行应用的渲染,支持多种入口配置形式:url、entry(即html url)、entryContent(即html内容,用于解决html url不支持前端跨域访问的情况)、render/component(仅支持使用React的主应用)。为了能够让icestark响应页面路由的变化并对相应的微应用进行加载,icestark对两类路由事件进行了劫持,即history API的popstate和hashChange,以及window的路由事件pushState和replaceState。支持微模块,一种没有路由、粒度更小的挂件,通常是一个模块或页面,跟页面路由无关,可以随处挂载。


4.Garfish


当执行注册子应用相关信息并执行Garfish.run后,此时Garfish框架将会启动路由劫持能力,当浏览器的地址发生变化时,Garfish框架内部便会立即触发匹配逻辑,当应用符合匹配逻辑时将会自动将应用挂载至页面中(也可以手动通过某些事件触发来挂载),并依次触发子应用加载、渲染过程中的生命周期。支持HTML entry 和 JS entry。


3.4 Fronts(渐进式)


Fronts 是一个基于 Webpack 的 Module Federation API 设计的渐进式微前端框架。它强调颗粒间的去中心化依赖管理,并支持多种运行模式来满足不同的微前端架构需求。这个渐进式是指,如果前端工程的各个颗粒并不都支持Module Federation,它依然能以微前端的形式良好地运行,也能自由选择所需要的运行模式;并随着项目升级,可以逐一升级到支持 Module Federation,并最终根据实际需要建立和开启微前端版本控制系统。


3.5 Web Components


浏览器的原生组件,由三项主要技术组成,可以创建可重用的定制元素,不必担心代码冲突。


  • Custom elements(自定义元素):一组JavaScript API,允许定义custom elements及其行为,然后可以在页面中使用。

  • Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其它部分发生冲突。

  • HTML templates(HTML模板):使用<template>和<slot>元素可以编写不在呈现页面中显示的标记模板,然后它们可以作为自定义元素结构的基础被多次重用。


可以看出来,Web Components是有能力以组件加载的方式将微应用整合在一起实现微前端架构的一种手段:


  • 技术栈无关:Web Components是浏览器原生组件,即可以在任何JS框架中使用。

  • 独立开发:使用Web Components开发的应用无需依赖其它应用。

  • 应用间隔离:Shadow DOM的特性,使得引入的微应用间可以达到相互隔离的效果。


当然,Web Components也有浏览器兼容性的限制。


micro-app:借鉴了Web Components的思想,通过Custom elements结合自定义的Shadow DOM,将微前端框架封装成一个类Web Component组件,从而实现基座应用对子应用的组件化渲染。




PART 04

微前端框架需要实现的功能




4.1应用加载


根据注册的子应用,通过给定的url,加载约定格式的子应用入口,并挂载到给定位置。入口方式通常有两种:HTML和JS,JS做入口更纯粹,HTML做入口更易于旧项目改造。此外,提供预加载功能也很有必要,预加载是指在应用尚未渲染时提前加载资源并缓存,从而提升首屏渲染速度。


4.2生命周期


加载、挂载、更新、卸载等。


4.3路由同步


子应用的路由切换时,同步更新url;url改变时,同步更新子应用。


4.4应用通信


各个应用间可以便捷通信,局部通信、全局通信。


4.5沙箱隔离


4.5.1 JS隔离


  • Snapshot。子应用挂载时,先对全局window变量打个快照放闭包里,再把全局window交给子应用,在子应用卸载时通过快照恢复全局window变量。这种方式实际上并没有形成“隔离”,只是防止多个子应用互相“污染”,并且多个子应用之间不能共存,因为全局window只有一个,快照只有一个。

  • Sandbox

    • Wasm VM。重新编译一个Wasm(WebAssembly)的JS解释器放在浏览器中,把子应用直接放进这个VM中执行,这种方式隔离非常严格,通信开销非常大。with()+new Function(code)+Proxy。with语法用于改变作用域链,当访问全局变量时进行拦截,不对window进行查找。new Function()将一段字符串解析成一段JS脚本并执行,只能访问全局作用域。Proxy提供的是with和new Function闭包中用到的充当window作用域的对象,通过白名单属性限制能访问真正window上的部分元素,同时对document、history、location进行劫持限制等,从而组成沙箱环境。


4.5.2 CSS隔离


命名约定、自动Scope、Shadow DOM、自动卸载、弹窗遮罩。


4.6异常处理


对各种异常进行统一处理。




PART 05

微前端的适用场景




概括来讲,微前端主要解决了两个问题:


  • 应用随着迭代变得越来越大,最终难以维护。

  • 相对独立的几个应用需要融合为一个应用。


任何一个方案都有优缺点,也不可能适用于所有场景,是否适合的评判标准是收益要大于损失。


关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接