Skip to content
On this page

qiankun 最佳实践

项目架构设计

1. 合理划分微应用

职责分离原则

  • 按业务领域划分微应用
  • 每个微应用应具有明确的业务边界
  • 避免微应用间的循环依赖
javascript
// 示例:合理的微应用划分
const microApps = [
  {
    name: 'user-center', // 用户中心
    entry: '//localhost:3001',
    container: '#user-center-container',
    activeRule: '/user',
  },
  {
    name: 'order-management', // 订单管理
    entry: '//localhost:3002',
    container: '#order-container',
    activeRule: '/order',
  },
  {
    name: 'product-catalog', // 产品目录
    entry: '//localhost:3003',
    container: '#product-container',
    activeRule: '/product',
  }
];

技术栈选择

  • 根据团队技术栈选择微应用实现
  • 保持技术栈的一致性以降低维护成本
  • 为新技术试点预留空间

2. 主应用设计

通用布局组件

javascript
// 主应用布局组件
function MainLayout() {
  return (
    <div className="main-layout">
      <Header />
      <Navigation />
      <div id="subapp-container" className="subapp-container">
        {/* 微应用将在此处渲染 */}
        <div id="subapp-viewport" />
      </div>
      <Footer />
    </div>
  );
}

全局状态管理

javascript
// 主应用全局状态初始化
import { initGlobalState } from 'qiankun';

const initialState = {
  user: null,
  theme: 'light',
  language: 'zh-CN',
  notifications: [],
};

const { onGlobalStateChange, setGlobalState } = initGlobalState(initialState);

// 提供全局状态管理服务
export { onGlobalStateChange, setGlobalState };

微应用开发规范

1. 生命周期实现

标准生命周期实现

javascript
// 微应用标准入口
let app = null;

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

export async function mount(props) {
  const { container, history, store, ...restProps } = props;
  
  // 初始化应用
  app = new Vue({
    router: createRouter(history), // 传入 history 对象
    store,
    render: h => h(App),
  });
  
  // 挂载到指定容器
  app.$mount(container ? container.querySelector('#app') : '#app');
  
  console.log('微应用挂载完成');
}

export async function unmount(props) {
  if (app) {
    app.$destroy();
    app.$el.innerHTML = '';
    app = null;
  }
  
  console.log('微应用卸载完成');
}

错误处理

javascript
export async function mount(props) {
  try {
    // 应用初始化逻辑
    app = new Vue({
      router,
      store,
      render: h => h(App),
    });
    app.$mount(props.container ? props.container.querySelector('#app') : '#app');
  } catch (error) {
    console.error('微应用挂载失败:', error);
    
    // 通知主应用错误状态
    if (props.onError) {
      props.onError(error);
    }
    
    // 提供降级方案
    const container = props.container || document.getElementById('app');
    container.innerHTML = '<div class="error-fallback">微应用加载失败</div>';
  }
}

2. 路由管理

微应用路由配置

javascript
// 微应用路由配置
import { createRouter, createWebHistory } from 'vue-router';

function createRouter(history) {
  return createRouter({
    // 使用主应用传递的 history 或创建自己的
    history: history || createWebHistory('/micro-app/'),
    routes: [
      { path: '/', component: Home },
      { path: '/profile', component: Profile },
      { path: '/settings', component: Settings }
    ]
  });
}

主应用路由协调

javascript
// 主应用路由配置
const mainRoutes = [
  { path: '/', component: Home },
  { path: '/micro-app', component: () => import('./MicroAppContainer') },
  { path: '/about', component: About }
];

通信机制设计

1. 数据传递

通过 props 传递数据

javascript
// 主应用注册微应用时传递数据
registerMicroApps([
  {
    name: 'user-profile',
    entry: '//localhost:3001',
    container: '#container',
    activeRule: '/user',
    props: {
      // 用户信息
      userInfo: getUserInfo(),
      // 主题设置
      theme: getTheme(),
      // 回调函数
      onUserUpdate: (userData) => {
        // 处理用户信息更新
        updateUserInMainApp(userData);
      }
    }
  }
]);

通过全局状态通信

javascript
// 主应用状态管理
const { setGlobalState, onGlobalStateChange } = initGlobalState({
  user: { id: 1, name: 'John' },
  permissions: ['read', 'write'],
});

// 微应用中使用全局状态
export async function mount(props) {
  const { onGlobalStateChange, setGlobalState } = props;
  
  // 监听全局状态变化
  onGlobalStateChange((state, prev) => {
    if (state.user !== prev.user) {
      // 用户信息变化,更新微应用状态
      updateUserInterface(state.user);
    }
  }, true);
  
  // 修改全局状态
  const updateUserInfo = (newInfo) => {
    setGlobalState({
      user: { ...getGlobalState().user, ...newInfo }
    });
  };
  
  // 将更新函数传递给应用
  props.updateUserInfo = updateUserInfo;
}

2. 事件通信

自定义事件系统

