qiankun接入 react + vite 项目

148 阅读4分钟

注意:永远不要用 vite 开发服务器作为微前端子应用的 entry

微前端子应用必须是 构建后的静态资源(纯 HTML + JS + CSS)。

注意:vite.config.ts中的base路径必须是相对路径

遇到的问题1

错误信息:

error occurs while executing normal script 
<script type="module">
import { injectIntoGlobalHook } from "/@react-refresh";
...
</script>

错误原因:

vite 开发服务器(vite dev)会自动注入 HMR(热更新)脚本,如:

<script type="module">
  import { injectIntoGlobalHook } from "/@react-refresh";
  ...
</script>

但 qiankun 在加载子应用的 HTML 的时候,会把整个

最简单的解决方式

vite.config.ts中增加这个,不执行这个报错依赖

plugins: [
    react({
      fastRefresh: false // 禁用 React Refresh
    })
  ],

解决方案1:先构建,再部署静态资源

步骤1:构建 Vite 项目

cd your-vite-react-app
npm run build  # 生成 dist/ 目录

步骤2:本地启动静态服务器(模拟生产环境)

npx serve -s dist -l 3001

这样 http://localhost:3001 返回的是 纯静态 HTML/JS/CSS,无 HMR 脚本

步骤3:主应用注册构建后的地址

{
  name: 'react-vite-app',
  entry: '//localhost:3001', // ← 指向静态服务器
  container: '#container',
  activeRule: '/vite'
}

解决方案2:坚持要在 「开发环境」调试微前端 + Vite 子应用

目前 qiankun 官方不支持直接加载 Vite dev server,但有 workaround

手动提供一个「纯净入口JS」

步骤1:创建 src/micro-entry.js
export { bootstrap, mount, unmount } from './micro-app';
步骤2:修改 vite.config.ts,增加一个构建目标
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    lib: {
      entry: 'src/micro-entry.ts', // ← 关键
      name: 'ReactViteApp',
      formats: ['umd'],
      fileName: 'micro-app',
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
});
步骤3:添加构建脚本
// package.json
"scripts": {
  "build:micro": "vite build"
}
步骤4:运行构建并启动静态服务
npm run build:micro
npx serve -s dist -l 3001
步骤5:主应用注册 JS 入口
{
  name: 'react-vite-app',
  entry: '//localhost:3001/micro-app.umd.js', // ← 直接加载 JS
  container: '#container',
  activeRule: '/vite'
}

遇到的问题2

错误信息

Failed to load module 
script: Expected a JavaScript-or-Wasm 
module script but the server responded with a 
MIME type of "text/html". Strict MIME type checking 
is enforced for module
scripts per HTML spec.

错误原因

子应用react19 + vite5的项目。

由于这样的项目无法正常使用vite的开发服务器进行微应用开发与调试。

解决方案

使用打包,然后通过静态服务器的形式进行调试与开发

pnpm build

// 启动静态服务器
npx serve -s dist -l 3001

遇到的问题3

错误信息

application 'my-react-demo' died in status LOADING_SOURCE_CODE: [qiankun]: You need to export lifecycle functions in my-react-demo entry
Error: [qiankun]: You need to export lifecycle functions in my-react-demo entry
    at getLifecyclesFromExports (http://localhost:3000/static/js/bundle.js:31610:9)

错误原因

qiankun加载了子应用,但是没有找到生命周期函数。

你使用的是 标准 Vite React 应用构建模式(非 UMD),而 qiankun 默认期望子应用 导出一个包含生命周期的对象

但在标准 HTML 入口模式下,qiankun 会尝试从全局变量或模块导出中查找生命周期函数。如果你没正确暴露它们,就会报这个错。

解决方案

使用全局window进行暴露生命周期函数

const root = createRoot(document.getElementById('root')!)
if(window.__POWERED_BY_QIANKUN__) {
  window.myReactDemo = {
    bootstrap: async () => {
      console.log('react app bootstraped');
    },
    mount: async (props) => {
      render(props);
    },
    unmount: async () => {
      root.unmount();
    },
  }
}

遇到的问题4

错误信息

加载子应用成功后,子应用样式丢失,控制台 network 显示已经加载 css文件。

错误原因

子应用的DOM挂载位置错误:子应用的 React 渲染容器( #root )不在 qiankun 注入样式的“作用域”内

  1. qiankun 创建一个 div(带 [data-qiankun="myReactDemo"])并插入到 #container
  2. 你的子应用 mount 函数中
const domContainer = props.container.querySelector('#root')

→ 但 props.container 是 qiankun 创建的沙箱 div → 它内部 没有 #root 元素!

所以你实际渲染到了 主文档的 #root(如果存在),或者渲染失败。

而 css 规则被重写为

[data-qiankun="myReactDemo"] .some-class { ... }

但你的 DOM 不在 [data-qiankun=...] 内部 → 样式不匹配 → 看起来没样式

解决方案

在子应用的 mount 函数中,重新创建节点,塞一个div#root的节点

function async mount(props) {
  let container = props.container;

      // 如果容器内没有 #root,就创建一个
      if (!container.querySelector('#root')) {
        const rootEl = document.createElement('div');
        rootEl.id = 'root';
        container.appendChild(rootEl);
      }

      const domContainer = container.querySelector('#root')!;
      const root = ReactDOM.createRoot(domContainer);
      root.render(<App />);
}

这样的DOM结构就被更改为

<div id="container">
  <div data-qiankun="myReactDemo">
    <div id="root"> <!-- 你的 App 在这里 --> </div>
  </div>
</div>

而css被重写为

[data-qiankun="myReactDemo"] .header { ... }