Skip to content
On this page

qiankun 高级特性

沙箱机制详解

1. JS 沙箱

qiankun 提供了多种 JS 沙箱实现方式:

快照沙箱(SnapshotSandbox)

适用于不支持 Proxy 的低版本浏览器:

javascript
// 在不支持 Proxy 的环境中自动降级
start({
  sandbox: {
    experimentalStyleIsolation: true,
  }
});

代理沙箱(LegacySandbox)

基于 Proxy 实现的沙箱机制:

javascript
// 代理沙箱配置
start({
  sandbox: {
    // 默认使用代理沙箱
    type: 'legacy',
    // 指定要保护的全局变量
    patchers: [
      function(window) {
        // 自定义补丁
        return function() {
          // 恢复操作
        };
      }
    ]
  }
});

2. 样式隔离

严格的样式隔离

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

在这种模式下,qiankun 会为每个微应用的样式添加特定的属性选择器,从而实现样式隔离。

实验性样式隔离

javascript
start({
  sandbox: {
    experimentalStyleIsolation: true,
  }
});

这种模式下,qiankun 会将微应用的 DOM 结构包裹在一个特殊的容器中,实现更严格的样式隔离。

生命周期管理

1. 完整生命周期钩子

javascript
// 自定义生命周期钩子
registerMicroApps([
  {
    name: 'app1',
    entry: '//localhost:3001',
    container: '#container',
    activeRule: '/app1',
    // 自定义加载行为
    loader: (loading) => {
      if (loading) {
        // 显示加载状态
        showLoading();
      } else {
        // 隐藏加载状态
        hideLoading();
      }
    }
  }
], {
  // 全局生命周期钩子
  beforeLoad: async (app) => {
    console.log('应用加载前', app.name);
    return app;
  },
  beforeMount: async (app) => {
    console.log('应用挂载前', app.name);
    return app;
  },
  afterMount: async (app) => {
    console.log('应用挂载后', app.name);
    return app;
  },
  beforeUnmount: async (app) => {
    console.log('应用卸载前', app.name);
    return app;
  },
  afterUnmount: async (app) => {
    console.log('应用卸载后', app.name);
    return app;
  }
});

2. 微应用生命周期

微应用需要导出以下生命周期函数:

javascript
// 微应用入口文件
let app = null;

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子
 */
export async function bootstrap(props) {
  console.log('微应用启动', props);
}

/**
 * 应用每次进入都会调用 mount 方法
 */
