极简实战:React + Vue 微前端(Qiankun + Vite)

✨ 微前端实战:React 主应用 + Vue 子应用

微前端架构将大型应用拆解为独立开发、部署的子应用,极大提升了复杂系统的可维护性。本文将手把手教你使用 Qiankun 框架,在 Vite 构建的 React 18 主应用中集成 Vue 3 子应用。


🛠️ 一、主应用 (React 18 + Vite):搭好舞台

主应用就像个"大舞台",负责调度和管理各个"演员"(子应用)。

  1. 请来"管家" Qiankun

    bash 复制代码
    npm install qiankun --save
    # 或者 yarn add qiankun
  2. 登记"演员"信息 & 启动舞台 在 React 主应用的启动文件(通常是 main.jsxApp.jsx)里操作:

    javascript 复制代码
    import { registerMicroApps, start } from 'qiankun';
    
    // 告诉 Qiankun 有哪些子应用可以上台表演
    registerMicroApps([
      {
        name: 'vue3-module',  // 给子应用起个唯一艺名
        entry: '//localhost:5500', // 子应用开发时在哪候场(开发服务器地址)
        container: '#vue-app-container', // 舞台上哪个区域给这个演员(DOM元素ID)
        activeRule: '/vue-module', // 什么信号(路由)一响,就该他上场了
        props: {  // 给演员的初始道具(数据)
          greeting: 'Hello from React Boss!',
          userRole: 'admin',
        },
      },
    ]);
    
    // 灯光师、音响师就位,舞台启动!
    start({
      sandbox: {
        experimentalStyleIsolation: true, // 重要!给演员单独化妆间(样式隔离),避免串妆
      },
    });

    💡 贴心提示:

    • activeRule: 主应用的路由(比如用了 react-router-dom)匹配到这个路径时,就召唤对应的子应用。
    • experimentalStyleIsolation: true: 强烈建议开启。这相当于给子应用套了个"透明玻璃房"(Shadow DOM),它们的 CSS 就不会跑出来把主应用或者其他子应用的页面搞乱。
  3. 给演员留好位置 (路由配置 - React Router v6 示例) 确保主路由知道把 /vue-module 开头的请求交给子应用:

    javascript 复制代码
    import { BrowserRouter, Routes, Route } from 'react-router-dom';
    
    function MainApp() {
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/" element={<HomePage />} />
            {/* 这里就是留给 Vue 子应用的专属区域! */}
            <Route path="/vue-module/*" element={<div id="vue-app-container" />} />
          </Routes>
        </BrowserRouter>
      );
    }

🎭 二、子应用 (Vue 3 + Vite):演员准备登场

Vue 子应用是个"独立演员",但要学会在 Qiankun 的舞台上表演。

  1. 装上"舞台适配器"

    bash 复制代码
    npm install vite-plugin-qiankun --save-dev
    # 或者 yarn add vite-plugin-qiankun -D
  2. 配置"化妆间"(vite.config.js)

    javascript 复制代码
    import { defineConfig } from 'vite';
    import vue from '@vitejs/plugin-vue';
    import qiankun from 'vite-plugin-qiankun'; // 引入适配器
    
    export default defineConfig({
      plugins: [
        vue(),
        qiankun('vue3-module', { // ⚠️ 艺名必须和主应用登记的一模一样!
          useDevMode: true // 开发模式也要能上台排练
        })
      ],
      server: {
        port: 5500, // ⚠️ 候场地址端口,必须和主应用 `entry` 一致
        origin: 'http://localhost:5500' // 确保资源能找到回家的路
      },
      base: process.env.NODE_ENV === 'production'
        ? '/path/to/your/vue-subapp/' // 正式演出时的后台路径
        : '/', // 排练时就在后台门口
    });

    🚨 关键警报:

    • qiankun('vue3-module', ...): 这里的 'vue3-module' 必须、必须、必须 和主应用 registerMicroApps 里的 name 完全一致!不然对不上号。
    • base: 这是最容易栽跟头的地方! 开发环境设为 '/',生产环境必须是你子应用最终部署在服务器上的相对路径(相对于主应用的域名)。配错了,图片、JS、CSS 全找不到!
  3. 学会"登台谢幕"(改造 main.js) 让 Vue 应用知道自己是独立演出还是在 Qiankun 的大舞台上:

    javascript 复制代码
    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router'; // 子应用自己的路由
    import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
    
    let vueApp = null; // 保存 Vue 应用实例
    
    // 独立表演时的剧本
    function renderStandaloneApp(container = null) {
      vueApp = createApp(App);
      vueApp.use(router); // 挂载自己的路由、状态管理等
      // ... 其他插件
      vueApp.mount(container ? container.querySelector('#app') : '#app'); // 挂载到指定或默认位置
    }
    
    // 判断:现在是独立演出吗?
    if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
      renderStandaloneApp(); // 是,按独立方式启动
    }
    
    // Qiankun 舞台的生命周期钩子:演员要遵守舞台规则
    renderWithQiankun({
      // 舞台导演喊"上场!"
      mount(props) {
        console.log('🎬 Vue子应用收到道具:', props); // 能看到主应用给的道具(props)
        renderStandaloneApp(props.container); // 把自己挂载到舞台导演指定的容器里
        // 通常这里也会初始化通信监听
      },
      // 第一次上场前准备 (可空)
      bootstrap() {
        console.log('🎬 Vue子应用准备上场...');
      },
      // 导演要求临时调整表演 (可空)
      update(props) {
        console.log('🎬 Vue子应用收到新剧本:', props);
      },
      // 导演喊"下场!"
      unmount() {
        console.log('🎬 Vue子应用谢幕...');
        vueApp?.unmount(); // 把自己卸载干净
        vueApp = null; // 清空实例
      },
    });

    🎭 演员修养:

    • qiankunWindow: 用它判断是在独立环境还是 Qiankun 舞台环境。
    • renderWithQiankun: 告诉 Qiankun 导演:"这是我的上场(mount)、下场(unmount)方法,您随时调用"。
    • mount(props): props.container 是导演递过来的话筒支架(挂载点 DOM 元素),props 里还有导演给的道具和通信工具。
    • 资源路径: 再次强调 base 配置正确的重要性!所有相对路径资源(./assets/logo.png)都依赖它。

