Skip to content
On this page

qiankun 常见问题与解决方案

安装和配置问题

1. 安装依赖问题

问题:qiankun 安装失败

错误信息npm install qiankun 失败或版本冲突

解决方案

bash
# 清理缓存后重新安装
npm cache clean --force
npm install qiankun --save

# 或使用 yarn
yarn add qiankun

# 检查版本兼容性
npm ls single-spa  # qiankun 基于 single-spa

问题:版本兼容性问题

错误信息Error: Cannot find module 'xxx'

解决方案

bash
# 检查 qiankun 版本要求
npm info qiankun peerDependencies

# 确保 Node.js 版本 >= 8
node --version

# 更新到兼容版本
npm install qiankun@latest

2. 构建配置问题

问题:微应用无法正常加载

错误信息Uncaught SyntaxError: Unexpected token '<'

解决方案

javascript
// webpack.config.js - 确保正确配置输出
module.exports = {
  output: {
    // 必须配置 library
    library: 'microApp',
    libraryTarget: 'umd',
    // 确保 publicPath 正确
    publicPath: 'http://localhost:3001/', // 微应用地址
  },
  devServer: {
    // 开发环境配置
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
    // 端口配置
    port: 3001,
  },
};

问题:样式丢失或冲突

错误信息:微应用样式未正确应用或影响主应用

解决方案

javascript
// 主应用中配置样式隔离
import { start } from 'qiankun';

start({
  sandbox: {
    // 启用严格的样式隔离
    strictStyleIsolation: true,
    // 或使用实验性样式隔离
    experimentalStyleIsolation: true,
  }
});

运行时问题

1. 生命周期问题

问题:微应用无法卸载

错误信息:切换应用时出现内存泄漏警告

解决方案

javascript
// 确保正确实现 unmount 生命周期
let app = null;
let routerInstance = null;
let eventListeners = [];

export async function mount(props) {
  const { container } = props;
  
  // 创建应用实例
  app = new Vue({
    router: createRouter(),
    store,
    render: h => h(App),
  });
  
  // 挂载到容器
  app.$mount(container ? container.querySelector('#app') : '#app');
  
  // 保存事件监听器
  eventListeners = [
    // 添加事件监听器到数组中
  ];
}

export async function unmount(props) {
  // 清理事件监听器
  eventListeners.forEach(cleanup => cleanup());
  eventListeners = [];
  
  // 销毁应用实例
  if (app) {
    app.$destroy();
    app.$el.innerHTML = '';
    app = null;
  }
  
  // 清理路由实例
  if (routerInstance) {
    routerInstance = null;
  }
}

问题:bootstrap 只执行一次

现象:微应用重新进入时没有执行 bootstrap

解决方案

javascript
// bootstrap 只在初始化时执行一次,后续直接调用 mount
let initialized = false;

export async function bootstrap(props) {
  if (!initialized) {
    // 初始化逻辑
    console.log('首次初始化');
    initialized = true;
    
    // 执行一次性初始化
    await initializeOnce();
  }
}

export async function mount(props) {
  // 每次挂载都执行的逻辑
  console.log('每次挂载执行');
  await setupApp(props);
}

2. 通信问题

问题:主应用和微应用通信失败

错误信息props.onGlobalStateChange is not a function

解决方案

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

// 必须在注册微应用之前初始化
const { onGlobalStateChange, setGlobalState } = initGlobalState({
  user: { name: 'admin' },
});

// 微应用:安全地使用通信方法
export async function mount(props) {
  // 安全检查
  if (typeof props.onGlobalStateChange === 'function') {
    props.onGlobalStateChange((state, prev) => {
      console.log('全局状态变化', state, prev);
    });
  }
  
  if (typeof props.setGlobalState === 'function') {
    props.setGlobalState({
      lastUpdate: Date.now(),
    });
  }
}

问题:跨应用数据传递失败

现象:微应用无法获取主应用传递的数据

解决方案

javascript
// 主应用:确保在注册时传递数据
registerMicroApps([
  {
    name: 'myApp',
    entry: '//localhost:3001',
    container: '#subapp-viewport',
    activeRule: '/app',
    // 传递数据
    props: {
      data: { message: 'Hello from main app' },
      onCallback: (data) => {
        console.log('收到微应用回调', data);
      }
    }
  }
]);

// 微应用:正确接收数据
export async function mount(props) {
  const { data, onCallback } = props;
  
  // 使用传递的数据
  console.log('收到的数据', data);
  
  // 调用回调函数
  if (typeof onCallback === 'function') {
    onCallback({ response: 'Hello from micro app' });
  }
}

