Single-SPA 学习总结

一、什么是 Single-SPA

Single-SPA 是微前端领域的"鼻祖"框架,它是一个用于前端微服务化的 JavaScript 框架,允许你在同一个页面中使用多个框架(React、Vue、Angular 等),而不需要刷新页面。

核心定位

  • JS Entry 方案:通过加载子应用的 JS 入口文件来集成
  • 路由驱动:基于 URL 变化自动激活/卸载子应用
  • 框架无关:支持任意前端框架,只要导出生命周期函数

二、核心概念

1. 三种模块类型

类型 说明 生命周期 使用场景
Application 有 UI 的微前端应用 bootstrap → mount → unmount 独立页面/功能模块
Parcel 可复用的 UI 组件 手动挂载/卸载 跨应用共享组件
Utility 无 UI 的共享模块 工具函数、API 封装、状态管理

2. 生命周期函数

每个 Application 必须导出三个生命周期函数:

javascript 复制代码
// 应用首次加载时调用(只执行一次)
export async function bootstrap(props) {
  console.log("应用初始化");
}

// 路由匹配时调用(每次激活都执行)
export async function mount(props) {
  // 渲染 DOM
  ReactDOM.createRoot(props.container).render(<App />);
}

// 路由离开时调用
export async function unmount(props) {
  // 清理 DOM 和副作用
  root.unmount();
}

3. 生命周期流程

makefile 复制代码
首次加载:  load → bootstrap → mount
路由切换:  unmount → mount (另一个应用)
完全卸载:  unmount → unload (可选)

三、核心原理

1. 路由劫持

Single-SPA 通过劫持浏览器的路由事件来实现应用切换:

javascript 复制代码
// 劫持 history API
const originalPushState = window.history.pushState;
window.history.pushState = function (...args) {
  originalPushState.apply(this, args);
  // 触发应用切换逻辑
  reroute();
};

// 监听 popstate 事件
window.addEventListener("popstate", reroute);

2. 应用状态机

每个应用都有状态流转:

markdown 复制代码
NOT_LOADED → LOADING_SOURCE_CODE → NOT_BOOTSTRAPPED
    → BOOTSTRAPPING → NOT_MOUNTED → MOUNTING → MOUNTED
    → UNMOUNTING → NOT_MOUNTED

3. 应用加载与执行

javascript 复制代码
// 注册应用
registerApplication({
  name: "app1",
  app: () => import("./app1/main.js"), // 动态导入
  activeWhen: "/app1", // 激活条件
  customProps: { authToken: "xxx" }, // 传递给子应用的 props
});

// 启动
start();

4. Import Map 模块解析

Single-SPA 推荐使用 Import Map 来管理模块 URL:

html 复制代码
<script type="importmap">
  {
    "imports": {
      "react": "https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js",
      "@myorg/app1": "https://mycdn.com/app1/main.js"
    }
  }
</script>

浏览器会根据 Import Map 解析 import '@myorg/app1' 到实际 URL。


四、Single-SPA 生态

1. 核心包

包名 作用
single-spa 核心库,提供注册、启动、生命周期管理
single-spa-layout 声明式布局引擎,用 HTML 定义路由和布局

2. 框架适配器

适配器 框架
single-spa-react React
single-spa-vue Vue 2/3
single-spa-angular Angular
single-spa-svelte Svelte

3. 开发工具

工具 作用
import-map-overrides 运行时覆盖 Import Map,方便本地调试
import-map-injector 支持从远程 URL 加载 Import Map
create-single-spa 官方脚手架 CLI

五、项目结构

推荐的目录结构

bash 复制代码
micro-frontends/
├── root-config/              # 基座应用
│   ├── src/
│   │   ├── index.ejs         # HTML 模板 + 布局配置
│   │   └── root-config.js    # 应用注册和启动
│   └── webpack.config.js
│
├── navbar/                   # 导航栏应用(始终显示)
├── app1/                     # 业务应用 1
├── app2/                     # 业务应用 2
│
├── shared/                   # 共享模块
│   ├── api/                  # API 封装
│   └── styleguide/           # 公共样式/组件
│
└── shared-dependencies/      # Import Map 配置
    └── importmap.json

六、创建 Single-SPA 项目

方式一:使用官方脚手架 create-single-spa(推荐)

bash 复制代码
# 全局安装
npm install -g create-single-spa

# 或使用 npx
npx create-single-spa

脚手架会引导你选择:

  1. 项目类型

    • single-spa root config - 基座应用
    • single-spa application / parcel - 子应用
    • in-browser utility module - 工具模块
  2. 框架:React / Vue / Angular / Svelte / None

  3. 包管理器:npm / yarn / pnpm

创建基座应用

bash 复制代码
npx create-single-spa --moduleType root-config
# 选择组织名称,如 @myorg

创建 React 子应用

bash 复制代码
npx create-single-spa --moduleType app-parcel --framework react

创建 Vue 子应用

bash 复制代码
npx create-single-spa --moduleType app-parcel --framework vue

方式二:手动配置

如果需要更多控制,可以手动配置:

1. 基座应用 (root-config)

bash 复制代码
mkdir root-config && cd root-config
npm init -y
npm install single-spa single-spa-layout
npm install -D webpack webpack-cli webpack-dev-server html-webpack-plugin
javascript 复制代码
// src/root-config.js
import { registerApplication, start } from "single-spa";
import {
  constructApplications,
  constructRoutes,
  constructLayoutEngine,
} from "single-spa-layout";

