Skip to content

微前端使用指南

1. 微前端概述

1.1 什么是微前端

微前端是一种类似于微服务的架构,它将前端应用拆分为多个小型、独立的前端应用,这些应用可以独立开发、独立部署、独立运行。

javascript
// 微前端架构示例
const microApps = [
  {
    name: 'user-management',
    entry: 'https://user.example.com',
    container: '#user-container',
    activeRule: '/user',
  },
  {
    name: 'order-management',
    entry: 'https://order.example.com',
    container: '#order-container',
    activeRule: '/order',
  },
];

1.2 微前端的核心价值

技术栈无关

  • 不同团队可以使用不同的技术栈(React、Vue、Angular)
  • 渐进式迁移老项目
  • 技术栈升级风险可控

独立开发部署

  • 团队自治,减少协调成本
  • 独立的开发、测试、部署流程
  • 故障隔离,单个应用问题不影响整体

代码库隔离

  • 避免单体应用代码库过大
  • 更好的代码组织和维护
  • 团队职责边界清晰

1.3 微前端的挑战

性能问题

  • 重复加载相同依赖
  • 应用切换的性能开销
  • 首屏加载时间可能增加

用户体验

  • 应用间切换的一致性
  • 共享状态管理复杂
  • 样式隔离和冲突

技术复杂度

  • 基础设施复杂度增加
  • 调试和监控难度提升
  • 版本兼容性管理

2. 主流微前端方案对比

2.1 iframe 方案

优点

html
<!-- 最简单的微前端实现 -->
<iframe src="https://sub-app.example.com" style="width: 100%; height: 500px; border: none;"> </iframe>
  • 实现简单,天然隔离
  • 技术栈完全无关
  • 安全性好

缺点

  • 性能差,刷新重新加载
  • 通信复杂,postMessage API
  • SEO 不友好
  • 移动端兼容性问题

2.2 Web Components 方案

实现示例

javascript
// 定义微前端组件
class MicroApp extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `
      <div id="micro-app-container"></div>
    `;
    this.loadApp();
  }

  async loadApp() {
    const { mount } = await import('https://micro-app.example.com/app.js');
    mount(this.querySelector('#micro-app-container'));
  }
}

customElements.define('micro-app', MicroApp);

优点

  • 原生支持,无需额外框架
  • 真正的组件化
  • 样式和脚本天然隔离

缺点

  • 浏览器兼容性有限
  • 学习成本高
  • 生态不够成熟

2.3 Module Federation (Webpack 5)

配置示例

javascript
// webpack.config.js - 主应用
const ModuleFederationPlugin = require('@module-federation/webpack');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        userApp: 'userApp@http://localhost:3001/remoteEntry.js',
        orderApp: 'orderApp@http://localhost:3002/remoteEntry.js',
      },
    }),
  ],
};

// 使用远程模块
const UserApp = React.lazy(() => import('userApp/App'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserApp />
    </Suspense>
  );
}

优点

  • Webpack 原生支持
  • 运行时动态加载
  • 共享依赖优化
  • 类型安全(TypeScript 支持)

缺点

  • 绑定 Webpack 生态
  • 配置复杂
  • 版本兼容性要求高

2.4 single-spa

基础配置

javascript
// 注册微应用
import { registerApplication, start } from 'single-spa';

registerApplication({
  name: 'vue-app',
  app: () => import('./vue-app/main.js'),
  activeWhen: (location) => location.pathname.startsWith('/vue'),
  customProps: {
    authToken: 'auth-token',
  },
});

registerApplication({
  name: 'react-app',
  app: () => import('./react-app/main.js'),
  activeWhen: ['/react'],
});

start();

微应用导出

javascript
// Vue 微应用
let instance = null;

export async function mount(props) {
  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  }).$mount('#vue-app');
}

export async function unmount() {
  instance.$destroy();
  instance = null;
}

优点

  • 框架无关,灵活性高
  • 生态成熟,插件丰富
  • 轻量级,性能好

缺点

  • 需要改造现有应用
  • 样式隔离需要额外处理
  • 学习成本相对较高

2.5 qiankun (基于 single-spa)

主应用配置

