Skip to content
On this page

qiankun 实战案例

案例一:大型电商平台微前端改造

项目背景

某大型电商平台,包含用户中心、商品管理、订单系统、营销活动等多个业务模块,原单体应用代码庞大,开发效率低,部署复杂。

技术栈

  • 主应用:Vue 3 + Vue Router + Pinia
  • 微应用1:React 18 + Redux + Ant Design
  • 微应用2:Vue 2 + Element UI
  • 微应用3:Angular 15

实施步骤

1. 主应用改造

javascript
// main.js - 主应用入口
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { createMicroApp, startApp } from './micro-app';
import App from './App.vue';

// 创建主应用路由
const router = createRouter({
  history: createWebHistory('/'),
  routes: [
    { path: '/', component: () => import('./views/Home.vue') },
    { path: '/user', component: () => import('./views/UserContainer.vue') },
    { path: '/product', component: () => import('./views/ProductContainer.vue') },
    { path: '/order', component: () => import('./views/OrderContainer.vue') },
  ]
});

const app = createApp(App);
app.use(router);

// qiankun 配置
import { registerMicroApps, start } from 'qiankun';

const microApps = [
  {
    name: 'user-center',
    entry: '//localhost:3001',
    container: '#user-center-container',
    activeRule: location => location.pathname.startsWith('/user'),
    props: {
      router,
      store: app.config.globalProperties.$store
    }
  },
  {
    name: 'product-management',
    entry: '//localhost:8080',
    container: '#product-container',
    activeRule: location => location.pathname.startsWith('/product')
  },
  {
    name: 'order-system',
    entry: '//localhost:4200',
    container: '#order-container',
    activeRule: location => location.pathname.startsWith('/order')
  }
];

registerMicroApps(microApps, {
  beforeLoad: app => {
    console.log('[MainApp] before load', app.name);
    return Promise.resolve();
  },
  beforeMount: app => {
    console.log('[MainApp] before mount', app.name);
    return Promise.resolve();
  },
  afterMount: app => {
    console.log('[MainApp] after mount', app.name);
    return Promise.resolve();
  },
  beforeUnmount: app => {
    console.log('[MainApp] before unmount', app.name);
    return Promise.resolve();
  },
  afterUnmount: app => {
    console.log('[MainApp] after unmount', app.name);
    return Promise.resolve();
  }
});

// 启动 qiankun
start({
  prefetch: true,
  sandbox: {
    strictStyleIsolation: true,
    experimentalStyleIsolation: false
  },
  // 全局状态管理
  ...initGlobalState({
    user: { id: 1, name: 'admin' },
    theme: 'dark'
  })
});

app.mount('#app');

2. React 微应用实现

javascript
// user-center/src/main.js - React 微应用
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import store from './store';

let reactApp = null;

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

export async function mount(props) {
  console.log('React app mount', props);
  
  const { container, store: mainStore } = props;
  
  // 整合主应用状态
  const integratedStore = store;
  if (mainStore) {
    // 合并状态逻辑
    integratedStore.dispatch({
      type: 'SET_MAIN_STORE',
      payload: mainStore
    });
  }
  
  reactApp = (
    <Provider store={integratedStore}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  );
  
  ReactDOM.render(
    reactApp,
    container ? container.querySelector('#react-root') : document.getElementById('react-root')
  );
}

export async function unmount(props) {
  console.log('React app unmount', props);
  
  if (reactApp) {
    ReactDOM.unmountComponentAtNode(
      props.container 
        ? props.container.querySelector('#react-root') 
        : document.getElementById('react-root')
    );
    reactApp = null;
  }
}

// 独立运行支持
if (!window.__POWERED_BY_QIANKUN__) {
  ReactDOM.render(<App />, document.getElementById('root'));
}

3. Vue 2 微应用实现

javascript
// product-management/src/main.js - Vue 2 微应用
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

let vueApp = null;

export async function bootstrap(props) {
  console.log('Vue2 app bootstrap', props);
}

