前言
大家好,我是海怪。了解过微前端的同学应该对 single-spa 这个框架都不陌生,但是我翻看了中文整个社区,发现太少文章是讲 single-spa Demo 实践的。
还有一些文章讲了,但是都是以晒代码为主,只讲是什么,不讲为什么。这对读者来说并不是一个很好的体验。那今天就跟大家深入分析一下 single-spa 的 React 版 Demo 吧。让读者知其然,也能知其所然。
简介
其实 single-spa 的官网上就写了非常多的 Demo 示例:
大家只关注 Actively maintained 的就好了。这里我就挑选第一个 React Microfrontends 跟大家举例说明。
架构
一点进去这个项目,发现这玩意有好几个项目:
一看这么多项目就头晕,而且这个 root-config 的 README.md 也写得云里雾里的,相信这里就能劝退一大波人。
不过呢,我把这些项目都下下来了,一共有 7 个项目:
├── api # API utils 调用函数
├── navbar # 导航条组件
├── people # people 页面组件
├── plants # plants 页面组件
├── root-config # 主应用核心项目
├── shared-dependencies # import-map json 文件
└── styleguide # Button 组件 + 全局 CSS 样式
它们的架构是这样的:
这些 “小项目” 对应的位置如下图所示:
我们可以把上面这些 “小项目”(除了 root-config 之外)归类如下:
类型 | 项目 |
---|---|
主应用 | root-config |
页面组件 | people, plants |
普通组件 | navbar |
公共套件 | api, styleguide |
JSON import-map | shared-dependencies |
这里除了 root-config 之外都是微应用,无论是页面组件,还是公共套件。 那我们现在就来过一过这些项目的内容吧。
root-config
首先来看 root-config,这个项目可以说是主应用,也可以理解为整个 App 的 “首脑”,它的工作非常纯净:
- 引入公共库、微应用的 JS
- 定义微应用的页面路由
- 加载各个微应用(页面/组件/公共函数/公共样式)
引入公共库、微应用的 JS
引入公共库、微应用的 JS 是通过 SystemJS 的 import-map 特性来实现的,比如现在有这个 import-map.json
:
{
"imports": {
"react": "https://cdn.jsdelivr.net/npm/react@17.0.1/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom@17.0.1/umd/react-dom.production.min.js",
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.8.2/lib/system/single-spa.min.js",
"@react-mf/root-config": "https://react.microfrontends.app/root-config/55aa0b39bcca3e3d0844b2c0aa2f658a2aa1b94f/react-mf-root-config.js",
"@react-mf/navbar": "https://react.microfrontends.app/navbar/c1a777c770ee187cebedd0724653c771495f2af9/react-mf-navbar.js",
"@react-mf/styleguide": "https://react.microfrontends.app/styleguide/504c8516e30274fc0e3221a719d5355b14af9500/react-mf-styleguide.js",
"@react-mf/people": "https://react.microfrontends.app/people/4d0af0a673764fa9b311f9f98163c88be9af9426/react-mf-people.js",
"@react-mf/api": "https://react.microfrontends.app/api/849cde43d1bf1a072c1b71b4de504fc7120d4629/react-mf-api.js",
"@react-mf/planets": "https://react.microfrontends.app/planets/010c38f36fc578c406f1aa44d16f6aad9062f2f2/react-mf-planets.js",
"@react-mf/things": "https://react.microfrontends.app/things/7f209a1ed9ac9690835c57a3a8eb59c17114bb1d/react-mf-things.js",
"rxjs": "https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.6.3/system/es2015/rxjs.min.js",
"rxjs/operators": "https://cdn.jsdelivr.net/npm/@esm-bundle/rxjs@6.6.3/system/es2015/rxjs-operators.min.js",
"@react-mf/api/": "https://react.microfrontends.app/api/849cde43d1bf1a072c1b71b4de504fc7120d4629/",
"@react-mf/people/": "https://react.microfrontends.app/people/4d0af0a673764fa9b311f9f98163c88be9af9426/",
"@react-mf/navbar/": "https://react.microfrontends.app/navbar/c1a777c770ee187cebedd0724653c771495f2af9/",
"@react-mf/planets/": "https://react.microfrontends.app/planets/010c38f36fc578c406f1aa44d16f6aad9062f2f2/",
"@react-mf/styleguide/": "https://react.microfrontends.app/styleguide/504c8516e30274fc0e3221a719d5355b14af9500/",
"@react-mf/root-config/": "https://react.microfrontends.app/root-config/55aa0b39bcca3e3d0844b2c0aa2f658a2aa1b94f/"
}
}
可以在 index.html
里通过 <script>
标签来引入:
<script type