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

一、微前端概述

微前端(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. 统一开发规范

个人观点,仅供参考

相关推荐
剩下了什么1 小时前
微服务入门介绍
微服务·云原生·架构
星浩AI2 小时前
基于知识图谱的多模态 GraphRAG 项目实战,系统架构详解[附源码]
架构·langchain·agent
techdashen2 小时前
Cloudflare HTML 解析器的十年演化史(二)
前端·html
ZC跨境爬虫2 小时前
Apple官网复刻第二阶段day_1:(导航栏模块化重构+工业化可复用UI落地)
前端·javascript·css·ui·重构
张忠琳2 小时前
【vllm】(六)vLLM v1 Sample — 模块超深度分析之一
ai·架构·vllm
SamDeepThinking2 小时前
秒杀下单,用户点一下按钮,后端要过六道关卡
java·后端·架构
虾米Life2 小时前
MVC与MVVM 架构
架构·mvc·mvvm
天外飞雨道沧桑2 小时前
Node.js在前端开发中扮演的角色
前端·node.js
Sam_Deep_Thinking2 小时前
适合中小型企业的出口入口网关微服务
java·微服务·架构