javascript
// 微应用内部事件管理
class MicroAppEventEmitter {
  constructor(props) {
    this.props = props;
    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));
    }
    
    // 同时通知主应用
    if (this.props.onMicroEvent) {
      this.props.onMicroEvent({ event, data });
    }
  }
  
  off(event, callback) {
    if (this.events[event]) {
      const index = this.events[event].indexOf(callback);
      if (index > -1) {
        this.events[event].splice(index, 1);
      }
    }
  }
}

性能优化策略

1. 预加载优化

智能预加载

javascript
// 基于用户行为的预加载
let userBehaviorHistory = [];

// 记录用户行为
function recordUserBehavior(path) {
  userBehaviorHistory.push({
    path,
    timestamp: Date.now()
  });
  
  // 清理历史记录
  userBehaviorHistory = userBehaviorHistory.slice(-10);
}

// 预测可能访问的应用
function predictNextApp() {
  // 简单的预测算法
  if (userBehaviorHistory.length >= 2) {
    const lastPath = userBehaviorHistory[userBehaviorHistory.length - 1].path;
    const secondLastPath = userBehaviorHistory[userBehaviorHistory.length - 2].path;
    
    // 根据访问模式预测
    if (lastPath === '/order' && secondLastPath === '/product') {
      return 'payment'; // 可能会访问支付页面
    }
  }
  return null;
}

// 动态调整预加载策略
function adjustPrefetchStrategy() {
  const predictedApp = predictNextApp();
  if (predictedApp) {
    // 预加载预测的应用
    preloadApp(predictedApp);
  }
}

资源优化

javascript
// 微应用资源优化配置
export async function bootstrap() {
  // 预加载关键资源
  preloadCriticalAssets();
  
  // 懒加载非关键资源
  setTimeout(() => {
    import('./non-critical-module').then(module => {
      // 使用非关键模块
    });
  }, 0);
}

function preloadCriticalAssets() {
  // 预加载关键样式和脚本
  const criticalAssets = [
    '/css/critical.css',
    '/js/vendor.js'
  ];
  
  criticalAssets.forEach(asset => {
    const link = document.createElement('link');
    link.rel = 'preload';
    link.as = 'style';
    link.href = asset;
    document.head.appendChild(link);
  });
}

2. 缓存策略

应用实例缓存

javascript
// 应用实例缓存管理
class AppInstanceCache {
  constructor() {
    this.cache = new Map();
    this.maxCacheSize = 5; // 最大缓存数量
  }
  
  set(name, instance) {
    if (this.cache.size >= this.maxCacheSize) {
      // 移除最久未使用的实例
      const firstKey = this.cache.keys().next().value;
      this.delete(firstKey);
    }
    
    this.cache.set(name, {
      instance,
      lastAccessed: Date.now()
    });
  }
  
  get(name) {
    const cached = this.cache.get(name);
    if (cached) {
      cached.lastAccessed = Date.now();
      return cached.instance;
    }
    return null;
  }
  
  delete(name) {
    const cached = this.cache.get(name);
    if (cached && cached.instance) {
      // 正确卸载实例
      if (cached.instance.unmount) {
        cached.instance.unmount();
      }
    }
    this.cache.delete(name);
  }
  
  clear() {
    for (const [name, cached] of this.cache) {
      this.delete(name);
    }
  }
}

const appCache = new AppInstanceCache();

错误处理和监控

1. 错误边界

微应用错误边界

javascript
// Vue 微应用错误处理
export async function mount(props) {
  try {
    app = new Vue({
      router,
      store,
      render: h => h(App),
      errorCaptured(err, vm, info) {
        console.error('微应用组件错误:', err, info);
        
        // 上报错误
        reportError({
          type: 'component_error',
          error: err.message,
          stack: err.stack,
          component: vm?.$options.name,
          info
        });
        
        // 返回 false 阻止错误继续向上传播
        return false;
      }
    });
    
    app.$mount(props.container ? props.container.querySelector('#app') : '#app');
  } catch (error) {
    handleError(error, 'mount');
  }
}

function handleError(error, stage) {
  console.error(`微应用${stage}阶段错误:`, error);
  
  // 上报错误
  reportError({
    type: `micro_app_${stage}_error`,
    error: error.message,
    stack: error.stack,
    stage
  });
  
  // 显示错误页面
  const container = props.container || document.getElementById('app');
  container.innerHTML = `
    <div class="error-container">
      <h3>应用加载失败</h3>
      <p>请联系管理员或稍后重试</p>
      <button onclick="location.reload()">重新加载</button>
    </div>
  `;
}

2. 性能监控

应用性能监控

javascript
// 性能监控工具
class PerformanceMonitor {
  constructor() {
    this.metrics = {};
  }
  
  startTracking(appName) {
    this.metrics[appName] = {
      startTime: performance.now(),
      resources: [],
      interactions: []
    };
    
    // 监控资源加载
    if ('performance' in window) {
      performance.getEntriesByType('resource').forEach(resource => {
        this.metrics[appName].resources.push(resource);
      });
    }
  }
  