路由问题

1. 路由冲突

问题:主应用和微应用路由冲突

现象:路由切换异常或无法正确匹配

解决方案

javascript
// 主应用路由配置
const mainRouter = new VueRouter({
  mode: 'history',
  base: '/main', // 设置基础路径
  routes: [
    { path: '/', component: Home },
    { path: '/app1', component: () => import('./MicroApp1') },
    { path: '/app2', component: () => import('./MicroApp2') },
  ]
});

// 微应用路由配置
export async function mount(props) {
  const { container, routerBase } = props;
  
  // 使用主应用传递的路由基础路径
  const microRouter = new VueRouter({
    mode: 'history',
    base: routerBase || '/micro-app', // 或使用默认路径
    routes: [
      { path: '/', component: Home },
      { path: '/profile', component: Profile },
    ]
  });
  
  app = new Vue({
    router: microRouter,
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

2. History 模式问题

问题:浏览器后退按钮异常

现象:点击浏览器后退按钮无法正常返回

解决方案

javascript
// 微应用中处理浏览器历史记录
export async function mount(props) {
  // 监听浏览器历史记录变化
  const unlisten = props.history.listen((location, action) => {
    console.log('路由变化', location, action);
  });
  
  // 在卸载时清理监听器
  window.__MICRO_APP_UNMOUNT__ = () => {
    unlisten(); // 清理历史记录监听器
  };
}

export async function unmount(props) {
  if (window.__MICRO_APP_UNMOUNT__) {
    window.__MICRO_APP_UNMOUNT__();
    delete window.__MICRO_APP_UNMOUNT__;
  }
  
  // 其他清理逻辑
  if (app) {
    app.$destroy();
    app.$el.innerHTML = '';
    app = null;
  }
}

样式和资源问题

1. 样式隔离问题

问题:微应用样式影响主应用

现象:微应用的 CSS 样式污染了主应用

解决方案

javascript
// 方案1:启用严格的样式隔离
start({
  sandbox: {
    strictStyleIsolation: true,
  }
});

// 方案2:使用 CSS 命名空间
// 在微应用中使用特定的 CSS 类名前缀
export async function mount(props) {
  const { container } = props;
  
  // 为微应用容器添加特定类名
  if (container) {
    container.classList.add('micro-app-container');
    container.classList.add('micro-app-' + props.name);
  }
}

问题:微应用样式不生效

现象:微应用的样式无法正确应用

解决方案

css
/* 使用更具体的选择器 */
.micro-app-container .my-component {
  /* 微应用样式 */
  color: blue;
}

/* 或使用 CSS Modules */
/* 在微应用中使用 CSS Modules */

2. 静态资源问题

问题:静态资源路径错误

错误信息Failed to load resource: the server responded with a 404

解决方案

javascript
// 微应用中正确处理静态资源路径
export async function mount(props) {
  const { container } = props;
  
  // 设置基础路径
  const basePath = props.basePath || '';
  
  // 动态设置资源路径
  const images = container.querySelectorAll('img');
  images.forEach(img => {
    if (img.src.startsWith('/static')) {
      img.src = basePath + img.src;
    }
  });
}

// 或在构建时配置 publicPath
// webpack.config.js
module.exports = {
  output: {
    publicPath: 'auto', // 自动检测 publicPath
    // 或
    publicPath: window.__POWERED_BY_QIANKUN__ ? '/micro-app/' : '/',
  },
};

性能问题

1. 加载性能问题

问题:微应用加载缓慢

现象:微应用首次加载时间过长

解决方案

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

// 或自定义预加载策略
start({
  prefetch: {
    criticalAppList: [
      { name: 'criticalApp', entry: '//localhost:3001' }
    ],
    idleAppList: [
      { name: 'idleApp', entry: '//localhost:3002' }
    ],
  }
});

// 微应用中优化资源加载
export async function bootstrap(props) {
  // 预加载关键资源
  const criticalResources = [
    '/css/critical.css',
    '/js/vendor.js'
  ];
  
  await Promise.all(criticalResources.map(loadResource));
}

function loadResource(url) {
  return new Promise((resolve, reject) => {
    const link = document.createElement('link');
    link.rel = 'preload';
    link.as = 'script';
    link.href = url;
    link.onload = resolve;
    link.onerror = reject;
    document.head.appendChild(link);
  });
}

2. 内存泄漏问题

问题:应用切换时内存泄漏

现象:长时间使用后内存占用持续增长

解决方案

javascript
// 完整的清理逻辑
let app = null;
let eventListeners = [];
let timers = [];
let observers = [];

export async function mount(props) {
  const { container } = props;
  
  // 创建应用
  app = new Vue({
    router,
    store,
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
  
  // 添加事件监听器到清理队列
  const handleClick = () => console.log('click');
  document.addEventListener('click', handleClick);
  eventListeners.push(() => document.removeEventListener('click', handleClick));
  
  // 添加定时器到清理队列
  const timer = setInterval(() => {
    // 定时任务
  }, 1000);
  timers.push(timer);
  
  // 添加观察器到清理队列
  const observer = new MutationObserver(() => {
    // 观察变化
  });
  observer.observe(document.body, { childList: true });
  observers.push(observer);
}

export async function unmount(props) {
  // 清理事件监听器
  eventListeners.forEach(cleanup => cleanup());
  eventListeners = [];
  
  // 清理定时器
  timers.forEach(timer => clearInterval(timer));
  timers = [];
  
  // 清理观察器
  observers.forEach(observer => observer.disconnect());
  observers = [];
  
  // 销毁应用
  if (app) {
    app.$destroy();
    app.$el.innerHTML = '';
    app = null;
  }
}

兼容性问题

1. 浏览器兼容性

问题:低版本浏览器不支持

错误信息Proxy is not defined

解决方案

javascript
// 降级到快照沙箱
start({
  sandbox: {
    type: 'snapshot', // 使用快照沙箱(不依赖 Proxy)
  }
});

// 或添加 Proxy polyfill
if (!window.Proxy) {
  // 加载 Proxy polyfill
  import('proxy-polyfill').then(polyfill => {
    window.Proxy = polyfill;
  });
}

2. 框架兼容性

问题:特定框架不兼容

现象:某些前端框架无法正常工作

解决方案

javascript
// 通用框架适配器
export async function mount(props) {
  const { container, framework } = props;
  
  switch (framework) {
    case 'vue2':
      app = new Vue({
        router,
        store,
        render: h => h(App),
      }).$mount(container.querySelector('#app'));
      break;
      
    case 'vue3':
      app = createApp(App);
      app.use(router);
      app.use(store);
      app.mount(container.querySelector('#app'));
      break;
      
    case 'react':
      app = ReactDOM.render(
        <App />,
        container.querySelector('#app')
      );
      break;
      
    default:
      // 默认处理
      console.warn('Unknown framework:', framework);
  }
}

调试技巧

1. 调试工具

使用浏览器调试

javascript
// 在控制台中检查 qiankun 状态
console.log(window.__POWERED_BY_QIANKUN__); // 检查是否在 qiankun 环境中

// 检查注册的应用
console.log(window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__);

// 手动触发应用加载
const { loadMicroApp } = require('qiankun');
loadMicroApp({
  name: 'test-app',
  entry: '//localhost:3001',
  container: '#test-container',
});

2. 日志记录

添加详细日志

javascript
// 日志记录工具
const logger = {
  log: (message, ...args) => console.log(`[qiankun] ${message}`, ...args),
  warn: (message, ...args) => console.warn(`[qiankun] ${message}`, ...args),
  error: (message, ...args) => console.error(`[qiankun] ${message}`, ...args),
};

// 在生命周期中添加日志
export async function mount(props) {
  logger.log('Mounting micro app', props.name);
  
  try {
    // 挂载逻辑
    app = new Vue({
      router,
      store,
      render: h => h(App),
    }).$mount(props.container.querySelector('#app'));
    
    logger.log('Micro app mounted successfully', props.name);
  } catch (error) {
    logger.error('Failed to mount micro app', props.name, error);
    throw error;
  }
}

生产环境问题

1. 部署问题

问题:生产环境微应用无法加载

解决方案

javascript
// 生产环境配置
const isProduction = process.env.NODE_ENV === 'production';
const domain = isProduction ? 'https://cdn.example.com' : 'http://localhost:3001';

// 微应用构建配置
module.exports = {
  output: {
    library: 'microApp',
    libraryTarget: 'umd',
    publicPath: isProduction ? domain + '/' : 'http://localhost:3001/',
  },
  devServer: {
    headers: isProduction ? {} : {
      'Access-Control-Allow-Origin': '*',
    },
  },
};

2. CDN 配置

问题:CDN 资源加载问题

解决方案

javascript
// 主应用中配置微应用入口
const microApps = [
  {
    name: 'cdnApp',
    entry: isProduction 
      ? 'https://cdn.example.com/micro-app/' 
      : '//localhost:3001',
    container: '#subapp-viewport',
    activeRule: '/cdn-app',
  }
];

通过了解和应用这些解决方案,可以有效处理 qiankun 微前端开发中的常见问题。