本文例子是使用qiankun框架以react项目为主应用,集成一个react微应用和一个vue微应用
前端环境-nodejs版本20,react18
主应用 react18+CRA
子应用A react18+CRA
子应用B vue3+vite
首先需要CRA来快速创建一个react主应用 npx create-react-app my-main-app
第一步
主应用配置
安装qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
第二步
//index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([{name: 'reactapp',entry: '//localhost:3001',container: '#container',activeRule: '/app-react',},
//如果有多个微应用//{// name: 'vueapp',// entry: '//localhost:8080',// container: '#container',// activeRule: '/app-vue',//},
]);
// 启动 qiankun
start();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />
);
reportWebVitals();
第三步
注意 activeRule: '/app-react',配置的是访问子应用的路由,entry: '//localhost:3001',则是访问地址,在你的index.html中添加 <div id="container"></div> 这是子应用的容器
最后 npm start即可
然后快速创建一个react微应用 npx create-react-app reactapp
安装路由 npm install --save react-router-dom
微应用这里是需要对webpack进行配置,然而create-creact-app 项目,如果需要手动修改配置,需先 npm run eject 弹出配置,这个过程是不可逆的,所以推荐使用第三方工具去修改。react-app-rewired 的作用是用来帮助你重写 react 脚手架配置,qiankun官方文档要求使用@rescripts/cli或者react-app-rewired,本文例子使用的是react-app-rewired
react-app-rewired 是一个用于自定义 create-react-app 项目配置的工具。create-react-app 是一个流行的 React 应用开发工具,它提供了一个零配置的开发环境,但有时候开发者可能需要自定义一些配置,比如添加新的 Webpack 插件、修改 Babel 配置等。
react-app-rewired 允许你在不 eject(弹出)项目的情况下修改 create-react-app 的配置。这意味着你可以保持 create-react-app 的便利性,同时又能根据需要自定义配置。
微应用配置
第一步
安装qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
安装react-app-rewired
react-app-rewired@2.x版本需要搭配customize-cra使用。
customize-cra的作用是帮助你自定义 react 脚手架 2.x 版本配置
npm i react-app-rewired customize-cra --save-dev
第二步
入口文件 index.js 修改,为了避免根 id #root 与其他的 DOM 冲突,需要限制查找范围。
//index.js
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
function render(props) {const { container } = props;
const root = ReactDOM.createRoot(document.getElementById('root'));root.render(<BrowserRouter basename={window.__POWERED_BY_QIANKUN__? '/app-react' : '/'}><App /></BrowserRouter>,container? container.querySelector('#root') : document.querySelector('#root'));
}if (!window.__POWERED_BY_QIANKUN__) {render({});
}export async function bootstrap() {console.log('[react16] react app bootstraped');
}export async function mount(props) {console.log('[react16] props from main framework', props);render(props);
}export async function unmount(props) {const { container } = props;ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}
第三步
在根目录下新建文件config-overrides.js文件
//config-overrides.js
const { override } = require('customize-cra');
const { name } = require('./package');
module.exports = {webpack: override((config, env) => {config.output.library = `${name}-[name]`;config.output.libraryTarget = 'umd';// webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobalconfig.output.chunkLoadingGlobal = `webpackJsonp_${name}`; config.output.globalObject = 'window';return config;},),devServer: override((_) => {const config = _;config.headers = {'Access-Control-Allow-Origin': '*',};config.historyApiFallback = true;config.hot = false;config.watchContentBase = false;config.liveReload = false;return config;},),};
第四步
修改 package.json 文件
{// ..."scripts": {"start": "react-app-rewired start","build": "react-app-rewired build","test": "react-app-rewired test","eject": "react-scripts eject"},// ...
}
至此,已经集成了一个react微应用
react主应用 localhost:3000 my-main-app
react微应用 localhost:3001 reactapp
在主应用访问子应用路由 /app-react 在主应用index配置中一定要对应上
下面是集成完毕效果图
接下来准备集成第二个微应用vueapp
还是先创建一个vueapp应用 vue3+vite
根据vue官网文档进行操作
https://cn.vuejs.org/guide/quick-start.html
这里使用 pnpm create vue@latest
选好配置后 pnpm i 安装依赖 然后 pnpm dev启动项目
qiankun官网配置都是基于webpack,目前为止官方还没有支持vite,直接使用的话只能解决build后的集成,经过一系列的尝试,最终选择使用了 vite-plugin-qiankun 插件接入
安装依赖 npm i vite-plugin-qiankun
在 vite.config.ts 中添加插件
import { fileURLToPath, URL } from "node:url";
import qiankun from "vite-plugin-qiankun";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import vueDevTools from "vite-plugin-vue-devtools";
export default defineConfig({base: "http://localhost:5173",server: {port: 5173,cors: true,origin: "http://localhost:5173",headers: {"Access-Control-Allow-Origin": "*",},},plugins: [vue(),vueJsx(),vueDevTools(),qiankun("flow-graph", {useDevMode: true,}),],resolve: {alias: {"@": fileURLToPath(new URL("./src", import.meta.url)),},},
});
main.ts 中添加qiankun的生命周期钩子,同样是 mount 时加载,unmount 时销毁
import "./assets/main.css";
import { createApp } from "vue";
import { createWebHistory, createRouter } from "vue-router";
import {renderWithQiankun,qiankunWindow,
} from "vite-plugin-qiankun/dist/helper";
import HomeView from "./views/HomeView.vue";
import App from "./App.vue";
const routes = [{ path: "/", component: HomeView },{path: "/about",name: "about",component: () => import("./views/AboutView.vue"),},
];
const router = createRouter({history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? "/app-vue" : "/"),routes,
});
创建并挂载 Vue 应用
// 创建并挂载 Vue 应用
let app: VueApp<Element>;
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {createApp(App).use(router).mount("#app");
} else {renderWithQiankun({mount(props) {console.log("--mount");app = createApp(App);app.use(router).mount((props.container? props.container.querySelector("#app"): document.getElementById("app")) as Element);},bootstrap() {console.log("--bootstrap");},update() {console.log("--update");},unmount() {console.log("--unmount");app?.unmount();},});
}
这里要注意的是qiankun使用 window.__POWERED_BY_QIANKUN__ 判断是否在子应用环境中,而插件使用 qiankunWindow.__POWERED_BY_QIANKUN__ 进行判断
在修改一下主应用的index.js配置子应用B
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([{name: 'reactapp',entry: '//localhost:3001',container: '#container',activeRule: '/app-react',},{name: 'vueapp',entry: '//localhost:5173',container: '#container',activeRule: '/app-vue',},]);
// 启动 qiankun
start();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />
);
reportWebVitals();
至此,第二个子应用vueapp也集成了
react主应用 localhost:3000 my-main-app
vue微应用 localhost:5173 vueapp
下面是集成之后的效果图