export async function mount(props) {
  console.log('Vue2 app mount', props);
  
  const { container, history, onGlobalStateChange, setGlobalState } = props;
  
  // 设置全局状态监听
  if (onGlobalStateChange) {
    onGlobalStateChange((state, prev) => {
      console.log('Global state changed:', state, prev);
      // 更新本地状态
      if (state.user) {
        store.commit('SET_USER', state.user);
      }
    }, true);
  }
  
  // 创建 Vue 实例
  vueApp = new Vue({
    router: createMicroRouter(history, router),
    store,
    render: h => h(App),
  });
  
  vueApp.$mount(container ? container.querySelector('#app') : '#app');
}

export async function unmount(props) {
  console.log('Vue2 app unmount', props);
  
  if (vueApp) {
    vueApp.$destroy();
    vueApp.$el.innerHTML = '';
    vueApp = null;
  }
}

// 为微应用创建适配的路由
function createMicroRouter(mainHistory, microRouter) {
  if (window.__POWERED_BY_QIANKUN__) {
    // 在微前端环境下使用主应用的 history
    return microRouter;
  }
  return microRouter;
}

// 独立运行支持
if (!window.__POWERED_BY_QIANKUN__) {
  new Vue({
    router,
    store,
    render: h => h(App),
  }).$mount('#app');
}

遇到的挑战与解决方案

1. 样式隔离问题

css
/* 解决方案:使用 CSS Modules 或命名空间 */
/* 在微应用中使用特定前缀 */
.user-center-module {
  .header {
    background: #fff;
  }
  
  .content {
    padding: 20px;
  }
}

2. 状态同步问题

javascript
// 统一的状态管理解决方案
import { initGlobalState } from 'qiankun';

const { onGlobalStateChange, setGlobalState } = initGlobalState({
  user: null,
  permissions: [],
  theme: 'light'
});

// 在各微应用中同步用户状态
onGlobalStateChange((state, prev) => {
  if (state.user !== prev.user) {
    // 更新本地用户状态
    updateUserInMicroApp(state.user);
  }
}, true);

案例二:企业级中后台系统

项目背景

某企业中后台系统,包含人事管理、财务管理、项目管理、报表系统等多个子系统,需要实现统一门户和独立开发部署。

架构设计

javascript
// 主应用架构
import { createApp } from 'vue';
import Layout from './components/Layout.vue';
import { registerMicroApps, start } from 'qiankun';

const app = createApp(Layout);

// 微应用配置
const enterpriseApps = [
  {
    name: 'hr-system',
    entry: '//hr.company.com',
    container: '#subapp-container',
    activeRule: '/hr',
    props: {
      apiBase: '/api/hr',
      permissions: ['hr:read', 'hr:write']
    }
  },
  {
    name: 'finance-system',
    entry: '//finance.company.com',
    container: '#subapp-container',
    activeRule: '/finance',
    props: {
      apiBase: '/api/finance',
      permissions: ['finance:read', 'finance:write']
    }
  },
  {
    name: 'project-system',
    entry: '//project.company.com',
    container: '#subapp-container',
    activeRule: '/project',
    props: {
      apiBase: '/api/project',
      permissions: ['project:read', 'project:write']
    }
  }
];

// 权限控制的微应用注册
registerMicroApps(
  enterpriseApps.filter(app => 
    hasPermission(app.props.permissions)
  ),
  {
    beforeLoad: (app) => {
      // 检查应用权限
      if (!hasAppPermission(app.name)) {
        throw new Error(`No permission to access ${app.name}`);
      }
      return Promise.resolve();
    }
  }
);

start({
  sandbox: {
    strictStyleIsolation: true
  },
  prefetch: true
});

function hasPermission(requiredPermissions) {
  const userPermissions = getUserPermissions();
  return requiredPermissions.every(perm => userPermissions.includes(perm));
}

function hasAppPermission(appName) {
  // 根据应用名称检查权限
  return true; // 实际实现中会检查用户权限
}

用户认证集成

javascript
// 认证服务集成
class AuthService {
  constructor() {
    this.token = localStorage.getItem('auth-token');
    this.refreshToken = localStorage.getItem('refresh-token');
  }
  
