微前端: single-spa
一个前端微应用的框架介绍与使用笔记
single-spa
是一个用于实现前端微应用的框架。
- single-spa-application/parcel: 微前端应用,可以使用 vue/react/angular 等框架
- single-spa root config: 创建微应用的容器应用(container)
- utilty modules: 公共模块应用,非渲染组件,用于跨应用共享的 js 逻辑微应用(module)
安装
类似于 react-cra 一样的 cli 工具。
yarn add global create-single-spa
最终的项目结构如下
- container: 主应用
- lagou: 不依赖任何框架的子应用
- lerna 管理我们的应用
- 最终的 repo: https://github.com/aric-tpls/micro-single-spa
创建容器应用
- create-single-spa
- 选择 single-spa-root config 这个
- 项目名称: container
调试工具
开发的时候,可以把 registerApp 的地址,替换成本地,方便开发。
chrome调试工具: single-spa inspector
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides@2.2.0/dist/import-map-overrides.js"></script>
<import-map-overrides-full show-when-local-storage="devtools" dev-libs></import-map-overrides-full>
开发与生产
- isLocal: 区分环境
- 加载不同的 js 文件
<% 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>
<% } %>
注册一个应用
- name: 唯一名称
- app: 反应一个应用,得是一个 Promise
- activeWhen: 路由
- 这个是在 container 里注册应用
registerApplication({
name: "@single-spa/welcome",
app: () =>
System.import(
"https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js"
),
activeWhen: ["/"],
});
启动应用
urlRerouteOnly
是否可以用 history 相关的触发路由有关
start({
urlRerouteOnly: true,
});
创建一个微应用(子)
- 创建目录 lagou
- 创建 package.json
- 另外:没有用他的脚手架
yarn add @babel/core single-spa webpack webpack-cli webpack-dev-server webpack-merge webpack-config-single-spa
目录结构
.
├── package.json
├── src
│ └── jswork-lagou.js
├── webpack.config.js
└── yarn.lock
wepback.config.js
const spaDefaults = require("webpack-config-single-spa");
const { merge } = require("webpack-merge");
module.exports = () => {
const defaultConfig = spaDefaults({
orgName: "jswork",
projectName: "lagou",
});
return merge(defaultConfig, {
devServer: {
port: 9001,
},
});
};
子应用注册 importmap
这个就是我们的不基于任何框架的微应用
"@jswork/lagou":"http://localhost:9001/jswork-lagou.js"
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js",
"@jswork/lagou":"http://localhost:9001/jswork-lagou.js"
}
}
</script>
子应用入口
src/jswork-lagou.js (
scope - projectName
这里需要与webpack一至)
// filename 必须与 scope-name 一致
// bootstrap mount unmout
let lagouEl = null;
export async function bootstrap() {
console.log("react app bootstraped");
}
export async function mount() {
console.log("props from main framework");
lagouEl = document.createElement("div");
lagouEl.id = "lagou";
lagouEl.innerHTML = "<h1>lagou works!</h1>";
document.body.appendChild(lagouEl);
}
export async function unmount() {
console.log("react app unmount");
document.body.removeChild(lagouEl);
}
路由冲突
在 container 应用注册的时候处理 loc.pathname 为精确匹配,即可
(loc) => loc.pathname === "/"
- container 应用: /
- 子应用: /lagou
import { registerApplication, start } from "single-spa";
registerApplication(
"@single-spa/welcome",
() =>
System.import(
"https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js"
),
(loc) => loc.pathname === "/"
);
registerApplication({
name: "@jswork/lagou",
app: () => System.import("@jswork/lagou"),
activeWhen: ["/lagou"],
});
start({
urlRerouteOnly: true,
});