javascript
// main.js
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'vue-app',
    entry: '//localhost:8081',
    container: '#vue-container',
    activeRule: '/vue',
    props: {
      data: { name: 'qiankun' },
    },
  },
  {
    name: 'react-app',
    entry: {
      scripts: ['//localhost:8082/static/js/bundle.js'],
      styles: ['//localhost:8082/static/css/main.css'],
    },
    container: '#react-container',
    activeRule: '/react',
  },
]);

// 启动微前端
start({
  sandbox: {
    strictStyleIsolation: true,
    experimentalStyleIsolation: true,
  },
  prefetch: 'all',
});

微应用改造

javascript
// Vue 微应用 main.js
let instance = null;

function render(props = {}) {
  const { container } = props;
  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('[vue] vue app bootstraped');
}

export async function mount(props) {
  console.log('[vue] props from main framework', props);
  render(props);
}

export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
}

优点

  • 开箱即用,配置简单
  • 强大的沙箱隔离
  • 完善的生态和文档
  • 阿里团队维护,稳定性好

缺点

  • 主要面向 React/Vue 生态
  • 自定义程度不如 single-spa
  • 部分高级特性学习成本较高

3. qiankun 深度使用指南

3.1 项目初始化

主应用搭建

bash
# 创建主应用
npx create-react-app main-app
cd main-app
npm install qiankun --save
javascript
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div className="App">
        <nav>
          <Link to="/vue">Vue应用</Link>
          <Link to="/react">React应用</Link>
        </nav>

        {/* 微应用容器 */}
        <div id="vue-container"></div>
        <div id="react-container"></div>
      </div>
    </Router>
  );
}

export default App;

微应用改造要点

javascript
// 1. 修改 webpack publicPath
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// 2. 导出生命周期函数
export async function bootstrap() {
  // 应用启动前的准备工作
}

export async function mount(props) {
  // 应用挂载
  ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.querySelector('#root'));
}

export async function unmount(props) {
  // 应用卸载
  ReactDOM.unmountComponentAtNode(
    props.container ? props.container.querySelector('#root') : document.querySelector('#root')
  );
}

3.2 沙箱机制详解

JS 沙箱

javascript
// qiankun 提供三种沙箱模式

// 1. SnapshotSandbox - 快照沙箱(兼容模式)
// 记录和恢复 window 对象的快照

// 2. LegacySandbox - 单例沙箱
// 使用 Proxy 代理 window 对象

// 3. ProxySandbox - 多例沙箱(推荐)
// 每个微应用都有独立的 window 代理对象

// 配置沙箱
start({
  sandbox: {
    strictStyleIsolation: true, // 严格样式隔离
    experimentalStyleIsolation: true, // 实验性样式隔离
    excludeAssetFilter: (assetUrl) => {
      // 排除某些资源的沙箱处理
      return assetUrl === '/some-special.js';
    },
  },
});

样式隔离

javascript
// 1. 严格样式隔离 - Shadow DOM
start({
  sandbox: {
    strictStyleIsolation: true
  }
});

// 2. 实验性样式隔离 - 样式作用域
start({
  sandbox: {
    experimentalStyleIsolation: true
  }
});

// 3. 手动样式隔离
// 微应用样式添加前缀
.vue-app {
  .header { color: red; }
  .content { background: blue; }
}

3.3 应用通信

1. 全局状态管理

javascript
// 主应用
import { initGlobalState } from 'qiankun';

const actions = initGlobalState({
  user: { name: 'qiankun' },
  theme: 'light',
});

// 监听全局状态变化
actions.onGlobalStateChange((state, prev) => {
  console.log('主应用监听到状态变化', state, prev);
});

// 设置全局状态
actions.setGlobalState({
  user: { name: 'updated' },
});

// 微应用中
export async function mount(props) {
  // 监听全局状态
  props.onGlobalStateChange((state, prev) => {
    console.log('微应用监听到状态变化', state, prev);
  });

  // 设置全局状态
  props.setGlobalState({
    theme: 'dark',
  });
}

2. 自定义通信机制

javascript
// 发布订阅模式
class EventBus {
  constructor() {
    this.events = {};
  }

  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach((callback) => callback(data));
    }
  }

  off(event, callback) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter((cb) => cb !== callback);
    }
  }
}

// 挂载到全局
window.eventBus = new EventBus();

