该文章将讲述业界各大知名IT企业使用的微前端解决方案,以及其带来的利弊之处,因为那些弊端,使得我们团队自己探究了一套目前认为最好的微前端解决方案。通过本文,可以快速帮您理清楚微前端方案的利弊,从而做出有利于您团队的更好更明智的选择。
一、写在前面
在之前的文章中,我们已经深入剖析了微前端究竟是什么,可以带来什么收益,现在让我们复习一下微前端的概念:
代码语言:javascript复制Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently.
中文释义:
可以由多个团队独立开发的现代web应用程序的技术、策略和方案。
本文则是在此基础上对现有的微前端解决方案进行对比总结,废话少说,让我们开始今天的课题。
二、现有微前端解决方案
查找了大量的资料后,我总结了以下主流的能够真正实现微前端概念的解决方案,如有遗漏,欢迎小伙伴们补充~
1、iframe
众所周知,iframe
是html
提供的标签,能加载其他web应用的内容,并且它能兼容所有的浏览器,因此,你可以用它来加载任何你想要加载的web应用。
iframe最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。读到这时,相信小伙伴们跟我一样,觉得iframe与微前端概念中提到的独立开发
、独立维护
、相互隔离
非常的吻合,有种直接上ifame就完事儿了的想法,但为何它到现在也不是微前端主要的实现方式呢,后来有幸拜读了qiankun技术圆桌
中一篇关于微前端Why Not Iframe的思考,总结的很到位,现复述其中的一段描述
iframe虽然基本能做到微前端所要做的所有事情,但它的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来开发体验、产品体验的问题。
以下是我对该文中总结部分的总结:
- 不是单页应用,会导致浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- 弹框类的功能无法应用到整个大应用中,只能在对应的窗口内展示。
- 由于可能应用间不是在相同的域内,主应用的 cookie 要透传到根域名都不同的子应用中才能实现免登录效果。
- 每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程,占用大量资源的同时也在极大地消耗资源。
- iframe的特性导致搜索引擎无法获取到其中的内容,进而无法实现应用的seo
我猜,以上原因便是iframe
没能作为官方微前端方案的原因吧。
2、Web Components
或许很多小伙伴对Web Components
不是很了解,它是由google
推出的浏览器的原生组件,MDN
对Web Components的定义是这样的:
作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的HTML(以及相关的样式和脚本),有时您不得不写代码来呈现自定义UI控件,并且如果您不小心的话,多次使用它们会使您的页面变得一团糟。
Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
它的三项主要技术是指:
- Custom elements(自定义元素):一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
- Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
- HTML templates(HTML模板):
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
通过以上描述,再结合微前端的概念,我们来看看Web Components
是如何做到微前端:
- 技术栈无关:
Web Components
是浏览器原生组件,那即是在任何框架中都可以使用。 - 独立开发:使用
Web Components
开发的应用无需与其他应用间产生任何关联。 - 应用间隔离:
Shadow DOM
的特性,各个引入的微应用间可以达到相互隔离的效果。
综上所述,Web Components
是有能力以组件加载的方式将微应用整合在一起作为微前端的一种手段,但不幸的是,Web Components
是浏览器的新特性,所以它的兼容性不是很好,如果有兼容性要求的项目还是无法使用,具体请查看can i use。
3、ESM
ESM
是ES Module
的缩写,是Ecma script 2015
中提出的一种前端模块化手段,那么,它又是如何做到微前端的呢?其实,微前端无外乎三大特性,无技术栈限制
、应用单独开发
,多应用整合
,只要抓住了这三个特性,那就不难理解ESM
如何做的了:
- 无技术栈限制:
ESM
加载的只是js内容,无论哪个框架,最终都要编译成js,因此,无论哪种框架,ESM
都能加载。 - 应用单独开发:ESM只是js的一种规范,不会影响应用的开发模式。
- 多应用整合:只要将微应用以
ESM
的方式暴露出来,就能正常加载。 - 远程加载模块:
ESM
能够直接请求cdn
资源,这是它与生俱来的能力。
ESM
是能做到微前端的核心思想,但是它也存在着兼容性这一大弊端,尽管ESM
已经很优秀了,但是大部分老版的浏览器仍然无法直接使用,这也是babel等编译工具出现的原因,幸运的是,他可以通过webpack
、rollup
、esbuild
、snowpack
等编译工具成为兼容性的代码。
4、qiankun
在微前端界,qiankun
算得上是最早成型且知名度最广的框架了,它是真正意义上的单页微前端框架,那么qiankun
到底有哪些特点呢,在其官网中我找到了如下概括:
- 基于
single-spa
封装,提供了更加开箱即用的 API - 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架
- HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单
- 样式隔离,确保微应用之间样式互相不干扰
- JS 沙箱,确保微应用之间 全局变量/事件 不冲突
- 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度
- umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统除了最后一点拓展以外,微前端想要达到的效果都已经达到。
5、EMP
EMP是由欢聚时代业务中台自主研发的最年轻的单页微前端解决方案
那么,他有哪些特性呢,下面我们一起看看:
- 基于
Webpack5
的新特性Module Federation
实现,达到第三方依赖共享,减少不必要的代码引入的目的,什么是Module Federation这里就不再赘述。 - 每个微应用独立部署运行,并通过cdn的方式引入主程序中,因此只需要部署一次,便可以提供给任何基于
Module Federation
的应用使用。并且此部分代码是远程引入,无需参与应用的打包。 - 动态更新微应用:
EMP
是通过cdn
加载微应用,因此每个微应用中的代码有变动时,无需重新打包发布新的整合应用便能加载到最新的微应用。 - 去中心化,每个微应用间都可以引入其他的微应用,无中心应用的概念。
- 跨技术栈组件式调用,提供了在主应用框架中可以调用其他框架组件的能力(目前已支持互相调用的框架及使用方式请参阅官方文档)。
- 按需加载,开发者可以选择只加载微应用中需要的部分,而不是强制只能将整个应用全部加载。
- 应用间通信,每一个应用都可以进行状态共享,就像在使用npm模块进行开发一样便捷。
- 生成对应技术栈模板,它能像
cerate-react-app
一样,也能像create-vue-app
一样,通过指令一键搭建好开发环境,减少开发者的负担。 - 远程拉取ts声明文件,
emp-cli
中内置了拉取远程应用中代码声明文件的能力,让使用ts开发的开发者不再为代码报错而烦恼。
细心的小伙伴应该发现,EMP
除了具备微前端的能力外,还实现了跨应用状态共享、跨框架组件调用的能力,这是现有框架所不具备的优秀特性!
三. 总结
又到了下课的最后五分钟时间,一起来看看今天的分享都有哪些关键的知识需要掌握:
1. 现有微前端解决方案:
- iframe
- Web Components
- ESM
- qiankun
- EMP
2. 各解决方案的利弊:
iframe
可以直接加载其他应用,但无法做到单页导致许多功能无法正常在主应用中展示。web Components
及ESM
是浏览器提供给开发者的能力,能在单页中实现微前端,不过后者需要做好代码隔离,并且他们都是浏览器的新特性,都存在兼容性问题,微前端方面的探索也不成熟,只能作为面向未来的微前端手段。qiankun
基本上可以称为单页版的iframe,具有沙箱隔离及资源预加载的特点,几乎无可挑剔。EMP
作为最年轻微前端解决方案,也是吸收了许多web优秀特性才诞生的,它在实现微前端的基础上,扩充了跨应用状态共享、跨框架组件调用、远程拉取ts声明文件、动态更新微应用等能力。同时,细心的小伙伴应该已经发现,EMP
能做到第三方依赖的共享,使代码尽可能地重复利用,减少加载的内容。