使用 AtomCode 构建微前端架构:从设计到实现实战

使用 AtomCode 构建微前端架构:从设计到实现实战

一、什么是微前端

微前端是一种将大型前端应用拆分为多个独立子应用的架构模式,每个子应用可以独立开发、测试和部署,最终通过主应用集成在一起。

核心优势:

  • 技术栈无关:各子应用可选用不同技术栈(React、Vue、Angular)
  • 独立开发部署:各团队独立工作,互不影响
  • 渐进式迁移:支持从单体应用逐步迁移到微前端架构

二、微前端架构设计

2.1 架构模式选择

常见的微前端实现模式有以下几种:

模式 优点 缺点 适用场景
iframe 完全隔离,实现简单 性能开销大,通信复杂 简单场景、第三方集成
Single-SPA 轻量,成熟稳定 共享依赖管理复杂 中大型项目
Module Federation 运行时共享,按需加载 配置复杂 现代化架构
qiankun 开箱即用,生态完善 有一定学习成本 企业级项目

技术选型:本文使用 qiankun 作为微前端框架,主应用使用 React,子应用支持 React、Vue、Angular 多技术栈。

2.2 整体架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      主应用 (Main App)                      │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │   Layout    │  │   Router    │  │   Store     │        │
│  │  (React)    │  │  (React)    │  │  (Redux)    │        │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘        │
└─────────┼────────────────┼────────────────┼────────────────┘
          │                │                │
          ▼                ▼                ▼
┌─────────────────────────────────────────────────────────────┐
│                     子应用 (Micro Apps)                     │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  User App   │  │  Product    │  │  Order App  │        │
│  │  (React)    │  │  App (Vue)  │  │  (Angular)  │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
└─────────────────────────────────────────────────────────────┘
          │                │                │
          └────────────────┼────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                     共享模块 (Shared)                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │   UI Kit    │  │   Utils     │  │   API SDK   │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
└─────────────────────────────────────────────────────────────┘

三、主应用实现

3.1 主应用入口配置

typescript 复制代码
import { registerMicroApps, start } from 'qiankun';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import App from './App';

// 注册微应用
registerMicroApps([
  {
    name: 'user-app',
    entry: '//localhost:8081',
    container: '#micro-app-container',
    activeRule: '/user',
    props: { appId: 'user-app' }
  },
  {
    name: 'product-app',
    entry: '//localhost:8082',
    container: '#micro-app-container',
    activeRule: '/product',
    props: { appId: 'product-app' }
  },
  {
    name: 'order-app',
    entry: '//localhost:8083',
    container: '#micro-app-container',
    activeRule: '/order',
    props: { appId: 'order-app' }
  }
]);

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

// 渲染主应用
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="*" element={<App />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

3.2 主应用布局组件

typescript 复制代码
import { useState } from 'react';
import { Link, Outlet } from 'react-router-dom';
import { Layout, Menu } from 'antd';

const { Header, Content, Sider } = Layout;

function App() {
  const [collapsed, setCollapsed] = useState(false);
  
  const menuItems = [
    { key: 'user', label: <Link to="/user">用户管理</Link> },
    { key: 'product', label: <Link to="/product">商品管理</Link> },
    { key: 'order', label: <Link to="/order">订单管理</Link> }
  ];
  
  return (
    <Layout style={{ height: '100vh' }}>
      <Header className="header">
        <h1>微前端平台</h1>
      </Header>
      
      <Layout>
        <Sider
          collapsible
          collapsed={collapsed}
          onCollapse={(value) => setCollapsed(value)}
        >
          <Menu mode="inline" items={menuItems} />
        </Sider>
        
        <Content className="content">
          <div id="micro-app-container">
            <Outlet />
          </div>
        </Content>
      </Layout>
    </Layout>
  );
}

export default App;

四、子应用实现

4.1 React 子应用

typescript 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import UserList from './pages/UserList';
import UserForm from './pages/UserForm';

let root: ReactDOM.Root | null = null;

// qiankun 生命周期
export async function bootstrap() {
  console.log('User app bootstrap');
}

export async function mount(props: { container: HTMLElement }) {
  root = ReactDOM.createRoot(props.container.querySelector('#root')!);
  root.render(
    <React.StrictMode>
      <BrowserRouter basename="/user">
        <Routes>
          <Route path="/" element={<UserList />} />
          <Route path="/create" element={<UserForm />} />
        </Routes>
      </BrowserRouter>
    </React.StrictMode>
  );
}

export async function unmount() {
  root?.unmount();
  root = null;
}

// 独立运行入口
if (!window.__POWERED_BY_QIANKUN__) {
  ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
      <BrowserRouter>
        <UserList />
      </BrowserRouter>
    </React.StrictMode>
  );
}