const routes = constructRoutes(document.querySelector("#single-spa-layout"));
const applications = constructApplications({
  routes,
  loadApp: ({ name }) => import(/* webpackIgnore: true */ name),
});

applications.forEach(registerApplication);
constructLayoutEngine({ routes, applications }).activate();
start();

2. React 子应用

bash 复制代码
npm install single-spa-react react react-dom
javascript 复制代码
// src/main.js
import React from "react";
import ReactDOMClient from "react-dom/client";
import singleSpaReact from "single-spa-react";
import App from "./App";

const lifecycles = singleSpaReact({
  React,
  ReactDOMClient,
  rootComponent: App,
  errorBoundary(err, info, props) {
    return <div>Error</div>;
  },
});

export const { bootstrap, mount, unmount } = lifecycles;

3. Vue 子应用

bash 复制代码
npm install single-spa-vue vue
javascript 复制代码
// src/main.js
import { createApp, h } from "vue";
import singleSpaVue from "single-spa-vue";
import App from "./App.vue";

const vueLifecycles = singleSpaVue({
  createApp,
  appOptions: {
    render() {
      return h(App);
    },
  },
});

export const { bootstrap, mount, unmount } = vueLifecycles;

方式三:参考官方示例仓库

示例 地址 说明
React 示例 github.com/react-micro... 完整的 React 微前端示例
Vue 示例 github.com/vue-microfr... 完整的 Vue 微前端示例
混合框架示例 github.com/polyglot-mi... React + Vue + Angular 混合

在线演示:


七、开发调试技巧

1. 使用 import-map-overrides

javascript 复制代码
// 在浏览器控制台启用开发工具
localStorage.setItem("devtools", true);

// 刷新页面后,右下角会出现开发工具面板
// 可以将任意模块指向本地开发服务器

2. 本地开发流程

bash 复制代码
# 1. 启动本地子应用
cd my-app && npm start --port 9001

# 2. 访问线上/本地基座
# 3. 使用 import-map-overrides 将 @myorg/my-app 指向 localhost:9001

3. 独立运行子应用

子应用应该能够独立运行,方便开发调试:

javascript 复制代码
// 判断是否在 single-spa 环境中
if (!window.singleSpaNavigate) {
  // 独立运行
  ReactDOM.createRoot(document.getElementById("root")).render(<App />);
}

八、Single-SPA vs 其他方案

特性 single-spa qiankun micro-app
Entry 类型 JS Entry HTML Entry HTML Entry
沙箱隔离 ❌ 无内置 ✅ Proxy 沙箱 ✅ 沙箱隔离
样式隔离 ❌ 无内置 ✅ Shadow DOM / Scoped ✅ 样式隔离
老项目改造 较高 极低 极低
灵活性 ★★★★★ ★★★★ ★★★
学习曲线 较陡 中等 较平缓

选择建议

  • 选 single-spa:需要最大灵活性、深入理解微前端原理、技术能力强的团队
  • 选 qiankun:企业级项目、多历史系统接入、需要开箱即用的沙箱和隔离
  • 选 micro-app:快速上手、组件化思维、Vue 技术栈为主

九、最佳实践

1. 共享依赖

通过 Import Map 共享公共依赖,避免重复加载:

json 复制代码
{
  "imports": {
    "react": "https://cdn.jsdelivr.net/npm/react@18/...",
    "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@18/..."
  }
}

2. 样式隔离

Single-SPA 不提供内置样式隔离,需要自行处理:

  • CSS Modules
  • CSS-in-JS (styled-components, emotion)
  • BEM 命名规范
  • 添加应用前缀

3. 全局状态管理

  • 使用 Utility 模块共享状态
  • 发布订阅模式 (EventBus)
  • 通过 customProps 传递

4. 错误边界

javascript 复制代码
singleSpaReact({
  // ...
  errorBoundary(err, info, props) {
    return <ErrorPage error={err} />;
  },
});

十、学习资源

官方资源

视频教程

相关规范

相关推荐
想学后端的前端工程师2 小时前
【CSS高级技巧与动画实战指南:打造炫酷的用户体验】
前端·css·ux
_码力全开_2 小时前
第一章 html5 第一节 HTML5入门基础
前端·javascript·css·html·css3·html5
KLW752 小时前
vue 绑定动态样式
前端·javascript·vue.js
没有bug.的程序员2 小时前
微服务网关:从“必选项”到“思考题”的深度剖析
java·开发语言·网络·jvm·微服务·云原生·架构
幼稚鬼_Blog2 小时前
可拖拽悬浮按钮组件支持vue3/vue2
前端·javascript·html
没有bug.的程序员2 小时前
Sentinel 流控原理深度解析:构建高可用微服务的底层架构
java·算法·微服务·云原生·架构·sentinel·负载均衡
前端小怪兽zmy3 小时前
Vue3实现纯前端语音输入成文字显示
前端·javascript·elementui
ohyeah3 小时前
原子化 CSS 与 Fragment:现代前端开发的高效实践
前端
鱼鱼块3 小时前
告别重复传参!用柯里化提升代码优雅度
前端·javascript·面试