// 微应用中使用
window.eventBus.on('userLogin', (user) => {
  console.log('用户登录', user);
});

window.eventBus.emit('userLogin', { name: 'John' });

3.4 路由配置

主应用路由

javascript
// 使用 history 模式
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();

// 监听路由变化
history.listen((location) => {
  console.log('路由变化', location);
});

// 手动跳转
history.push('/vue/user/123');

微应用路由

javascript
// Vue Router 配置
const router = new VueRouter({
  mode: 'history',
  base: window.__POWERED_BY_QIANKUN__ ? '/vue' : '/',
  routes: [
    { path: '/', component: Home },
    { path: '/user/:id', component: User },
  ],
});

// React Router 配置
function App() {
  return (
    <Router basename={window.__POWERED_BY_QIANKUN__ ? '/react' : '/'}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/order/:id" element={<Order />} />
      </Routes>
    </Router>
  );
}

3.5 资源预加载

javascript
import { prefetchApps } from 'qiankun';

// 预加载微应用
prefetchApps([
  { name: 'vue-app', entry: '//localhost:8081' },
  { name: 'react-app', entry: '//localhost:8082' },
]);

// 或者在注册时配置
start({
  prefetch: 'all', // 预加载所有微应用
  // prefetch: ['vue-app'], // 预加载指定微应用
  // prefetch: (apps) => apps.filter(app => app.name === 'critical'), // 自定义预加载逻辑
});

3.6 错误处理

javascript
import { addErrorHandler } from 'qiankun';

// 全局错误处理
addErrorHandler((error) => {
  console.error('微前端加载出错', error);

  // 可以进行错误上报
  errorReporting(error);

  // 显示降级页面
  showFallbackUI();
});

// 微应用级别错误处理
registerMicroApps([
  {
    name: 'vue-app',
    entry: '//localhost:8081',
    container: '#vue-container',
    activeRule: '/vue',
    loader: (loading) => {
      if (loading) {
        showLoading();
      } else {
        hideLoading();
      }
    },
  },
]);

4. 微前端底层原理

4.1 应用加载原理

HTML Entry 解析

javascript
// qiankun 的 HTML Entry 实现原理
async function importHTML(url) {
  // 1. 获取 HTML 内容
  const html = await fetch(url).then((res) => res.text());

  // 2. 解析 HTML,提取 script 和 link 标签
  const { scripts, styles, template } = parseHTML(html);

  // 3. 动态执行脚本
  const execScripts = async () => {
    for (const script of scripts) {
      if (script.src) {
        // 外部脚本
        await loadScript(script.src);
      } else {
        // 内联脚本
        eval(script.innerHTML);
      }
    }
  };

  return {
    template,
    execScripts,
    styles,
  };
}

// 解析 HTML 的简化实现
function parseHTML(html) {
  const template = document.createElement('div');
  template.innerHTML = html;

  const scripts = Array.from(template.querySelectorAll('script'));
  const styles = Array.from(template.querySelectorAll('link[rel="stylesheet"], style'));

  // 移除 script 标签,避免重复执行
  scripts.forEach((script) => script.remove());

  return {
    scripts,
    styles,
    template: template.innerHTML,
  };
}

模块加载机制

javascript
// SystemJS 风格的模块加载
class ModuleLoader {
  constructor() {
    this.modules = new Map();
  }

  async loadModule(url) {
    if (this.modules.has(url)) {
      return this.modules.get(url);
    }

    const moduleCode = await fetch(url).then((res) => res.text());
    const module = this.executeModule(moduleCode, url);
    this.modules.set(url, module);

    return module;
  }

  executeModule(code, url) {
    // 创建模块作用域
    const moduleScope = {
      exports: {},
      module: { exports: {} },
      require: (id) => this.loadModule(this.resolveModule(id, url)),
    };

    // 包装模块代码
    const wrappedCode = `
      (function(exports, module, require) {
        ${code}
      })
    `;

    // 执行模块
    const moduleFunction = eval(wrappedCode);
    moduleFunction(moduleScope.exports, moduleScope.module, moduleScope.require);

    return moduleScope.module.exports;
  }
}

4.2 沙箱隔离原理

Proxy 沙箱实现

