微前端初体验-Qiankun框架

76 阅读3分钟

写在前面:接触前端开发也有几年了,最近难得有机会使用微前端:当前项目使用vue3,当前有个页面需要使用react组件,项目负责人建议使用react来做,那么这时候方案就来了,iframe和react-dom等也能实现,这不是想到微前端可以独立开发部署,于是乎搜索了下qiankun,教程都说没那么难,那么自己打算开始做一下实践了;

由于需要贴合实际使用场景,所以总结用VUE3+vite作为底座(主应用),vite+react为子应用;

首先是主应用部分: 1、创建vite+vue3的项目:npm create vite vue3-app --tempalte

2、安装依赖:npm i; 然后安装qiankun:npm i qiankun -S

3、需要在主应用中注册为微应用:在入口文件中引入qiankun、注册子应用、启动qiankun;

import {initGlobalState, registerMicroApps, start} from 'qiankun';
registerMicroApps([
  {
    name: 'react-sub-app', // app name registered
    entry: '//localhost:9000',
    container: '#react-app',
    activeRule: '/react-app',
  },
]);

// 启动qiankun
start(); 

4、在主应用模板中添加子应用的渲染容器

<div>
    React 子应用挂载点
    <div id="react-app"></div>
</div>

然后在子应用中: 1、创建vite+react的子项目:npm create vite react-sub-app --tempalte

2、安装依赖vite-plugin-qiankun: npm i vite-plugin-qiankun -S;

3、修改vite.config.js配置:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import qiankun from 'vite-plugin-qiankun'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    // react({
    //   jsxRuntime: 'classic', // 确保启用新的 JSX 转换
    // }), 
    qiankun('react-sub-app', {
      useDevMode: true
    })
  ],
  server: {
    port: 9000,
    // 允许跨域
    cors: true,
    // 允许其他地址访问
    host: '0.0.0.0',
    origin: 'http://localhost:9000', // 添加 origin
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  // 关键配置:明确设置构建目标
  build: {
    target: 'esnext',
    rollupOptions: {
      external: [], // 确保不排除任何必要的依赖
    }
  },
  define: {
    'process.env': {}
  },

  // 设置base,如果主应用是通过根路径下的某个路径来加载子应用,比如http://localhost:9000/react-sub-app,那么base设置为'/react-sub-app/'
  // base: '/react-sub-app/'
})

4、修改入口文件:

import { StrictMode } from 'react'
import React from 'react'; 
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import {renderWithQiankun, qiankunWindow} from 'vite-plugin-qiankun/dist/helper'

let root;

function render(props = {}) {
  const container = props.container ? props.container.querySelector('#root') : document.getElementById('root');
  root = ReactDOM.createRoot(container);
  root.render(
    <StrictMode>
      <App />
    </StrictMode>
  );
}

// 处理模块加载错误
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
  // 在 qiankun 环境中,等待主应用处理完模块加载
  // const originalError = console.error;
  // console.error = function(...args) {
  //   if (typeof args[0] === 'string' && args[0].includes('import-html-entry')) {
  //     return; // 忽略 qiankun 的模块加载错误
  //   }
  //   originalError.apply(console, args);
  // };
  
  // // 延迟渲染以确保环境稳定
  // setTimeout(() => {
  //   console.error = originalError;
  // }, 100);
  render();
}

renderWithQiankun({
  mount(props) {
    console.log('react app mounted');
    render(props);
    return Promise.resolve();
  },
  bootstrap() {
    console.log('react app bootstraped');
    return Promise.resolve();
  },
  unmount() {
    console.log('react app unmounted');
    if (root) {
      root.unmount();
      root = null;
    }
    return Promise.resolve();
  },
  update() {
    console.log('react app updated');
    return Promise.resolve();
  }
});

两个应用都顺利起来之后,通过主应用的访问地址后面添加激活的路由:/react-app,访问http://localhost:5173/react-app 最终可以在vue3项目中访问react项目。

第一版先写到这里;后续可以补充踩过的坑,选型原因等

问题一:报错Cannot use import statement outside a module

image.png

原因:@vitejs/plugin-react 在开发模式会注入 /@react-refresh 预热脚本(基于 ESModule),而 qiankunimport-html-entry 以普通脚本方式 eval 该片段,导致解析失败。

  • 解决:微应用开发模式下不启用 React 插件(或至少关闭 Fast Refresh),仅依赖 Vite 对 JSX 的基础处理;保留 vite-plugin-qiankunuseDevMode
    • 关闭 React 插件
    • 启用 qiankun 插件开发模式

问题二:React is not defined(移除 React 插件后的 JSX 转译)

  • 现象:进入子应用时报错:React is not defined,指向 JSX 渲染位置。
  • 原因:在不使用 @vitejs/plugin-react 的情况下,JSX 转译输出依赖 React.createElement,代码中未引入默认导入 React
  • 解决:显式加入默认导入。
    • 子应用入口:micro-react/src/main.jsx:1
    • 示例组件:micro-react/src/App.jsx:1