微前端是一种软件架构,可以将前端应用拆解成一些更小的能够独立开发部署的微型应用,然后再将这
些微应用进行组合使其成为整体应用的架构模式。
微前端架构类似于组件架构,但不同的是,组件不能独立构建和发布,但是微前端中的应用是可以的。
微前端架构与框架无关,每个微应用都可以使用不同的框架。
使用场景:
1.拆分巨型应用,使应用变得更加可维护
2.兼容历史应用,实现增量开发
微前端实现
-
多个微应用如何组合
在微前端架构中,除了存在多个微应用以外,还存在一个容器应用,每个微应用都需要被注册到容
器应用中。
微前端中的每个应用在浏览器中都是一个独立的 JavaScript 模块,通过模块化的方式被容器应用启
动和运行。
使用模块化的方式运行应用可以防止不同的微应用在同时运行时发生冲突。 -
在微应用中如何实现路由
在微前端架构中,当路由发生变化时,容器应用首先会拦截路由的变化,根据路由匹配微前端应
用,当匹配到微应用以后,再启动微应用路由,匹配具体的页面组件。 -
微应用与微应用之间如何实现状态共享
在微应用中可以通过发布订阅模式实现状态共享,比如使用 RxJS。 -
微应用与微应用之间如何实现框架和库的共享
通过 import-map 和 webpack 中的 externals 属性。
Systemjs 模块化解决方案
在微前端架构中,微应用被打包为模块,但浏览器不支持模块化,需要使用 systemjs 实现浏览器中的模
块化。
systemjs 是一个用于实现模块化的 JavaScript 库,有属于自己的模块化规范。
在开发阶段我们可以使用 ES 模块规范,然后使用 webpack 将其转换为 systemjs 支持的模块
通过 webpack 将 react 应用打包为 systemjs 模块,在通过 systemjs 在浏览器中加载模块
微前端框架single-spa
single-spa 是一个实现微前端架构的框架
在 single-spa 框架中有三种类型的微前端应用:
1.single-spa-application / parcel:微前端架构中的微应用,可以使用 vue、react、angular 等框
架。(single-spa-application与路由关联 single-spa-parcel不与路由相关联,主要用于跨应用共享ui组件)
2.single-spa root config:创建微前端容器应用。
3.utility modules:公共模块应用,非渲染组件,用于跨应用共享 javascript 逻辑的微应用。
创建容器应用
- 安装single-spa脚手架工具:npm install create-single-spa@2.0.3 -g
- 创建微前端应用目录:mkdir spa_workspace && cd "$_"
- 创建微前端容器应用:create-single-spa
- 应用文件夹名称:container
- 应用选择 single-spa root config
- 组织名称:test
组织名称可以理解为团队名称,微前端架构允许多团队共同开发应用,组织名称可以标识应用由哪个团队开发。
应用名称的命名规则为 @组织名称/应用名称,比如 @test/todos
4.启动应用 npm start
- 访问应用 localhost:9000
root-config.js
import { registerApplication, start } from "single-spa"
/*注册微前端应用 1. name: 字符串类型, 微前端应用名称 "@组织名称/应用名称"
2. app: 函数类型, 返回 Promise, 通过 systemjs 引用打包好的微前端应用模块代码 (umd)
3. activeWhen: 路由匹配时激活应用
*/
registerApplication({
name: "@single-spa/welcome",
app: () => System.import( "https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js" ),
activeWhen: ["/"]
})
// start 方法必须在 single spa 的配置文件中调用
// 在调用 start 之前, 应用会被加载, 但不会初始化, 挂载或卸载.
start({
// 是否可以通过 history.pushState() 和 history.replaceState() 更改触发 single-spa 路由
// true 不允许 false 允许
urlRerouteOnly: true
})
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Root Config</title>
<!--
Remove this if you only support browsers that support async/await.
This is needed by babel to share largeish helper code for compiling async/await in older
browsers. More information at https://github.com/single-spa/create-single-spa/issues/112
-->
<script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.7/runtime.min.js"></script>
<!--
This CSP allows any SSL-enabled host and for arbitrary eval(), but you should limit these directives further to increase your app's security.
Learn more about CSP policies at https://content-security-policy.com/#directive
-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https: localhost:*; script-src 'unsafe-inline' 'unsafe-eval' https: localhost:*; connect-src https: localhost:* ws://localhost:*; style-src 'unsafe-inline' https:; object-src 'none';">
<meta name="importmap-type" content="systemjs-importmap" />
<!-- If you wish to turn off import-map-overrides for specific environments (prod), uncomment the line below -->
<!-- More info at https://github.com/joeldenning/import-map-overrides/blob/master/docs/configuration.md#domain-list -->
<!-- <meta name="import-map-overrides-domains" content="denylist:prod.example.com" /> -->
<!-- Shared dependencies go into this import map. Your shared dependencies must be of one of the following formats:
1. System.register (preferred when possible) - https://github.com/systemjs/systemjs/blob/master/docs/system-register.md
2. UMD - https://github.com/umdjs/umd
3. Global variable
More information about shared dependencies can be found at https://single-spa.js.org/docs/recommended-setup#sharing-with-import-maps.
-->
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js"
}
}
</script>
<link rel="preload" href="https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js" as="script">
<!-- Add your organization's prod import map URL to this script's src -->
<!-- <script type="systemjs-importmap" src="/importmap.json"></script> -->
<% if (isLocal) { %>
<script type="systemjs-importmap">
{
"imports": {
"@study/root-config": "//localhost:9000/study-root-config.js"
}
}
</script>
<% } %>
<!--
If you need to support Angular applications, uncomment the script tag below to ensure only one instance of ZoneJS is loaded
Learn more about why at https://single-spa.js.org/docs/ecosystem-angular/#zonejs
-->
<!-- <script src="https://cdn.jsdelivr.net/npm/zone.js@0.11.3/dist/zone.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.2.0/dist/import-map-overrides.js"></script>
<% if (isLocal) { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.js"></script>
<% } else { %>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.min.js"></script>
<% } %>
</head>
<body>
<main></main>
<!-- 导入微前端容器应用 -->
<script>
System.import('@study/root-config');
</script>
<!--import-map-overrides 可以覆盖导入映射 当前项目中用于配合 single-spa Inspector 调试工具使用. 可以手动覆盖项目中的 JavaScript 模块加载地址, 用于调试. -->
<import-map-overrides-full show-when-local-storage="devtools" dev-libs></import-map-overrides-full>
</body>
</html>