javascript
class ProxySandbox {
  constructor(name) {
    this.name = name;
    this.proxy = null;
    this.running = false;

    // 沙箱期间新增的全局变量
    this.addedPropsMapInSandbox = new Map();
    // 沙箱期间更新的全局变量
    this.modifiedPropsOriginalValueMapInSandbox = new Map();
    // 持续记录更新的(新增和修改的)全局变量的 map,用于在任意时刻做 snapshot
    this.currentUpdatedPropsValueMap = new Map();

    this.createProxy();
  }

  createProxy() {
    const fakeWindow = Object.create(null);

    this.proxy = new Proxy(fakeWindow, {
      get: (target, prop) => {
        if (prop === Symbol.unscopables) return undefined;

        // 优先从代理对象取值
        if (target.hasOwnProperty(prop)) {
          return target[prop];
        }

        // 从原始 window 对象取值
        const value = window[prop];

        // 如果是函数,绑定正确的 this
        if (typeof value === 'function') {
          const boundTarget = value.bind(window);
          return boundTarget;
        }

        return value;
      },

      set: (target, prop, value) => {
        if (this.running) {
          if (!target.hasOwnProperty(prop)) {
            // 新增属性
            this.addedPropsMapInSandbox.set(prop, value);
          } else if (!this.modifiedPropsOriginalValueMapInSandbox.has(prop)) {
            // 记录原始值
            this.modifiedPropsOriginalValueMapInSandbox.set(prop, window[prop]);
          }

          this.currentUpdatedPropsValueMap.set(prop, value);
          target[prop] = value;

          return true;
        }

        // 沙箱未激活时,直接设置到 window
        window[prop] = value;
        return true;
      },

      has: (target, prop) => {
        return prop in target || prop in window;
      },
    });
  }

  active() {
    if (!this.running) {
      this.running = true;

      // 恢复沙箱环境
      this.currentUpdatedPropsValueMap.forEach((value, prop) => {
        this.proxy[prop] = value;
      });
    }
  }

  inactive() {
    if (this.running) {
      this.running = false;

      // 清理新增的全局变量
      this.addedPropsMapInSandbox.forEach((_, prop) => {
        delete window[prop];
      });

      // 还原被修改的全局变量
      this.modifiedPropsOriginalValueMapInSandbox.forEach((value, prop) => {
        window[prop] = value;
      });
    }
  }
}

样式隔离实现

javascript
// Shadow DOM 样式隔离
class ShadowDOMStyleIsolation {
  constructor(container) {
    this.container = container;
    this.shadowRoot = null;
  }

  enable() {
    // 创建 Shadow DOM
    this.shadowRoot = this.container.attachShadow({ mode: 'open' });

    // 将微应用内容移入 Shadow DOM
    while (this.container.firstChild) {
      this.shadowRoot.appendChild(this.container.firstChild);
    }
  }

  disable() {
    if (this.shadowRoot) {
      // 将内容移回普通 DOM
      while (this.shadowRoot.firstChild) {
        this.container.appendChild(this.shadowRoot.firstChild);
      }
      this.shadowRoot = null;
    }
  }
}

// CSS Scoped 样式隔离
class ScopedStyleIsolation {
  constructor(appName) {
    this.appName = appName;
    this.styleElements = [];
  }

  enable() {
    // 拦截样式插入
    this.hijackDynamicStyles();

    // 处理已有样式
    this.scopeExistingStyles();
  }

  hijackDynamicStyles() {
    const originalAppendChild = HTMLHeadElement.prototype.appendChild;
    const originalInsertBefore = HTMLHeadElement.prototype.insertBefore;

    HTMLHeadElement.prototype.appendChild = function (element) {
      if (element.tagName === 'STYLE' || (element.tagName === 'LINK' && element.rel === 'stylesheet')) {
        return this.scopeStyle(element);
      }
      return originalAppendChild.call(this, element);
    };

    HTMLHeadElement.prototype.insertBefore = function (element, before) {
      if (element.tagName === 'STYLE' || (element.tagName === 'LINK' && element.rel === 'stylesheet')) {
        return this.scopeStyle(element);
      }
      return originalInsertBefore.call(this, element, before);
    };
  }

