qiankun 微前端框架

2,057 阅读3分钟

qiankun 微前端框架

一、基础介绍

1.1 什么是 qiankun

qiankun 框架 是阿里巴巴开源的一款基于 微前端架构 的解决方案,基于 Single-SPA 的二次封装,提供了更完善的开发体验和开箱即用的功能。

1.2 应用场景

  • 大型企业级应用:需要多个团队协作开发,不同模块使用不同技术栈
  • 逐步重构:将旧系统逐步迁移到新技术栈,同时保持原有功能可用
  • 独立部署需求:子应用需要频繁更新,但主应用保持稳定

1.3 核心特性

  1. 技术栈无关:支持任意前端框架(React、Vue、Angular、jQuery 等)
  2. 独立开发部署:子应用可独立开发、独立部署、独立运行
  3. 样式隔离:确保子应用样式互不影响
  4. JS 沙箱:提供 JS 运行环境隔离
  5. 资源预加载:支持子应用资源预加载
  6. 应用通信:提供灵活的应用间通信方案

二、基本使用

2.1 主应用配置

import { registerMicroApps, start } from "qiankun";

registerMicroApps([
  {
    name: "vue-app",
    entry: "//localhost:7100",
    container: "#subapp-container",
    activeRule: "/vue",
  },
]);

start();

2.2 子应用适配

export async function mount(props) {
  ReactDOM.render(<App />, props.container);
}

export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(props.container);
}

三、核心实现原理

3.1 路由劫持

class RouterHijacker {
  constructor(apps) {
    this.apps = apps;
    this.currentApp = null;

    // 监听路由变化
    window.addEventListener("hashchange", this.routeChange.bind(this));
    window.addEventListener("popstate", this.routeChange.bind(this));
  }

  routeChange() {
    const { pathname } = window.location;
    const app = this.apps.find((app) => {
      return typeof app.activeRule === "string"
        ? pathname.startsWith(app.activeRule)
        : app.activeRule(pathname);
    });

    if (app && app !== this.currentApp) {
      if (this.currentApp) {
        this.currentApp.unmount();
      }
      app.mount();
      this.currentApp = app;
    }
  }
}

3.2 JS 沙箱实现

3.2.1 Proxy 代理沙箱(现代浏览器)
class ProxySandbox {
  constructor() {
    this.fakeWindow = {};
    this.proxy = new Proxy(this.fakeWindow, {
      get: (target, key) => target[key] || window[key],
      set: (target, key, value) => {
        target[key] = value;
        return true;
      },
    });
  }
}
3.2.2 快照沙箱(兼容模式)
class SnapshotSandbox {
  constructor() {
    this.windowSnapshot = {};
    this.modifyPropsMap = {};
  }

  active() {
    // 记录当前window快照
    for (const prop in window) {
      this.windowSnapshot[prop] = window[prop];
    }
    // 恢复之前的修改
    Object.keys(this.modifyPropsMap).forEach((prop) => {
      window[prop] = this.modifyPropsMap[prop];
    });
  }

  inactive() {
    // 记录被修改的属性
    for (const prop in window) {
      if (window[prop] !== this.windowSnapshot[prop]) {
        this.modifyPropsMap[prop] = window[prop];
        window[prop] = this.windowSnapshot[prop];
      }
    }
  }
}

3.3 样式隔离

3.3.1 动态样式表(默认方案)
function loadStyles(css) {
  const style = document.createElement("style");
  style.textContent = css;
  document.head.appendChild(style);
  return () => style.remove();
}
3.3.2 Shadow DOM(可选方案)
  • 将子应用的 DOM 和样式封装在 Shadow Root 中,实现天然隔离

3.4 应用通信

  • 全局状态管理:通过 initGlobalState 实现
  • 事件总线:基于 CustomEvent 实现

四、优化与注意事项

4.1 性能优化

  1. 预加载策略:使用 requestIdleCallback 在空闲时预加载资源
  2. 资源缓存:通过 singular 配置控制子应用缓存

4.2 常见问题

  1. 子应用需要适配生命周期钩子
  2. Web Components 和 Webpack 5 Module Federation 需要特殊处理
  3. 旧版浏览器兼容性问题

五、qiankun vs Single-SPA

single-spa 是微前端的“内核”,而 qiankun 是基于它的“完整操作系统”。如果你希望深入理解微前端的底层机制(如路由调度、生命周期管理),或需要高度定制化的架构,学习 single-spa 是必经之路;如果追求快速落地,直接使用 qiankun 更为高效。

特性single-spaqiankun
定位底层框架,提供核心路由和生命周期上层解决方案,封装 single-spa 并增强功能
隔离机制需自行实现(如沙箱、样式隔离)内置 JS 沙箱、动态样式隔离
子应用加载方式JS Entry(需手动处理依赖)HTML Entry(自动解析资源)
开箱即用功能预加载、通信机制、错误恢复等
上手难度高(需处理大量细节)低(提供完整解决方案)
适用场景需要高度定制化的微前端架构快速搭建企业级微前端应用

手写一个简易 single-spa

// 1. 注册子应用
const applications = [];
function registerApplication(appConfig) {
  applications.push(appConfig);
}

// 2. 路由劫持
window.addEventListener("hashchange", reroute);
function reroute() {
  const path = window.location.hash.slice(1);
  applications.forEach((app) => {
    const shouldMount = path.startsWith(app.activeWhen);
    if (shouldMount && !app.mounted) {
      app.app().then((childApp) => {
        childApp.bootstrap();
        childApp.mount({ domElement: document.getElementById(app.name) });
        app.mounted = true;
      });
    } else if (!shouldMount && app.mounted) {
      childApp.unmount();
      app.mounted = false;
    }
  });
}

六、最佳实践

  1. 优先使用动态样式表方案,必要时再考虑 Shadow DOM
  2. 合理使用预加载,避免资源浪费
  3. 注意子应用生命周期管理
  4. 遵循官方文档建议的开发规范

更多详情请参考官方文档