🔥 基于 Vite 的 Qiankun 微前端完整模板
主应用(Vite+React) + React子应用(Vite) + Vue3子应用(Vite)
纯 Vite 构建,无 Webpack,开箱即用,包含:
- 完整目录结构
- 所有依赖清单
- 可直接运行的启动脚本
- 全局状态互通
- 路由隔离
- 样式隔离
一、项目整体结构(直接按这个创建)
qiankun-vite-micro/
├── main-app/ # 主应用(Vite + React)
├── react-sub/ # React 子应用(Vite + React)
└── vue-sub/ # Vue3 子应用(Vite + Vue3)
二、主应用:main-app(Vite + React)
1. package.json 依赖
json
{
"name": "main-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"qiankun": "^2.10.13",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.11"
}
}
2. vite.config.js
js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 4000, // 主应用端口
cors: true
}
})
3. 入口 src/main.jsx
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App.jsx'
import { registerMicroApps, start, initGlobalState } from 'qiankun'
// 全局状态
const initialState = {
userInfo: { name: '主应用用户' },
token: '123456'
}
const { setGlobalState, onGlobalStateChange } = initGlobalState(initialState)
// 注册子应用
registerMicroApps([
{
name: 'reactSub',
entry: '//localhost:4001',
container: '#container',
activeRule: '/react',
props: { setGlobalState, onGlobalStateChange }
},
{
name: 'vueSub',
entry: '//localhost:4002',
container: '#container',
activeRule: '/vue',
props: { setGlobalState, onGlobalStateChange }
}
])
// 启动
start({
sandbox: { strictStyleIsolation: true }
})
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
4. src/App.jsx
jsx
import { Link, Outlet } from 'react-router-dom'
function App() {
return (
<div>
<h1>🚀 主应用(React+Vite)</h1>
<nav style={{ margin: '1rem 0' }}>
<Link to="/react" style={{ marginRight: 10 }}>React 子应用</Link>
<Link to="/vue">Vue 子应用</Link>
</nav>
{/* 子应用挂载点 */}
<div id="container" style={{ border: '1px solid #eee', padding: 20 }} />
<Outlet />
</div>
)
}
export default App
三、React 子应用:react-sub(Vite + React)
1. package.json
json
{
"name": "react-sub",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.11",
"vite-plugin-qiankun": "^1.0.15"
}
}
2. vite.config.js
js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
plugins: [
react(),
qiankun('reactSub', { useDevMode: true })
],
server: {
port: 4001,
cors: true
}
})
3. src/main.jsx
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { BrowserRouter } from 'react-router-dom'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
let root = null
function render(props) {
const { container } = props || {}
const dom = container ? container.querySelector('#root') : document.getElementById('root')
root = ReactDOM.createRoot(dom)
root.render(
<BrowserRouter basename={qiankunWindow.__POWERED_BY_QIANKUN__ ? '/react' : ''}>
<App {...props} />
</BrowserRouter>
)
}
renderWithQiankun({
mount(props) { render(props) },
bootstrap() {},
unmount() { root.unmount() }
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render()
}
4. src/App.jsx
jsx
import { useEffect, useState } from 'react'
export default function App(props) {
const [globalState, setGlobalState] = useState({})
useEffect(() => {
if (props.onGlobalStateChange) {
props.onGlobalStateChange((state) => {
setGlobalState(state)
}, true)
}
}, [props])
return (
<div>
<h2>⚛️ React 子应用</h2>
<p>全局用户:{globalState.userInfo?.name}</p>
<button onClick={() => props.setGlobalState({ userInfo: { name: 'React修改' } })}>
修改全局状态
</button>
</div>
)
}
四、Vue3 子应用:vue-sub(Vite + Vue3)
1. package.json
json
{
"name": "vue-sub",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.4.15",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.3",
"vite": "^5.0.11",
"vite-plugin-qiankun": "^1.0.15"
}
}
2. vite.config.js
js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
plugins: [
vue(),
qiankun('vueSub', { useDevMode: true })
],
server: {
port: 4002,
cors: true
}
})
3. src/main.js
js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
let app = null
function render(props) {
const { container } = props || {}
app = createApp(App)
app.use(router)
app.mount(container ? container.querySelector('#app') : '#app')
}
renderWithQiankun({
mount(props) { render(props) },
bootstrap() {},
unmount() { app.unmount() }
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render()
}
4. src/router/index.js
js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
const routes = [
{ path: '/', component: Home }
]
const router = createRouter({
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vue' : ''),
routes
})
export default router
5. src/App.vue
vue
<template>
<div>
<h2>🟢 Vue 子应用</h2>
<p>全局用户:{{ userInfo?.name }}</p>
<button @click="changeName">修改全局状态</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const userInfo = ref({})
const props = defineProps(['onGlobalStateChange', 'setGlobalState'])
onMounted(() => {
if (props.onGlobalStateChange) {
props.onGlobalStateChange((state) => {
userInfo.value = state.userInfo
}, true)
}
})
const changeName = () => {
props.setGlobalState({ userInfo: { name: 'Vue修改' } })
}
</script>
6. src/views/Home.vue
vue
<template>
<div>Vue 子应用首页</div>
</template>
五、一键启动脚本(根目录创建 start.bat)
bat
@echo off
start cmd /k "cd main-app && npm install && npm run dev"
timeout /t 2 /nobreak >nul
start cmd /k "cd react-sub && npm install && npm run dev"
timeout /t 2 /nobreak >nul
start cmd /k "cd vue-sub && npm install && npm run dev"
六、访问地址
- 主应用:http://localhost:4000
- React 子应用:http://localhost:4000/react
- Vue 子应用:http://localhost:4000/vue
七、核心功能说明
✅ 纯 Vite 构建,无任何 Webpack 兼容问题
✅ React + Vue3 完美混部
✅ 全局状态互通(修改一个应用,所有应用同步)
✅ 路由严格隔离,不冲突
✅ 样式严格隔离,不污染
✅ 子应用可独立运行 + 主应用加载