  scopeStyle(styleElement) {
    const prefix = `[data-qiankun="${this.appName}"]`;

    if (styleElement.tagName === 'STYLE') {
      const css = styleElement.innerHTML;
      styleElement.innerHTML = this.scopeCSS(css, prefix);
    }

    this.styleElements.push(styleElement);
    return styleElement;
  }

  scopeCSS(css, prefix) {
    // 简化的 CSS 作用域处理
    return css.replace(/([^{}]+){/g, (match, selector) => {
      const scopedSelector = selector
        .split(',')
        .map((s) => `${prefix} ${s.trim()}`)
        .join(', ');
      return `${scopedSelector} {`;
    });
  }
}

4.3 生命周期管理

javascript
class MicroAppManager {
  constructor() {
    this.apps = new Map();
    this.currentApp = null;
  }

  async loadApp(appConfig) {
    const { name, entry, container, activeRule } = appConfig;

    // 1. 加载应用资源
    const { template, execScripts } = await this.importHTML(entry);

    // 2. 创建沙箱
    const sandbox = new ProxySandbox(name);

    // 3. 创建应用实例
    const app = {
      name,
      sandbox,
      template,
      execScripts,
      container: typeof container === 'string' ? document.querySelector(container) : container,
      activeRule,
      status: 'NOT_LOADED', // NOT_LOADED -> LOADING_SOURCE_CODE -> NOT_BOOTSTRAPPED -> BOOTSTRAPPING -> NOT_MOUNTED -> MOUNTING -> MOUNTED
      lifecycle: {},
    };

    this.apps.set(name, app);
    return app;
  }

  async mountApp(app) {
    if (app.status !== 'NOT_MOUNTED') {
      return;
    }

    app.status = 'MOUNTING';

    try {
      // 1. 激活沙箱
      app.sandbox.active();

      // 2. 渲染模板
      app.container.innerHTML = app.template;

      // 3. 执行脚本,获取生命周期函数
      const lifecycle = await app.execScripts();
      app.lifecycle = lifecycle;

      // 4. 执行 bootstrap
      if (app.lifecycle.bootstrap) {
        await app.lifecycle.bootstrap();
      }

      // 5. 执行 mount
      if (app.lifecycle.mount) {
        await app.lifecycle.mount({
          container: app.container,
        });
      }

      app.status = 'MOUNTED';
      this.currentApp = app;
    } catch (error) {
      console.error(`挂载应用 ${app.name} 失败:`, error);
      app.status = 'LOAD_ERROR';
    }
  }

  async unmountApp(app) {
    if (app.status !== 'MOUNTED') {
      return;
    }

    app.status = 'UNMOUNTING';

    try {
      // 1. 执行 unmount
      if (app.lifecycle.unmount) {
        await app.lifecycle.unmount();
      }

      // 2. 清理 DOM
      app.container.innerHTML = '';

      // 3. 停用沙箱
      app.sandbox.inactive();

      app.status = 'NOT_MOUNTED';

      if (this.currentApp === app) {
        this.currentApp = null;
      }
    } catch (error) {
      console.error(`卸载应用 ${app.name} 失败:`, error);
    }
  }

  // 路由变化处理
  onRouteChange(location) {
    const targetApp = this.findMatchingApp(location);

    if (targetApp !== this.currentApp) {
      // 卸载当前应用
      if (this.currentApp) {
        this.unmountApp(this.currentApp);
      }

      // 挂载目标应用
      if (targetApp) {
        this.mountApp(targetApp);
      }
    }
  }

  findMatchingApp(location) {
    for (const [name, app] of this.apps) {
      if (this.isActive(app.activeRule, location)) {
        return app;
      }
    }
    return null;
  }

  isActive(activeRule, location) {
    if (typeof activeRule === 'string') {
      return location.pathname.startsWith(activeRule);
    }
    if (typeof activeRule === 'function') {
      return activeRule(location);
    }
    if (Array.isArray(activeRule)) {
      return activeRule.some((rule) => this.isActive(rule, location));
    }
    return false;
  }
}

5. 实际项目应用经验

5.1 技术选型建议

选择 qiankun 的场景

  • 团队主要使用 React/Vue 技术栈
  • 需要快速实施微前端架构
  • 对沙箱隔离要求较高
  • 希望有完善的社区支持

选择 Module Federation 的场景

