跳到主要内容

Single SPA

提示
  • 建议使用单个版本框架
  • 适用于跨框架 - 如果不 跨框架,建议自行封装一个简单的挂载逻辑
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/instant-test?name=@wener-dash/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

推荐设置