  endTracking(appName) {
    if (this.metrics[appName]) {
      const endTime = performance.now();
      this.metrics[appName].endTime = endTime;
      this.metrics[appName].totalTime = endTime - this.metrics[appName].startTime;
      
      // 上报性能数据
      this.reportPerformance(appName);
    }
  }
  
  reportPerformance(appName) {
    const metrics = this.metrics[appName];
    if (metrics) {
      // 发送性能数据到监控服务
      fetch('/api/performance', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          app: appName,
          totalTime: metrics.totalTime,
          resourceCount: metrics.resources.length,
          timestamp: Date.now()
        })
      });
    }
  }
}

const performanceMonitor = new PerformanceMonitor();

安全性考虑

1. 沙箱配置

安全的沙箱配置

javascript
// 主应用安全配置
start({
  sandbox: {
    // 启用严格的样式隔离
    strictStyleIsolation: true,
    // 启用实验性样式隔离(更安全)
    experimentalStyleIsolation: true,
    // 配置沙箱选项
    speedy: false, // 关闭快速模式以提高安全性
  },
  // 配置加载选项
  fetch: window.fetch, // 使用原生 fetch
});

2. 数据验证

输入验证

javascript
// 验证来自主应用的数据
function validateProps(props) {
  const { userInfo, permissions } = props;
  
  // 验证用户信息格式
  if (userInfo && typeof userInfo === 'object') {
    if (typeof userInfo.id !== 'number' || typeof userInfo.name !== 'string') {
      throw new Error('Invalid user info format');
    }
  }
  
  // 验证权限格式
  if (permissions && Array.isArray(permissions)) {
    if (!permissions.every(p => typeof p === 'string')) {
      throw new Error('Invalid permissions format');
    }
  }
  
  return true;
}

export async function mount(props) {
  try {
    validateProps(props);
    
    // 安全地使用 props
    app = new Vue({
      router,
      store: createStore(props.userInfo),
      render: h => h(App),
    });
    
    app.$mount(props.container ? props.container.querySelector('#app') : '#app');
  } catch (error) {
    console.error('Props validation failed:', error);
    throw error;
  }
}

部署和运维

1. 版本管理

微应用版本控制

javascript
// 版本检测和兼容性检查
async function checkMicroAppVersion(appName, requiredVersion) {
  try {
    const response = await fetch(`${getAppEntry(appName)}/version.json`);
    const versionInfo = await response.json();
    
    if (!isVersionCompatible(versionInfo.version, requiredVersion)) {
      console.warn(`微应用 ${appName} 版本不兼容: ${versionInfo.version} < ${requiredVersion}`);
      // 可以选择降级或提示更新
      return false;
    }
    
    return true;
  } catch (error) {
    console.error('版本检测失败:', error);
    return false;
  }
}

function isVersionCompatible(current, required) {
  // 简单的版本比较逻辑
  const currentParts = current.split('.').map(Number);
  const requiredParts = required.split('.').map(Number);
  
  for (let i = 0; i < requiredParts.length; i++) {
    if (currentParts[i] > requiredParts[i]) return true;
    if (currentParts[i] < requiredParts[i]) return false;
  }
  
  return true;
}

2. 灰度发布

渐进式部署

javascript
// 灰度发布控制
const GRAY_RELEASE_CONFIG = {
  'user-center': {
    enabled: true,
    percentage: 30, // 30% 用户访问新版本
    testUsers: ['admin', 'test'] // 指定测试用户
  }
};

function shouldLoadNewVersion(appName, user) {
  const config = GRAY_RELEASE_CONFIG[appName];
  if (!config || !config.enabled) {
    return true; // 默认加载新版本
  }
  
  // 检查是否为测试用户
  if (config.testUsers.includes(user.name)) {
    return true;
  }
  
  // 按百分比随机决定
  return Math.random() * 100 < config.percentage;
}

// 根据灰度配置选择应用版本
function getAppEntry(appName, user) {
  if (shouldLoadNewVersion(appName, user)) {
    return getNewVersionEntry(appName);
  } else {
    return getOldVersionEntry(appName);
  }
}

调试和开发工具

1. 开发时调试

调试工具集成

javascript
// 开发环境调试工具
if (process.env.NODE_ENV === 'development') {
  // 启用 qiankun 开发工具
  window.qiankunDevTools = {
    getMicroApps: () => window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__,
    getAppStatus: () => getMicroAppState(),
    reloadApp: (appName) => {
      // 重新加载指定微应用
      return loadMicroApp(
        getMicroAppConfig(appName),
        getMicroAppProps(appName)
      );
    }
  };
  
  // 添加调试信息到控制台
  console.log('qiankun dev tools enabled');
  console.log('Available commands: window.qiankunDevTools');
}

通过遵循这些最佳实践,您可以构建出更加稳定、高效和安全的基于 qiankun 的微前端应用。