线上演示地址: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和port
container: '#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;
}
}