  • 已经使用 Webpack 5
  • 需要更细粒度的模块共享
  • 对构建时优化有较高要求
  • 团队有较强的 Webpack 配置能力

选择 single-spa 的场景

  • 需要更大的灵活性和自定义能力
  • 多种技术栈混合使用
  • 对框架侵入性要求较低
  • 有充足的开发时间

5.2 常见问题和解决方案

1. 样式冲突

css
/* 解决方案1:CSS 命名空间 */
.micro-app-user {
  .header {
    color: red;
  }
  .content {
    background: blue;
  }
}

/* 解决方案2:CSS-in-JS */
const styles = {
  header: {
    color: 'red';
  }
}

/* 解决方案3:CSS Modules */
.header {
  composes: global-header;
  color: red;
}

2. 状态共享

javascript
// 全局状态管理
class GlobalStore {
  constructor() {
    this.state = {};
    this.listeners = [];
  }

  setState(newState) {
    this.state = { ...this.state, ...newState };
    this.listeners.forEach((listener) => listener(this.state));
  }

  getState() {
    return this.state;
  }

  subscribe(listener) {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter((l) => l !== listener);
    };
  }
}

// 挂载到全局
window.globalStore = new GlobalStore();

3. 依赖共享

javascript
// webpack externals 配置
module.exports = {
  externals: {
    react: 'React',
    'react-dom': 'ReactDOM',
    lodash: '_',
  },
};

// 主应用提供共享依赖
window.React = require('react');
window.ReactDOM = require('react-dom');
window._ = require('lodash');

5.3 性能优化策略

1. 预加载优化

javascript
// 智能预加载
const prefetchStrategy = {
  // 根据用户行为预测
  predictive: (userBehavior) => {
    const likelyApps = predictNextApps(userBehavior);
    return likelyApps.slice(0, 2); // 预加载前2个最可能访问的应用
  },

  // 空闲时间预加载
  idle: () => {
    if (window.requestIdleCallback) {
      window.requestIdleCallback(() => {
        prefetchApps(['low-priority-app']);
      });
    }
  },

  // 网络状态感知
  networkAware: () => {
    if (navigator.connection) {
      const { effectiveType } = navigator.connection;
      if (effectiveType === '4g') {
        return ['all']; // 4G 网络预加载所有应用
      } else {
        return ['critical-app']; // 慢网络只预加载关键应用
      }
    }
    return [];
  },
};

2. 缓存策略

javascript
// Service Worker 缓存策略
self.addEventListener('fetch', (event) => {
  const { request } = event;

  // 微应用资源缓存
  if (request.url.includes('/micro-apps/')) {
    event.respondWith(
      caches.open('micro-apps-cache').then((cache) => {
        return cache.match(request).then((response) => {
          if (response) {
            // 缓存命中,同时更新缓存
            fetch(request).then((fetchResponse) => {
              cache.put(request, fetchResponse.clone());
            });
            return response;
          }

          // 缓存未命中,从网络获取
          return fetch(request).then((fetchResponse) => {
            cache.put(request, fetchResponse.clone());
            return fetchResponse;
          });
        });
      })
    );
  }
});

5.4 监控和调试

1. 错误监控

javascript
// 微前端错误收集
class MicroFrontendMonitor {
  constructor() {
    this.errors = [];
    this.performance = [];
    this.init();
  }

  init() {
    // 全局错误捕获
    window.addEventListener('error', (event) => {
      this.collectError({
        type: 'javascript',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        stack: event.error?.stack,
        timestamp: Date.now(),
      });
    });

    // Promise 错误捕获
    window.addEventListener('unhandledrejection', (event) => {
      this.collectError({
        type: 'promise',
        message: event.reason?.message || event.reason,
        stack: event.reason?.stack,
        timestamp: Date.now(),
      });
    });

    // 微应用加载性能监控
    this.monitorMicroAppPerformance();
  }

  collectError(error) {
    this.errors.push({
      ...error,
      userAgent: navigator.userAgent,
      url: location.href,
      microApp: this.getCurrentMicroApp(),
    });

    // 上报错误
    this.reportError(error);
  }

