【架构实战】微前端架构设计与落地

一、微前端概述

微前端(Micro Frontend)是将微服务思想应用到前端的一种架构模式:

核心理念:

  • 将大型前端应用拆分为独立可部署的小应用
  • 各子应用可以独立开发、测试、部署
  • 技术栈无关,打破团队边界

解决的问题:

  • 大型前端项目的维护困难
  • 多团队协作的代码冲突
  • 技术栈升级的困难
  • 巨石应用的性能问题

二、微前端架构模式

1. 架构图

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         微前端架构                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │  会员子应用   │  │  订单子应用   │  │  商品子应用   │          │
│  │  (React)    │  │  (Vue)       │  │  (Angular)   │          │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘          │
│         │                  │                  │                   │
│  ┌──────▼──────────────────▼──────────────────▼───────┐        │
│  │                    容器应用                         │        │
│  │  (主应用骨架、路由管理、公共组件、样式隔离)           │        │
│  └────────────────────────┬───────────────────────────┘        │
│                           │                                      │
│  ┌────────────────────────▼───────────────────────────┐        │
│  │              独立部署平台                           │        │
│  │  (CI/CD流水线、版本管理、灰度发布)                  │        │
│  └────────────────────────────────────────────────────┘        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2. 技术选型对比

方案 描述 优点 缺点 适用场景
iframe 嵌套独立页面 隔离性强 体验差、通讯难 简单场景
JS Bundle 动态加载子应用 体验好 样式冲突 中等复杂度
Web Component 自定义组件 原生隔离 学习曲线 新项目
Module Federation Webpack联邦模块 成熟、共享依赖 需Webpack 已有项目改造

3. Module Federation方案

主应用配置:

javascript 复制代码
// 主应用 webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const deps = require('./package.json').dependencies;

module.exports = {
  mode: 'development',
  devServer: {
    port: 3000,
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'container',
      // 共享的依赖(子应用可以复用)
      shared: {
        react: { singleton: true, requiredVersion: deps.react },
        'react-dom': { singleton: true, requiredVersion: deps['react-dom'] }
      }
    })
  ]
};

子应用配置:

javascript 复制代码
// 子应用(Vue)webpack.config.js
module.exports = {
  mode: 'development',
  devServer: {
    port: 3001,
    // 暴露子应用
    headers: { 'Access-Control-Allow-Origin': '*' }
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'orderApp',
      // 暴露的模块
      exposes: {
        './OrderModule': './src/OrderModule'
      },
      // 共享依赖
      shared: {
        vue: { singleton: true },
        'vue-router': { singleton: true }
      }
    })
  ]
};

三、微前端框架对比

1. qiankun(阿里)

特点:

  • 基于single-spa
  • 接入简单,API友好
  • 样式隔离
  • 资源预加载

主应用:

javascript 复制代码
// main.js
import { registerMicroApps, start } from 'qiankun';

const apps = [
  {
    name: 'orderApp',           // 子应用名称
    entry: '//localhost:3001', // 子应用入口
    container: '#container',    // 挂载容器
    activeRule: '/order'        // 激活路由
  },
  {
    name: 'productApp',
    entry: '//localhost:3002',
    container: '#container',
    activeRule: '/product'
  }
];

// 注册子应用
registerMicroApps(apps);

// 启动
start();

// 设置全局生命周期
import { setGlobalUnmount } from 'qiankun';

setGlobalUnmount(() => {
  console.log('子应用卸载');
});

子应用(Vue):

javascript 复制代码
// src/main.js
let vueApp = null;

function render(props = {}) {
  const { container } = props;
  
  vueApp = createApp(App);
  vueApp.use(router);
  vueApp.mount(container ? container.querySelector('#app') : '#app');
}

// qiankun生命周期
if (process.env.NODE_ENV === 'development') {
  render();
}

export async function bootstrap() {
  console.log('子应用启动');
}

export async function mount(props) {
  console.log('子应用挂载', props);
  render(props);
}

export async function unmount() {
  console.log('子应用卸载');
  vueApp.$destroy();
  vueApp.$el.innerHTML = '';
}

