前端面试-微前端
date
Aug 10, 2023
slug
frontend_interview_micro_frontend
status
Published
tags
前端
interview
summary
微前端
type
Post
微前端实现的方式有 iframe, web components, javascript模块加载器。
最常用的是javascript模块加载器(SystemJS),可以让我们在运行时动态的加载和卸载模块,从而实现微前端应用程序的动态部署和更新。
工作原理 (qiankun,跟single-spa应该差不多)
- 应用加载:通过动态创建script标签的方式加载子应用的入口文件。加载完成后,会执行子应用里定义的生命周期函数
- 生命周期管理:qiankun需要每个子应用都要暴露出bootstrap,mount和unmount三个生命周期函数。bootstrap在应用加载时被调用,mount在应用启动时被调用,unmount在应用卸载是被调用。
- 沙箱隔离:qiankun通过proxy对象创建了一个javascript沙箱,用于隔离子应用的全局变量,防止子应用之间的全局变量污染。
- 样式隔离:qiankun通过动态添加和移除样式标签的方式实现了样式隔离。当子应用启动时,会动态添加子应用的样式,当子应用卸载时,会动态卸载子应用的样式标签
- 全局通信:qiankun提供了一个全局的通信机制,允许子应用之间进行通信
bootstrap:这个生命周期函数会在应用第一次挂载前执行一次。就是说在子应用的代码加载完成以后,页面渲染之前执行。
mount:当主应用判定需要激活这个子应用时会调用这个生命周期函数。在这个函数中实现子应用的挂载、页面渲染等逻辑。这个函数也只会执行一次
unmount:当主应用判定需要卸载这个子应用时会调用这个生命周期函数。在这个函数中实现组件卸载、清理事件监听等逻辑。
single-spa中做模块导入大量的用到了SystemJS,主要是为了解决模块化导出的一些问题
qiankun vs iframe
在选择
qiankun 和 iframe 时,需要根据具体的使用场景来决定。如果你的子应用是基于现代前端框架(如 React、Vue、Angular 等)开发的单页应用,那么 qiankun 可能是一个更好的选择,因为它可以提供更好的用户体验和更高的开发效率。如果你的子应用是基于 jQuery 或者其他传统技术开发的多页应用,或者你需要在子应用中加载一些第三方的页面,那么 iframe 可能是一个更好的选择,因为它可以提供更强的隔离性。不同前端框架的代码如何复用
Web Components的三驾马车,即Custom elements、Shadow DOM和HTML templates。
1)Custom elements
允许用户自定义一组JS API,完成UI和逻辑行为,这与主流框架中的组件自定义元素的概念是一致的。
2)Shadow DOM
自定义元素将生成一棵与主文档隔离的“影子”DOM树,而Shadow DOM的作用就是将这棵树附加到宿主元素中,保证了元素功能的私有和独立性。
3)HTML templates
提供了 template 和 slot 功能,用于自定义元素结构和模板复用。
1)优点
- 框架0耦合
- 浏览器原生支持
- 主流框架支持
2)缺点
- 兼容性
目前原生浏览器中只有Chrome和Firfox提供了全面的支持,IE和Edge等并不友好。庆幸的是,官方polyfill可以提供IE11以及Edge和其他大部分浏览器的支持,这对B端产品来说,已经够了。
- 数据绑定
- 状态管理
- 开发成本
Web Components目前并没有数据绑定和状态管理,导致我们无法像其他主流框架那样方便地更新视图、使用redux等进行数据状态管理。
是可以使用某个主流框架进行组件核心逻辑的开发,以Web Components作为桥梁,进行其他框架的复用手段。 比如把react组件用direflow构建成web components, 然后在angular里复用
隔离
single-spa
子应用样式的加载和卸载。single-spa 提供了 single-spa-css 这个工具来实现。
css-module实现子应用之间样式隔离
single-spa 采用了类似于快照模式的JS隔离机制,通过 single-spa-leaked-globals 来实现。
所谓快照模式,就是将启动子应用之前,对当前环境打一个快照,子应用退出之后,再重新加载这个快照来恢复环境。
在实现层面,我们可以针对每一种副作用设计一个
save 方法保存当前状态,在设计一个 load 方法来加载保存的状态。框照模式的缺陷是对操作的顺序要求非常严格,当页面有多个子应用的时候,快照沙箱就会有多个实例存在,此时不同顺序的
save 和 load 会产生问题。css公共依赖
这个问题和上面提到的处理“公共依赖”的问题是差不多的。官方给出两个建议:
- 将公共的 CSS 放到 importmap 里,也可以理解为在 index.html 里直接加个 link 获取 antd 的 CSS 完事
- 将所有的公共的 UI 库都 import 到 utility 里,将 antd 所有内容都 export,再把 utility 包放到 importmap 里,然后
import { Button } from '@your-org-name/utility';去引入里面的组件
其实上面两个方法都大同小异,思路都是在主应用一波引入,只是一个统一引入CSS,另一个统一引入 UI 库。
qiankun
shadow-dom
css module
静态资源文件(尽量别提)
qiankun 方案
优点
降低了应用改造的成本,通过html entry的方式引入子应用;
提供了完备的沙箱方案,包括js沙箱和css沙箱;
支持静态资源预加载能力。
缺点
适配成本较高,包括工程化、生命周期、静态资源路径、路由等方面的适配;
css沙箱的严格隔离可能引发问题,js沙箱在某些场景下执行性能下降;
无法同时激活多个子应用,不支持子应用保活;
不支持vite等esmodule脚本运行。
静态资源路径要拼上父应用domain路径
应用复用依赖
- 子项目之间的依赖复用可以通过保证依赖的URL一致来实现。如果多个子项目都使用同一份CDN文件,加载时会先从缓存读取,避免重复加载。
- 在使用
webpack构建的子项目中,要实现复用公共依赖,需要配置webpack的externals,将公共依赖指定为外部依赖,不打包进子项目的代码中。
父子应用通信
single-spa中:
- custom events
- 后端数据通信
- localstorage
- window全局挂载