线上演示地址:React App
源码地址:https://github.com/Jiang-K-J/micro-app?tab=readme-ov-file (帮忙点个小星星)
主应用:react 18+
子应用:vite + vue3
子应用:react 18+
安装
- 主应用
$ yarn add qiankun # 或者 npm i qiankun -S
- 子应用(如果你的子应用不是vite构建的,你无需安装任何插件)
npm i vite-plugin-qiankun
搭建
在主应用中注册子应用
import { registerMicroApps, start } from 'qiankun';registerMicroApps([{name: 'react app', // 子应用的名称entry: '//localhost:7100', // 子应用运行的url和portcontainer: '#yourContainer', // 用于放置子应用显示的载体activeRule: '/sub-react', // 匹配的路由},{name: 'vue app',entry: '//localhost:3000',container: '#yourContainer',activeRule: '/sub-vue',},
]);start();
子应用配置
- vite子应用
import { createApp } from 'vue'
import App from './App.vue'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
import { router, abstractRouter } from './router';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'let app;
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {createApp(App).use(router).use(ElementPlus).mount('#app');
} else {renderWithQiankun({// 子应用挂载mount(props) {let routerInstance = null;console.log('props', props?.path);if (props?.path) {routerInstance = abstractRouter;} else {routerInstance = router;}app = createApp(App);// 使用 provide 将 props 传递给所有后代组件app.provide('qiankunProps', props); app.use(routerInstance).use(ElementPlus);app.mount(props.container.querySelector('#app'));if (props?.path) {routerInstance.push(props.path)}},// 只有子应用第一次加载会触发bootstrap() {console.log('vue app bootstrap');},// 更新update() {console.log('vue app update');},// 卸载unmount() {console.log('vue app unmount');app?.unmount();}});
}
- react子应用
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, MemoryRouter } from "react-router-dom";
import { QiankunContext } from "./QiankunContext.jsx";
import "./index.css";
import App from "./App";
import "./public-path"; // webpack子应用需要新增一个这样的文件,下方有说明
import "./a1.js";let root;
function render(props) {const { container,path } = props;const RouterWrapper = props?.path ? MemoryRouter : BrowserRouter;const dom = container? container.querySelector("#root"): document.getElementById("root");root = createRoot(dom);root.render(<RouterWrapper basename="/sub-react" initialEntries={path ? [path] : ["/"]}><QiankunContext.Provider value={props}><App mianProps={props} /></QiankunContext.Provider></RouterWrapper>);
}// 判断是否在qiankun环境下,非qiankun环境下独立运行
if (!window.__POWERED_BY_QIANKUN__) {render({});
}// 各个生命周期
// bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
export async function bootstrap() {console.log("react app bootstraped");
}// 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
export async function mount(props) {console.log("props from main framework", props);render(props);
}// 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
export async function unmount(props) {root.unmount();
}basename="/sub-react" 这个和你在主应用注册子应用中的activeRule要保持一直
webpack构建的子应用需要新增下面的文件,并在入口文件中进行导入
在 src
目录新增 public-path.js
:
if (window.__POWERED_BY_QIANKUN__) {__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
子应用配置文件修改
- webpack构建的应用
由于webpack构建的应用一般不会暴露webpack文件,我们这里可以下载 react-app-rewired 这个插件用于修改webpack配置,具体可以百度一下
const { name } = require("./package");module.exports = {webpack: (config) => {// 设置输出配置config.output.library = `${name}-[name]`;config.output.libraryTarget = "umd";config.output.chunkLoadingGlobal = `webpackJsonp_${name}`;return config;},devServer: (_) => {const config = _;config.headers = {"Access-Control-Allow-Origin": "*",};config.historyApiFallback = true;config.hot = false;config.watchContentBase = false;config.liveReload = false;return config;},
};
- vite构建的应用
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun';
export default defineConfig({base: '/sub-vue', // 和基座中配置的activeRule一致server: {port: 3000,cors: true,origin: 'http://localhost:3000' //你的实际运行地址},plugins: [vue(),qiankun('sub-vue', { // 配置qiankun插件useDevMode: true}),]
})
# 这里还需要配置下方那部分内容,具体怎样在vite中配置output,可以百度一下output: {library: `${name}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal},
具体配置可以参考官网文档:项目实践 - qiankun
建议:vite应用中base配置应该和实际线上地址保持一致,这样可以避免很多保持:
base: 'http://xxx:3000/sub-vue', // 和基座中配置的activeRule一致
部署
部署主要是nginx配置,没有别的操作
主应用
location / {add_header Cache-Control no-cache;index index.html;try_files $uri /index.html;}
子应用
# /sub-react 这个需要和activeRule保持一致即可location /sub-react {# 设置允许的跨域来源alias /web/qiankun/rf; # 指向静态文件目录index index.html;try_files $uri /index.html; # 注意这里的路径,仅需指向子应用的 `index.html`}location / {# 添加跨域头add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";add_header Access-Control-Allow-Headers "Content-Type, Authorization";if ($request_method = OPTIONS) {add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";add_header Access-Control-Allow-Headers "Content-Type, Authorization";return 204;}}