- 作者:老汪软件技巧
- 发表时间:2024-10-01 07:01
- 浏览量:
什么是 Qiankun?
简单来说,Qiankun 是一个基于 single-spa 的微前端实现库。它让多个前端应用在一个页面上无缝运行。想象一下,你有一个大盒子,里面可以放很多小盒子,每个小盒子都是一个独立的应用,但它们又能很好地协作,就像一个现代的“橡皮泥”框架。
Qiankun 的核心是提供了一种新的应用架构思路,方便我们更好地拆分前端项目,让每个子应用都能单独开发和部署。
Qiankun 能干啥?
随着业务量增长,单一的前端项目会变得难以维护:
Qiankun 帮助我们:
那为啥不用iframe来个实战
OK,现在我们来完成qiankun的示例项目,一起了解如何接入qiankun框架。这是我们所使用的项目框架:
主应用 by Vue3
// qiankun
import { registerMicroApps, addGlobalUncaughtErrorHandler, start } from 'qiankun'
// 注册子应用
registerMicroApps([
// VUE3子应用
{
name: 'subAppVue3',
entry: 'http://localhost:3002',
container: '#subapp-vue3',
// 当路由中包含有subv3时,激活子应用
activeRule: location => {
return location.pathname.includes('/subv3')
},
},
// react子应用
{
name: 'subAppReact',
entry: 'http://localhost:3003',
container: '#subapp-react',
// 当路由中包含有subreact时,激活子应用
activeRule: location => {
return location.pathname.includes('/subreact')
},
},
])
// 启动 qiankun
start({
prefetch: 'all',
})
// 添加全局异常捕获(非必须)
addGlobalUncaughtErrorHandler(handler => {
console.log('qiankun异常捕获', handler)
})
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/subv3',
name: 'subv3',
component: SubAppView
},
{
path: '/subreact',
name: 'subreact',
component: SubAppView
},
]
})
要注意的是,这里配置的渲染子应用的容器ID,要跟main.ts配置的子应用容器保持一致。
Vue3子应用
对于子应用来说,我们不仅要考虑子应用被嵌入口主应用运行,还需要考虑单独运行要如何处理。这里同样为了方便,我们仍然先使用vite脚手架创建一个全新的项目,在此基础上进行修改。
一般情况下,vue的app在创建后都是直接挂载在#app DOM进行渲染,但是作为子应用,我们必须要把渲染逻辑交给qiankun框架来完成:
// main.ts
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
const initQianKun = () => {
renderWithQiankun({
bootstrap() {console.log('bootstrap');},
mount(_props) {
console.log('mount', _props);
render(_props.container)
},
unmount(_props) {
console.log('unmount', _props);
},
update: function (props) {console.log('update');}
})
}
const render = (container: HTMLElement | null | undefined) => {
const app = createApp(App)
const appDom = container ? container : "#sub-app-v3"
app.mount(appDom)
}
// 判断是否为乾坤环境,否则会报错iqiankun]: Target container with #subAppContainerVue3 not existed while subAppVue3 mounting!
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render(null)
这里进行运行环境判断,如果是子应用环境,则调用qiankun来进行app的渲染,否则则直接渲染。
// qiankun插件
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
plugins: [
vue(),
qiankun('subAppVue3', { useDevMode: true })
],
server: {
port: 3002,
host: true
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
这样,就完成了对vue3子应用的改造,如果现在直接启动子应用,则会成功看到页面效果:
react子应用
react的改造步骤稍微多一些
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
import './public-path'
import './index.css';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
export function render(props) {
const { container } = props;
const conDom = container ? container.querySelector('#react-root') : document.getElementById('react-root');
console.log("conDom", conDom)
const root = ReactDOM.createRoot(conDom);
root.render(
<React.StrictMode>
<App />
React.StrictMode>
);
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log('React app bootstrapped');
}
export async function mount(props) {
console.log('Props from main framework', props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#react-root') : document.getElementById('react-root'));
}
跟vue3子应用类似,我们也需要处理直接渲染react的逻辑,同时将qiankun的各生命周期函数暴露出来,供qiankun进行调用。
pnpm i -D @rescripts/cli
const { name } = require('./package.json');
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
config.output.globalObject = 'window';
return config;
},
devServer: (_) => {
const config = _;
config.headers = {
'Access-Control-Allow-Origin': '*',
};
config.historyApiFallback = true;
config.hot = false;
config.liveReload = false;
return config;
},
};
同时把启动脚本修改为rescripts
{
"start": "PORT=3003 rescripts start",
"build": "rescripts build",
"test": "rescripts test",
"eject": "rescripts eject"
}
直接启动react项目,一切正常的话可以看下运行效果
整体运行效果
同时启动三个项目,然后通过切换路由来确认子项目是否都能成功加载:
示例源码
/open4jj/qia…
示例源码放在gitee上了,有需要的同学请自取,欢迎一键三连!