  monitorMicroAppPerformance() {
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (entry.name.includes('/micro-apps/')) {
          this.performance.push({
            name: entry.name,
            duration: entry.duration,
            startTime: entry.startTime,
            timestamp: Date.now(),
          });
        }
      }
    });

    observer.observe({ entryTypes: ['navigation', 'resource'] });
  }

  getCurrentMicroApp() {
    // 获取当前激活的微应用名称
    return window.__CURRENT_MICRO_APP__ || 'unknown';
  }

  reportError(error) {
    // 发送到监控平台
    fetch('/api/monitor/error', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(error),
    }).catch(() => {
      // 上报失败,存储到本地
      localStorage.setItem(
        'pending_errors',
        JSON.stringify([...JSON.parse(localStorage.getItem('pending_errors') || '[]'), error])
      );
    });
  }
}

// 初始化监控
new MicroFrontendMonitor();

2. 调试工具

javascript
// 微前端调试面板
class MicroFrontendDevtools {
  constructor() {
    this.apps = new Map();
    this.createDevPanel();
  }

  createDevPanel() {
    if (process.env.NODE_ENV !== 'development') return;

    const panel = document.createElement('div');
    panel.id = 'micro-frontend-devtools';
    panel.style.cssText = `
      position: fixed;
      top: 0;
      right: 0;
      width: 300px;
      height: 100vh;
      background: #f0f0f0;
      border-left: 1px solid #ccc;
      z-index: 9999;
      overflow-y: auto;
      font-family: monospace;
      font-size: 12px;
    `;

    document.body.appendChild(panel);
    this.panel = panel;
    this.updatePanel();
  }

  updatePanel() {
    if (!this.panel) return;

    const appsInfo = Array.from(this.apps.values())
      .map(
        (app) => `
      <div style="padding: 10px; border-bottom: 1px solid #ddd;">
        <h4>${app.name}</h4>
        <p>状态: ${app.status}</p>
        <p>路由: ${app.activeRule}</p>
        <p>容器: ${app.container?.id || 'unknown'}</p>
        <button onclick="window.microDevtools.toggleApp('${app.name}')">
          ${app.status === 'MOUNTED' ? '卸载' : '挂载'}
        </button>
      </div>
    `
      )
      .join('');

    this.panel.innerHTML = `
      <h3 style="padding: 10px; margin: 0; background: #333; color: white;">
        微前端调试面板
      </h3>
      ${appsInfo}
    `;
  }

  addApp(app) {
    this.apps.set(app.name, app);
    this.updatePanel();
  }

  updateAppStatus(name, status) {
    const app = this.apps.get(name);
    if (app) {
      app.status = status;
      this.updatePanel();
    }
  }

  toggleApp(name) {
    const app = this.apps.get(name);
    if (app) {
      if (app.status === 'MOUNTED') {
        window.microAppManager.unmountApp(app);
      } else {
        window.microAppManager.mountApp(app);
      }
    }
  }
}

// 全局调试工具
window.microDevtools = new MicroFrontendDevtools();

6. 面试重点总结

6.1 核心概念

  • 微前端定义: 将前端应用拆分为多个独立的子应用
  • 主要价值: 技术栈无关、独立开发部署、代码库隔离
  • 核心挑战: 性能问题、用户体验一致性、技术复杂度

6.2 技术原理

  • 应用加载: HTML Entry、模块联邦、SystemJS
  • 沙箱隔离: Proxy 沙箱、快照沙箱、样式隔离
  • 生命周期: bootstrap、mount、unmount
  • 通信机制: 全局状态、发布订阅、props 传递

6.3 方案对比

  • qiankun: 易用性高、生态完善、适合 React/Vue
  • Module Federation: 构建时优化、细粒度共享、需要 Webpack 5
  • single-spa: 灵活性高、框架无关、学习成本较高
  • iframe: 实现简单、隔离性好、体验较差

6.4 最佳实践

  • 合理的应用拆分策略
  • 统一的技术规范和开发流程
  • 完善的监控和错误处理机制
  • 性能优化和缓存策略

6.5 常见问题

  • 如何解决样式冲突?
  • 如何实现应用间通信?
  • 如何处理路由同步?
  • 如何优化加载性能?
  • 如何进行错误监控?

通过这份指南,你应该能够全面了解微前端的核心概念、技术原理和实践经验,为面试做好充分准备。

Released under the MIT License.