  async authenticate() {
    if (!this.token) {
      // 重定向到登录页
      window.location.href = '/login';
      return false;
    }
    
    // 验证 token 有效性
    try {
      const response = await fetch('/api/auth/validate', {
        headers: {
          'Authorization': `Bearer ${this.token}`
        }
      });
      
      if (!response.ok) {
        throw new Error('Token invalid');
      }
      
      return true;
    } catch (error) {
      // 刷新 token 或重新登录
      return await this.refreshOrLogin();
    }
  }
  
  async refreshOrLogin() {
    if (this.refreshToken) {
      try {
        const response = await fetch('/api/auth/refresh', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ refreshToken: this.refreshToken })
        });
        
        if (response.ok) {
          const data = await response.json();
          this.token = data.token;
          localStorage.setItem('auth-token', data.token);
          return true;
        }
      } catch (error) {
        console.error('Token refresh failed:', error);
      }
    }
    
    // 重定向到登录
    window.location.href = '/login?redirect=' + encodeURIComponent(window.location.href);
    return false;
  }
}

// 在主应用中集成认证
const authService = new AuthService();

// 检查认证状态
if (!await authService.authenticate()) {
  // 认证失败,不启动微应用
  console.error('Authentication failed, cannot start micro apps');
} else {
  // 启动 qiankun
  start({
    sandbox: { strictStyleIsolation: true },
    prefetch: true
  });
}

案例三:多团队协作的微前端平台

项目背景

多个团队协作开发的大型平台,每个团队负责不同的业务域,需要实现技术栈无关的微前端架构。

工程化配置

javascript
// 主应用的 webpack 配置
const path = require('path');
const { ModuleFederationPlugin } = require('@module-federation/enhanced');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: './src/main.js',
  devServer: {
    port: 8080,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
    new ModuleFederationPlugin({
      name: 'main_app',
      filename: 'remoteEntry.js',
      remotes: {
        // 可以与 Module Federation 集成
      },
      shared: {
        vue: { singleton: true },
        'vue-router': { singleton: true },
      }
    })
  ]
};

微应用标准化模板

javascript
// 微应用通用模板
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';

// 通用微应用生命周期
export async function bootstrap(props) {
  console.log(`${props.name} bootstrap`, props);
}

export async function mount(props) {
  console.log(`${props.name} mount`, props);
  
  const { container, routerBase = '/', name } = props;
  
  // 创建微应用路由
  const router = createRouter({
    history: createWebHistory(routerBase),
    routes: [
      // 微应用特有路由
    ]
  });
  
  const app = createApp(App);
  app.use(router);
  
  // 挂载到指定容器
  app.mount(container.querySelector('#app') || container);
  
  // 保存应用实例以便卸载
  window[`__${name.toUpperCase()}_APP__`] = app;
}

export async function unmount(props) {
  console.log(`${props.name} unmount`, props);
  
  const appName = props.name.toUpperCase();
  const app = window[`__${appName}_APP__`];
  
  if (app) {
    app.unmount();
    delete window[`__${appName}_APP__`];
  }
}

// 独立开发模式
if (!window.__POWERED_BY_QIANKUN__) {
  const app = createApp(App);
  app.use(createRouter({
    history: createWebHistory(),
    routes: [] // 开发环境路由
  }));
  app.mount('#app');
}

CI/CD 集成

yaml
# .github/workflows/micro-app-deploy.yml
name: Deploy Micro App

on:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '16'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Build micro app
      run: npm run build
      env:
        VUE_APP_BASE_URL: ${{ secrets.MICRO_APP_BASE_URL }}
        VUE_APP_API_URL: ${{ secrets.API_URL }}
        
    - name: Run tests
      run: npm run test:unit
      
    - name: Deploy to staging
      if: github.ref == 'refs/heads/develop'
      run: |
        # 部署到预发布环境
        scp -r dist/* user@staging-server:/var/www/micro-app/
        
    - name: Deploy to production
      if: github.ref == 'refs/heads/main'
      run: |
        # 部署到生产环境
        scp -r dist/* user@prod-server:/var/www/micro-app/
        
    - name: Notify main app
      run: |
        # 通知主应用更新微应用入口
        curl -X POST ${{ secrets.MAIN_APP_UPDATE_HOOK }} \
          -H "Content-Type: application/json" \
          -d '{"app": "${{ github.event.repository.name }}", "version": "${{ github.sha }}"}'

性能优化实践

1. 预加载策略

javascript
// 智能预加载
import { start } from 'qiankun';

// 基于用户行为的预加载
class IntelligentPrefetch {
  constructor() {
    this.userBehavior = {
      visitedPages: [],
      timeOnPage: {},
      navigationPattern: []
    };
  }
  
  recordBehavior(page, time) {
    this.userBehavior.visitedPages.push(page);
    this.userBehavior.timeOnPage[page] = time || Date.now();
    
    if (this.userBehavior.visitedPages.length > 10) {
      this.userBehavior.visitedPages.shift();
    }
  }
  
  predictNextMicroApp() {
    const recentPages = this.userBehavior.visitedPages.slice(-3);
    
    // 电商场景预测逻辑
    if (recentPages.includes('/product') && recentPages.includes('/cart')) {
      return 'checkout'; // 可能会访问结算页面
    }
    
    // 中后台场景预测
    if (recentPages.includes('/hr/employees') && recentPages.includes('/hr/departments')) {
      return 'hr/reports';
    }
    
    return null;
  }
}

const prefetchManager = new IntelligentPrefetch();

start({
  prefetch: () => {
    const predictedApp = prefetchManager.predictNextMicroApp();
    if (predictedApp) {
      return [predictedApp];
    }
    return ['common-apps']; // 默认预加载常用应用
  }
});

2. 资源优化

javascript
// 微应用资源优化配置
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // 分离公共依赖
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
          priority: 10
        },
        // 分离 UI 库
        uiLibrary: {
          test: /[\\/]node_modules[\\/](element-ui|ant-design-vue|@angular[\\/]/,
          name: 'ui-library',
          chunks: 'all',
          priority: 8
        }
      }
    }
  }
};

故障排查与监控

1. 错误监控

javascript
// 微应用错误监控
class MicroAppMonitor {
  constructor() {
    this.errorQueue = [];
    this.performanceMetrics = {};
  }
  
  init() {
    // 监控微应用错误
    window.addEventListener('error', (event) => {
      this.reportError({
        type: 'javascript',
        message: event.error.message,
        stack: event.error.stack,
        microAppName: this.getCurrentMicroApp(),
        url: window.location.href,
        timestamp: Date.now()
      });
    });
    
    window.addEventListener('unhandledrejection', (event) => {
      this.reportError({
        type: 'unhandled-promise',
        message: event.reason.message || event.reason,
        stack: event.reason.stack,
        microAppName: this.getCurrentMicroApp(),
        url: window.location.href,
        timestamp: Date.now()
      });
    });
  }
  
  reportError(error) {
    this.errorQueue.push(error);
    
    // 批量上报
    if (this.errorQueue.length >= 5) {
      this.flushErrors();
    }
    
    console.error('Micro app error:', error);
  }
  
  flushErrors() {
    if (this.errorQueue.length > 0) {
      fetch('/api/errors', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          errors: this.errorQueue,
          userAgent: navigator.userAgent,
          timestamp: new Date().toISOString()
        })
      }).catch(err => {
        console.error('Failed to report errors:', err);
      });
      
      this.errorQueue = [];
    }
  }
  
  getCurrentMicroApp() {
    // 根据当前路由判断当前微应用
    const path = window.location.pathname;
    const microAppMap = {
      '/user': 'user-center',
      '/product': 'product-management',
      '/order': 'order-system',
      '/hr': 'hr-system',
      '/finance': 'finance-system'
    };
    
    for (const [route, appName] of Object.entries(microAppMap)) {
      if (path.startsWith(route)) {
        return appName;
      }
    }
    
    return 'unknown';
  }
}

const monitor = new MicroAppMonitor();
monitor.init();

通过这些实战案例,我们可以看到 qiankun 在不同场景下的应用方式和解决方案,包括电商平台、企业中后台和多团队协作等复杂场景。