2. EMP(欢聚时代)

特点:

  • 基于Webpack Module Federation
  • 支持多实例
  • 共享依赖更高效

3. Garfish(字节)

特点:

  • 支持多实例隔离
  • 支持预渲染
  • 完善的沙箱机制

四、微前端通信方案

1. Props通信

javascript 复制代码
// 主应用传递数据
<MicroApp name="orderApp" data={{ userId: 123 }} />

// 子应用接收
function App(props) {
  const { data } = props;
  console.log('收到主应用数据:', data.userId);
}

2. 自定义事件

javascript 复制代码
// 发送事件(子应用)
import { emit } from 'qiankun';

emit('user-login', { userId: 123, token: 'xxx' });

// 监听事件(另一个子应用)
import { onGlobalStateChange } from 'qiankun';

onGlobalStateChange((state) => {
  console.log('收到全局状态变更:', state);
});

3. 共享状态(Redux/Vuex)

javascript 复制代码
// shared/store/index.js
import { createStore } from 'redux';

const initialState = {
  user: null,
  token: null
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    default:
      return state;
  }
}

export const store = createStore(reducer);

// 主应用初始化
import { initGlobalState } from 'qiankun';

const actions = initGlobalState({ user: null, token: null });

// 监听变化
actions.onGlobalStateChange((state) => {
  console.log('全局状态变化:', state);
  store.dispatch({ type: 'SET_USER', payload: state.user });
});

4. 基于事件总线的通信

javascript 复制代码
// eventBus.js
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(cb => cb(data));
    }
  }
  
  off(event, callback) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(cb => cb !== callback);
    }
  }
}

export const eventBus = new EventBus();

五、样式隔离方案

1. CSS Modules

css 复制代码
/* 子应用样式 */
.container {
  padding: 20px;
}

.title {
  color: blue;
}

/* 生成唯一的类名 */
.container { color: blue; }
.container__title { color: blue; }

2. CSS-in-JS

javascript 复制代码
// 使用styled-components
import styled from 'styled-components';

const Container = styled.div`
  padding: 20px;
`;

const Title = styled.h1`
  color: blue;
  font-size: 24px;
`;

// 样式自动隔离

3. Shadow DOM

javascript 复制代码
// 使用Web Component
class OrderWidget extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'closed' });
    
    shadow.innerHTML = `
      <style>
        .container { padding: 20px; }
      </style>
      <div class="container">
        <h1>订单应用</h1>
      </div>
    `;
  }
}

customElements.define('order-widget', OrderWidget);

4. 样式前缀隔离

javascript 复制代码
// 为子应用添加唯一前缀
function mountWithPrefix(container, prefix) {
  const styleElements = container.querySelectorAll('style');
  
  styleElements.forEach(style => {
    const css = style.textContent;
    // 为所有选择器添加前缀
    const prefixedCSS = addPrefix(css, `.${prefix}`);
    style.textContent = prefixedCSS;
  });
}

六、子应用加载与路由

1. 路由分发