4.2 Vue 子应用

typescript 复制代码
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
import ProductList from './pages/ProductList.vue';

let app = null;

export async function bootstrap() {
  console.log('Product app bootstrap');
}

export async function mount(props) {
  const router = createRouter({
    history: createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/product' : '/'),
    routes: [{ path: '/', component: ProductList }]
  });
  
  app = createApp(App);
  app.use(router);
  app.mount(props.container.querySelector('#app'));
}

export async function unmount() {
  app?.unmount();
  app = null;
}

五、共享模块设计

5.1 共享 UI 组件

typescript 复制代码
// Button 组件
export function Button({ type = 'primary', children, onClick }) {
  const styles = {
    primary: { backgroundColor: '#1890ff', color: '#fff' },
    secondary: { backgroundColor: '#fff', color: '#666', border: '1px solid #d9d9d9' }
  };
  
  return (
    <button style={{ ...styles[type], padding: '8px 16px', borderRadius: '4px', cursor: 'pointer' }} onClick={onClick}>
      {children}
    </button>
  );
}

// Card 组件
export function Card({ title, children }) {
  return (
    <div style={{ background: '#fff', borderRadius: '8px', padding: '20px', border: '1px solid #f0f0f0' }}>
      {title && <h3 style={{ marginBottom: '16px', paddingBottom: '12px', borderBottom: '1px solid #f0f0f0' }}>{title}</h3>}
      {children}
    </div>
  );
}

5.2 共享工具函数

typescript 复制代码
// 日期格式化
export function formatDate(date, format = 'YYYY-MM-DD') {
  const d = new Date(date);
  const year = d.getFullYear();
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return format.replace('YYYY', year).replace('MM', month).replace('DD', day);
}

// 防抖函数
export function debounce(fn, delay) {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// 生成 UUID
export function generateUUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
  });
}

六、应用间通信

6.1 EventBus 事件总线

typescript 复制代码
class EventBus {
  constructor() {
    this.events = new Map();
  }
  
  subscribe(eventName, handler) {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, new Set());
    }
    this.events.get(eventName).add(handler);
    
    return {
      unsubscribe: () => this.events.get(eventName)?.delete(handler)
    };
  }
  
  publish(eventName, data) {
    this.events.get(eventName)?.forEach(handler => handler(data));
  }
}

export const eventBus = new EventBus();

// 使用示例
// eventBus.subscribe('user:login', (data) => console.log(data));
// eventBus.publish('user:login', { userId: '123' });

6.2 共享状态管理

typescript 复制代码
class SharedState {
  constructor() {
    this.state = {};
    this.listeners = new Map();
  }
  
  set(key, value) {
    const oldValue = this.state[key];
    this.state[key] = value;
    this.listeners.get(key)?.forEach(listener => listener(value, oldValue));
  }
  
  get(key) {
    return this.state[key];
  }
  
  on(key, listener) {
    if (!this.listeners.has(key)) {
      this.listeners.set(key, new Set());
    }
    this.listeners.get(key).add(listener);
    
    return { unsubscribe: () => this.listeners.get(key)?.delete(listener) };
  }
}

