微前端方向的思考和选择
背景
由于我们的项目是自行编辑的BI图表,为了减少对BI图表的重复开发,所以我们要把自己的项目做成微应用以方便其它项目组快速拿来使用。
其实微前端这个概念一直耳熟能详,对于个人开发者来说,还是很有必要亲自接触并开发一下相关的项目的。
各个微前端原理
- HTML 内联框架元素 (
<iframe>
) 表示嵌套的browsing context。它能够将另一个 HTML 页面嵌入到当前页面中。
-
Custom elements :一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。
-
Shadow DOM :一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
-
HTML templates:
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
-
single-spa(qiankun)的路由劫持方案
-
Webpack5 Module Federation
-
每个构建都充当一个容器,也可将其他构建作为容器。通过这种方式,每个构建都能够通过从对应容器中加载模块来访问其他容器暴露出来的模块。
-
共享模块是指既可重写的又可作为向嵌套容器提供重写的模块。它们通常指向每个构建中的相同模块,例如相同的库。
经过
我们项目在改造微前端的过程中,使用了很多方案,来分享一下项目改造的过程。
由于我们项目是作为微应用暴露出去的,别人接入我们项目不能对自身项目做过大的改造,所以我们项目的微前端改造优先考虑是尽量减少的对主应用的入侵性(所以以下只会说各个微前端的缺点,目的是为了适配自身需求,当然提到的各个框架都是非常优秀的)
Webpack5 Module Federation(emp)
由于当时我们的项目是使用vue-cli@4脚手架搭建的,需要升级到webpack5才能Module Federation,所以就借此机会升级到了webapck5
如果想要Module Federation实现微前端,最大的缺点是要主应用也要升级成webpack5才能使用,所以说这个升级更多的是为了项目加快构建速度,并不能实际上用于推广微前端进程。
qiankun
一说到微前端,相信大部分人都是会先想到qiankun,毕竟它推出的时间比较早,所以我一开始也是尝试着使用qiankun。
- 根据官网的介绍,一步步修改项目(这个修改参考官方文档即可)
- 将所有的图片资源修改成相对路径,举例:
- <img :src="`${$publicPath}/imgs/logo2.png`" class="logo-icon" />
+ <img :src="require('public/imgs/logo2.png')" class="logo-icon" />
- 通过内联方式手动引入Keypress监听键盘事件,使用window.keypress会导致微应用加载报错
<script src="./js/keypress-2.1.5.min.js"></script>
this.keyListener = window.keypress
修改后:
const keypress = await import("@/assets/js/keypress-2.1.5.min.js");
this.keyListener = new keypress.Listener();
由于qiankun是基于路由url进行劫持的,所以在进行初始化微应用的时候,比较麻烦的一点是需要对路由匹配逻辑进行修改,如下官方demo:
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react app', // app name registered
entry: '//localhost:7100',
container: '#yourContainer',
activeRule: '/yourActiveRule',
},
{
name: 'vue app',
entry: { scripts: ['//localhost:7100/main.js'] },
container: '#yourContainer2',
activeRule: '/yourActiveRule2',
},
]);
start();
由于这个路由匹配逻辑的存在,导致了我们要对主应用进行大幅度代码修改,所以我们暂时先放弃了qiankun这个方案。
Vue.component + git subtree + webpack打包
当时在2022年头的时候,micro-app和wujie还没有推出,而且我们有这方面需求的项目,基本都是使用vue2框架,所以这个方案就被选用了。
这个方案的实现原理是,在微应用中完成组件注册注册,并通过webpack打包项目,然后通过git subtree上传构建包,主应用通过git subtree更新组件包,再进行重新发版。
这个方案的缺点是,只能在vue2项目之间,并且每次微应用修改后主应用都要重新走一遍发版流程,所以在micro-app和wujie出来之后,我们马上就进行了更换。
micro-app
虽然说我们使用Vue.component + git subtree + webpack打包方案能解决当时的需求,但随着时间的推移,我们已经有vue3和React的项目想要接入我们的项目作为他们的微应用。刚好京东官方推出了micro-app的时候,就感觉能解决这个问题了,而且当初在改造成qiankun微前端的时候,其实已经把很多工作做好了,所以我很快就启动了基于micro-app的改造。
在接入的过程当中,遇到了一个问题,我们主应用在加载微前端的时候,报了这个错误:
这个错误最后找出来了,是因为我们的index.html没有把body做成闭合标签(神奇的是这个bug一直没有被发现):
<html>
<!-- 后面发现是缺少了<body> -->
<body>
<script>
(function () {}(
……
))
</script>
</body>
</html>
wujie
其实在腾讯的wujie推出来的时候,我们的微前端已经改造了很多次,基本就能做到无缝衔接到wujie方案。在看了官方demo到代码后,wujie在适配vite方面更加简便,所以最后也改成了wujie方案了。
总结
优先考虑的方案是qiankun、micro-app、wujie,因为它们加载微应用的方式都是通过http的方式,可以实现主应用和微应用之间的解耦。
如果优先考虑性能问题,可以选择micro-app,因为wujie是Web Components + iframe的方案实现,iframe的加载会耗费更多的性能(这个结论还没有准确的数据支撑,只是从理论角度分析)
如果是优先考虑兼容性问题就选择micro-app和wujie,因为qiankun改造成本相对来说更大,并且不支持vite
等 ESM
脚本运行。
个人强烈推荐选择wujie,因为wujie使用iframe来解决js隔离和路由问题,特别是在路由问题上基本不需要再额外的适配工作。
转载自:https://juejin.cn/post/7188568313470353468