Single SPA

Tips#

Topic应用/applicationparcel工具/utility
路由无路由无路由
API定义式 API声明式 API
渲染 UI
生命周期single-spa 管理自行管理
使用场景核心构建组件多个框架的时候需要公共逻辑

create-single-spa#

# http://localhost:9000
# 默认 importmap 是在 html 中
# 开启 importmap 开发工具
# localStorage.setItem("devtools", true);
yarn create single-spa --framework react --moduleType root-config --dir root
yarn create single-spa --framework react --dir dash
# localhost:8500
# http://single-spa-playground.org/playground/[email protected]/spa&url=8500
# 默认位置 http://localhost:8500/<OrgName>-<ProjectName>.js
# 例如 http://localhost:8500/wener-spa-dash.js
yarn start --port 8500
yarn create single-spa --framework react --moduleType util-module --dir utils \
--packageManager yarn --typescript
# react + ts 使用的配置
# yarn add --dev webpack-config-single-spa-react-ts webpack-merge

root-config#

  • 单个 html
  • 由服务端生成即可

index#

<!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>
<!-- 用于不支持 async/await 的浏览器 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/runtime.min.js"></script> -->
<!--
This CSP allows any SSL-enabled host, 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' https: localhost:*; connect-src https: localhost:* ws://localhost:*; style-src 'unsafe-inline' https:; object-src 'none';">
<meta name="importmap-type" content="systemjs-importmap" />
<!-- 全局样式 -->
<link href="https://unpkg.com/antd/dist/antd.min.css" rel="stylesheet"/>
<!-- 公共依赖
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
参考 https://single-spa.js.org/docs/recommended-setup#sharing-with-import-maps.
-->
<script type="systemjs-importmap">
{
"imports": {
"single-spa": "https://cdn.jsdelivr.net/npm/[email protected]/lib/system/single-spa.min.js",
"react": "https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js",
"antd": "https://unpkg.com/[email protected]/dist/antd-with-locales.min.js"
}
}
</script>
<!-- 使用外部导入映射 -->
<!-- <script type="systemjs-importmap" src="/importmap.json"></script> -->
<!-- 本地开发地址 -->
<script type="systemjs-importmap">
{
"imports": {
"@wener-spa/root-config": "//localhost:9000/wener-spa-root-config.js",
"@wener-spa/dash": "//localhost:8081/wener-spa-dash.js"
}
}
</script>
<!-- 本地开发使用 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/import-map-overrides.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/system.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/extras/amd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/extras/named-exports.js"></script>
<!-- 生产使用
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/import-map-overrides.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/system.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/extras/amd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/extras/named-exports.min.js"></script>
-->
</head>
<body>
<main></main>
<script>
// 启动该模块
System.import('@wener-spa/root-config');
</script>
<!-- 开发工具 - 测试 importmap -->
<import-map-overrides-full show-when-local-storage="devtools" dev-libs></import-map-overrides-full>
</body>
</html>

config#

import { registerApplication, start } from "single-spa";
// 注册应用
registerApplication({
name: "@wener-spa/dash",
app: () => System.import("@wener-spa/dash"),
// 前缀匹配的激活路径
activeWhen: ["/"]
});
// 启动应用
start({
urlRerouteOnly: true,
});

parcel#

entry#

import React from 'react';
import ReactDOM from 'react-dom';
// 挂载根组件
import rootComponent from './path-to-root-component.js';
// Note that SingleSpaContext is a [email protected] (if available) context that provides the singleSpa props
import singleSpaReact, {SingleSpaContext} from 'single-spa-react';
const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent,
errorBoundary(err, info, props) {
// https://reactjs.org/docs/error-boundaries.html
return (
<div>This renders when a catastrophic error occurs</div>
);
},
});
export const bootstrap = reactLifecycles.bootstrap;
export const mount = reactLifecycles.mount;
export const unmount = reactLifecycles.unmount;

webpack#

const webpackMerge = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react-ts");
module.exports = (webpackConfigEnv) => {
const defaultConfig = singleSpaDefaults({
orgName: "wener-spa",
projectName: "dash",
webpackConfigEnv,
});
const config = webpackMerge.smart(defaultConfig, {
// modify the webpack config however you'd like to by adding to this object
});
// 添加额外的外部依赖 - 默认会添加 react、react-dom 等
config.externals.push('antd')
return config
};

utility#

  • 没有 entry

推荐设置#