export const sharedState = new SharedState();

七、性能优化策略

7.1 懒加载与预加载

typescript 复制代码
// 配置预加载策略
start({
  prefetch: 'all',  // 预加载所有子应用
  
  // 或使用自定义预加载策略
  // prefetch: (app) => app.name === 'user-app'
});

// 路由守卫实现按需加载
router.beforeEach((to, from, next) => {
  const appName = getAppNameFromRoute(to.path);
  if (appName && !window.__MICRO_APPS__?.includes(appName)) {
    prefetchApp(appName);
  }
  next();
});

7.2 资源优化配置

javascript 复制代码
// Webpack 配置优化
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  },
  
  // Gzip 压缩
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip',
      threshold: 8192
    })
  ]
};

八、CI/CD 部署流程

yaml 复制代码
name: MicroFrontend CI/CD

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        app: [main-app, user-app, product-app, order-app]
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with: { node-version: '20' }
      
      - name: Install dependencies
        run: npm ci
        working-directory: ./apps/${{ matrix.app }}
      
      - name: Build
        run: npm run build
        working-directory: ./apps/${{ matrix.app }}
      
      - name: Deploy to CDN
        uses: cloudflare/wrangler-action@v3
        with:
          command: pages deploy ./dist

九、常见问题与解决方案

问题 原因 解决方案
样式冲突 子应用样式污染主应用 使用 CSS Modules 或 Shadow DOM
依赖冲突 不同子应用使用不同版本依赖 使用 Module Federation 共享依赖
通信困难 应用间通信复杂 使用 EventBus 或共享状态
性能问题 多个应用加载导致性能下降 按需加载和预加载策略
调试困难 多应用调试复杂 使用 qiankun 调试工具

十、最佳实践总结

  1. 明确模块边界:子应用间保持独立,通过明确定义的接口通信
  2. 统一共享模块:公共组件和工具通过共享模块统一管理
  3. 渐进式迁移:逐步迁移,避免一次性大规模重构
  4. 独立测试部署:每个子应用独立编写测试和部署
  5. 完善监控体系:建立监控和告警,及时发现问题

结语

微前端架构为大型前端项目提供了更好的可维护性和扩展性。通过合理的架构设计和工具选择,团队可以实现高效协作和快速迭代。


本文为原创内容,基于真实微前端项目开发经验整理。如需转载,请注明出处。

相关推荐
爱折腾的小黑牛12 分钟前
小程序云开发数据模型设计:礼账系统的三表结构
数据库·架构
XUHUOJUN1 小时前
Azure Local GPU 部署与企业应用场景指南(下篇)
microsoft·架构·nvidia·azure local
爱勇宝2 小时前
3位工程师靠“删AI代码”创业,一周收费1万美元:以后最贵的能力,可能不是写代码
前端·后端·架构
●VON2 小时前
HarmonyKit | 鸿蒙开发:项目目录结构与多模块架构最佳实践
华为·架构·单元测试·harmonyos·鸿蒙
没落英雄3 小时前
6. 从零搭建一个 AI Agent —— 构建 Web 前端,让用户能和 agent 实时交互
前端·人工智能·架构
珠海西格电力5 小时前
数据采集与治理:零碳园区管理系统的 “生命线”
大数据·人工智能·算法·架构·能源
头茬韭菜5 小时前
双架构演进与NDJSON远程协议——Agent突破本地边界
ai·架构
XUHUOJUN5 小时前
Azure Local GPU 部署与企业应用场景指南(上篇 )
windows·microsoft·架构·nvidia·azure local
进击的前栈6 小时前
鸿蒙实战:全栈回顾——Kit API 全景、架构总结与未来演进
华为·架构·harmonyos
刀法如飞7 小时前
Spring Boot 4.1 + JDK 25 DDD开源脚手架,面向 AI 编程
设计模式·架构·ai编程