📣 三、主应用和子应用"对讲机":通信

舞台上的演员需要交流。Qiankun 提供了 initGlobalState 这个"对讲机系统"。

  1. 主应用:安装并管理对讲机

    javascript 复制代码
    // 主应用某处 (e.g., src/utils/qiankunState.js)
    import { initGlobalState } from 'qiankun';
    
    // 初始化对讲机公共频道和默认消息
    const initialState = {
      theme: 'light-mode',
      currentProjectId: 123,
      notifications: []
    };
    const globalActions = initGlobalState(initialState);
    
    // 主应用自己也要听听公共频道
    globalActions.onGlobalStateChange((newState, oldState) => {
      console.log('主应用监听到:', newState, '之前是:', oldState);
      // 根据消息更新主应用自己的状态或UI (比如换主题)
    });
    
    // 主应用发广播 (e.g., 用户切换了主题)
    function switchAppTheme(newTheme) {
      globalActions.setGlobalState({
        ...globalActions.getGlobalState(), // 先拿当前所有状态
        theme: newTheme                   // 只更新 theme 字段
      });
    }
    
    // 把 globalActions 导出去,哪里需要发广播哪里引入
    export { globalActions };
  2. 子应用:加入公共频道,收听和发言 在子应用 mount 时拿到对讲机:

    javascript 复制代码
    renderWithQiankun({
      mount(props) {
        // ... 挂载逻辑
        // 1. 领一个对讲机耳机,收听公共频道
        props.onGlobalStateChange(
          (newState, oldState) => {
            console.log('👂 Vue子应用听到:', newState);
            // 根据消息更新子应用内部状态 (比如用 Pinia/Vuex 存 theme)
            if (newState.theme !== oldState?.theme) {
              switchThemeLocally(newState.theme); // 本地切换主题
            }
          },
          true // true 表示立刻用当前状态触发一次上面的回调
        );
    
        // 2. 子应用也可以发广播 (但只能更新主应用定义好的那些"话题")
        function updateProjectStatus(status) {
          props.setGlobalState({
            currentProjectStatus: status // 只能更新 initialState 里已有的一级属性!
          });
        }
      },
      // ... 其他生命周期
    });

    📡 通信规则:

    • 主控权在主应用: 主应用初始化状态和对讲机系统。
    • 子应用"有限发言权": 子应用只能修改 全局状态对象中主应用已经预先定义好 的一级属性(比如 theme, currentProjectId)。它不能自己发明一个新的一级属性广播出去。
    • 记得"摘耳机": Qiankun 在子应用下场(unmount)时会自动帮它关掉监听(offGlobalStateChange),一般无需子应用自己操作。

四、必看注意事项

  1. 名称一致性 :主/子应用的 name 必须完全匹配
  2. base 配置:子应用生产环境需设置正确部署路径
  3. 样式隔离 :始终开启 experimentalStyleIsolation
  4. 路由冲突:确保主应用路由不拦截子应用路径
  5. 部署优化:生产环境需配置 CDN 和 CORS

资源直达

相关推荐
533_1 分钟前
[echarts] 更新数据
前端·javascript·echarts
excel2 分钟前
理解 JavaScript 中的迭代器协议与中断行为:for...of vs for...in
前端
幻雨様4 分钟前
UE5多人MOBA+GAS 番外篇:同时造成多种类型伤害,以各种属性值的百分比来应用伤害(版本二)
java·前端·ue5
讨厌吃蛋黄酥8 分钟前
利用Mock实现前后端联调的解决方案
前端·javascript·后端
zzywxc78730 分钟前
在处理大数据列表渲染时,React 虚拟列表是提升性能的关键技术,但在实际实现中常遇到渲染抖动和滚动定位偏移等问题。
前端·javascript·人工智能·深度学习·react.js·重构·ecmascript
Hello.Reader1 小时前
Rust → WebAssembly 的性能剖析全指南
前端·rust·wasm
前端小巷子1 小时前
Vue 2 Diff 算法
前端·vue.js·面试
奕辰杰5 小时前
关于npm前端项目编译时栈溢出 Maximum call stack size exceeded的处理方案
前端·npm·node.js
JiaLin_Denny7 小时前
如何在NPM上发布自己的React组件(包)
前端·react.js·npm·npm包·npm发布组件·npm发布包
路光.8 小时前
触发事件,按钮loading状态,封装hooks
前端·typescript·vue3hooks