javascript 复制代码
// 主应用路由
import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  {
    path: '/',
    component: Home
  },
  // 动态加载子应用
  {
    path: '/order/:page*',
    component: () => import('./OrderApp.vue')
  },
  {
    path: '/product/:page*',
    component: () => import('./ProductApp.vue')
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

2. 预加载

javascript 复制代码
// 主应用预加载子应用
import { preloadApp } from 'qiankun';

preloadApp([
  {
    name: 'orderApp',
    entry: '//localhost:3001'
  }
]);

3. 懒加载

javascript 复制代码
// Vue Router懒加载子应用
const routes = [
  {
    path: '/order',
    component: () => import('./views/Order.vue')
  }
];

// React Router懒加载
const OrderApp = lazy(() => import('orderApp/OrderModule'));

七、微前端最佳实践

1. 项目结构

复制代码
├── micro-frontend-project/
│   ├── container/                 # 主应用
│   │   ├── src/
│   │   ├── public/
│   │   ├── package.json
│   │   └── webpack.config.js
│   │
│   ├── apps/
│   │   ├── order-app/            # 订单子应用
│   │   │   ├── src/
│   │   │   └── package.json
│   │   │
│   │   ├── product-app/          # 商品子应用
│   │   │   ├── src/
│   │   │   └── package.json
│   │   │
│   │   └── user-app/             # 用户子应用
│   │       ├── src/
│   │       └── package.json
│   │
│   └── shared/                   # 共享代码
│       ├── components/
│       ├── utils/
│       └── styles/

2. 开发规范

javascript 复制代码
// 1. 子应用导出标准接口
export { bootstrap, mount, unmount };

// 2. 统一状态管理
// 每个子应用使用独立状态,但通过事件与主应用通信

// 3. 统一错误处理
window.addEventListener('error', (e) => {
  console.error('子应用错误:', e.error);
});

// 4. 统一日志
console.log('[order-app]', '用户操作日志');

3. 性能优化

javascript 复制代码
// 1. 预加载关键子应用
import { prefetchApps } from 'qiankun';

prefetchApps([
  { name: 'orderApp', entry: '//localhost:3001' }
]);

// 2. 代码分割
const OrderModule = lazy(() => import('./OrderModule'));

// 3. 缓存子应用资源
// 配置CDN缓存策略

4. 安全考虑

javascript 复制代码
// 1. 子应用资源校验
const ALLOWED_APPS = ['orderApp', 'productApp', 'userApp'];

function validateApp(appName, appEntry) {
  if (!ALLOWED_APPS.includes(appName)) {
    throw new Error('未授权的子应用');
  }
}

// 2. CSP配置
// 限制子应用可以加载的资源

八、常见问题与解决方案

1. 样式冲突

css 复制代码
/* 方案1:CSS命名空间 */
.order-app .container { }
.product-app .container { }

/* 方案2:CSS Modules */
:local(.container) { }

/* 方案3:Shadow DOM */

2. 状态共享

javascript 复制代码
// 共享用户信息
const sharedState = {
  user: null,
  permissions: []
};

// 主应用设置
function setUser(user) {
  sharedState.user = user;
  emitGlobalStateChange(sharedState);
}

// 子应用获取
onGlobalStateChange((state) => {
  sharedState.user = state.user;
});

3. 公共依赖

javascript 复制代码
// webpack配置共享依赖
shared: {
  react: { singleton: true, eager: true },
  'react-dom': { singleton: true, eager: true }
}

4. 子应用通信

javascript 复制代码
// 使用qiankun的initGlobalState
import { initGlobalState } from 'qiankun';

const initialState = {};
const actions = initGlobalState(initialState);

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

// 子应用修改
actions.setGlobalState({ token: 'xxx' });

九、总结

微前端是大型前端项目的解决方案:

  • 独立开发:各子应用可独立开发
  • 独立部署:解除团队耦合
  • 技术多样:支持不同技术栈
  • 渐进迁移:逐步改造旧项目

最佳实践:

  1. 优先使用qiankun或Module Federation
  2. 做好样式隔离
  3. 设计好通信机制
  4. 统一开发规范

个人观点,仅供参考

相关推荐
漂流瓶jz3 小时前
总结CSS组件化演进之路:命名规范/CSS Modules/CSS in JS/原子化CSS
前端·javascript·css
踩着两条虫3 小时前
「AI + 低代码」的可视化设计器
开发语言·前端·低代码·设计模式·架构
Jagger_4 小时前
项目上线忙碌结束之后,为什么总想找点事做?
前端
GalenZhang8884 小时前
OpenClaw 配置多个飞书账号实战指南
前端·chrome·飞书·openclaw
萌新小码农‍5 小时前
python装饰器
开发语言·前端·python
threelab6 小时前
Three.js 初中数学函数可视化 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
爱学习的程序媛6 小时前
浏览器工作原理全景解析
前端·浏览器·web
耕烟煮云6 小时前
本文深入解析AI Native产品设计的核心范式——Linear三层架构模型
人工智能·架构
我是若尘7 小时前
用 Git Worktree 同时开多个需求,不用来回 stash
前端
IT_陈寒7 小时前
Vue的v-for为什么不加key也能工作?我差点翻车
前端·人工智能·后端