export async function mount(props) {
  console.log('微应用挂载', props);
  
  // 获取主应用传递的属性
  const { container, onGlobalStateChange, setGlobalState } = props;
  
  // 初始化应用
  app = new Vue({
    router,
    store,
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

/**
 * 应用每次切出/卸载都会调用 unmount 方法
 */
export async function unmount(props) {
  console.log('微应用卸载', props);
  
  // 销毁应用实例
  if (app) {
    app.$destroy();
    app.$el.innerHTML = '';
    app = null;
  }
}

/**
 * 可选的 update 钩子,仅使用 loadMicroApp 方式加载微应用时会调用
 */
export async function update(props) {
  console.log('微应用更新', props);
}

通信机制

1. 主应用向微应用传递数据

javascript
// 主应用注册微应用时传递数据
registerMicroApps([
  {
    name: 'app1',
    entry: '//localhost:3001',
    container: '#container',
    activeRule: '/app1',
    props: {
      // 传递给微应用的数据
      userName: 'admin',
      theme: 'dark',
      onMainEvent: (data) => {
        // 主应用提供的回调函数
        console.log('来自主应用的事件', data);
      }
    }
  }
]);

2. 微应用访问主应用数据

javascript
// 微应用中接收主应用传递的数据
export async function mount(props) {
  const { container, userName, theme, onMainEvent } = props;
  
  // 使用传递的数据
  console.log('用户名:', userName);
  console.log('主题:', theme);
  
  // 调用主应用提供的方法
  onMainEvent({ message: '来自微应用的消息' });
  
  // 设置主应用提供的状态变更监听器
  if (props.onGlobalStateChange) {
    props.onGlobalStateChange((state, prev) => {
      console.log('全局状态变化', state, prev);
    }, true); // true 表示立即触发一次
  }
}

3. 全局状态管理

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

const { onGlobalStateChange, setGlobalState, getGlobalState } = initGlobalState({
  user: { name: 'admin', id: 1 },
  theme: 'light',
  language: 'zh-CN'
});

// 监听全局状态变化
onGlobalStateChange((state, prev) => {
  console.log('全局状态变化', state, prev);
}, true);

// 微应用中使用全局状态
export async function mount(props) {
  // 从 props 中获取状态管理方法
  const { onGlobalStateChange, setGlobalState, getGlobalState } = props;
  
  // 监听状态变化
  onGlobalStateChange((state, prev) => {
    console.log('微应用监听到状态变化', state, prev);
  });
  
  // 修改全局状态
  setGlobalState({
    user: { ...getGlobalState().user, lastLogin: Date.now() }
  });
}

预加载策略

1. 默认预加载

javascript
start({
  prefetch: true, // 开启预加载
});

2. 自定义预加载

javascript
start({
  prefetch: ['app1', 'app2'], // 预加载指定应用
});

// 或者更复杂的预加载策略
start({
  prefetch: {
    criticalAppList: [
      { name: 'criticalApp', entry: '//localhost:3001' }
    ],
    idleAppList: [
      { name: 'idleApp', entry: '//localhost:3002' }
    ],
  }
});

// 自定义预加载函数
start({
  prefetch: (apps) => {
    // 自定义预加载逻辑
    return apps.filter(app => app.status !== 'failed');
  }
});

动态加载微应用

1. 使用 loadMicroApp

javascript
import { loadMicroApp } from 'qiankun';

// 动态加载微应用
const microApp = await loadMicroApp(
  {
    name: 'dynamicApp',
    entry: '//localhost:3003',
    container: '#dynamic-container',
  },
  {
    sandbox: {
      strictStyleIsolation: true,
    },
    props: {
      data: 'from parent'
    }
  }
);

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

// 卸载微应用
await microApp.unmount();

2. 条件加载

javascript
// 根据条件动态注册微应用
async function registerConditionalApp(userRole) {
  if (userRole === 'admin') {
    registerMicroApps([
      {
        name: 'adminPanel',
        entry: '//localhost:3004',
        container: '#admin-container',
        activeRule: '/admin',
      }
    ]);
  }
}

错误处理

1. 全局错误处理

javascript
// 捕获微应用错误
window.addEventListener('error', (e) => {
  console.error('微应用运行时错误:', e);
  // 可以添加错误上报逻辑
});

window.addEventListener('unhandledrejection', (e) => {
  console.error('微应用未处理的 Promise 错误:', e);
});

// qiankun 提供的错误处理
start({
  error: (error, app) => {
    console.error('qiankun 错误:', error, app);
  }
});

2. 微应用错误处理

javascript
// 微应用中处理错误
export async function mount(props) {
  try {
    // 应用初始化逻辑
    app = new Vue({
      router,
      store,
      render: h => h(App),
    }).$mount(props.container ? props.container.querySelector('#app') : '#app');
  } catch (error) {
    console.error('微应用挂载失败:', error);
    // 可以通知主应用错误状态
    if (props.onError) {
      props.onError(error);
    }
  }
}

性能优化

1. 资源预加载

javascript
// 预加载微应用资源
start({
  prefetch: true,
  sandbox: {
    // 使用沙箱提高安全性
    strictStyleIsolation: true,
  }
});

2. 懒加载配置

javascript
// 配置懒加载
const lazyLoadApp = (appName, appConfig) => {
  return new Promise((resolve) => {
    // 检查是否已加载
    if (!window.loadedApps) {
      window.loadedApps = new Set();
    }
    
    if (window.loadedApps.has(appName)) {
      resolve(appConfig);
      return;
    }
    
    // 首次加载时添加到已加载集合
    window.loadedApps.add(appName);
    resolve(appConfig);
  });
};

3. 缓存策略

javascript
// 自定义缓存策略
start({
  sandbox: {
    // 沙箱缓存
    experimentalStyleIsolation: true,
  }
});

// 微应用级别的缓存
const appCache = new Map();

export async function mount(props) {
  const cacheKey = props.container;
  
  if (appCache.has(cacheKey)) {
    // 使用缓存的实例
    app = appCache.get(cacheKey);
    app.$mount(cacheKey);
  } else {
    // 创建新实例并缓存
    app = new Vue({
      router,
      store,
      render: h => h(App),
    });
    app.$mount(cacheKey);
    appCache.set(cacheKey, app);
  }
}

安全性考虑

1. XSS 防护

javascript
// 确保内容安全策略
start({
  sandbox: {
    // 启用样式隔离防止 CSS XSS
    strictStyleIsolation: true,
  }
});

2. 数据验证

javascript
// 验证来自主应用的数据
export async function mount(props) {
  const { userData } = props;
  
  // 验证数据格式
  if (userData && typeof userData === 'object') {
    // 安全处理数据
    processUserData(userData);
  }
}

通过这些高级特性,您可以更好地控制和优化基于 qiankun 的微前端架构,实现更复杂和安全的应用集成。