阿里qiankun微服务搭建
主服务chatvue3 tsvite 子服务 pptreact 18vite 子服务agent主服务mian.tsvue3 ts服务main.ts。
·
主服务 chat
vue3 ts vite 子服务 ppt
react 18 vite 子服务 agent
主服务路由改为history 不然qiankun 的activeRule 匹配不上
const router = createRouter({
history: createWebHistory(), // hash history: createWebHashHistory(),
strict: true,
routes: constantRouterMap as RouteRecordRaw[],
scrollBehavior: () => ({ left: 0, top: 0 })
})
主服务
npm install qiankun --save
npm i vite-plugin-qiankun
mian.ts
import './style/base.scss'
import 'virtual:svg-icons-register'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import Axios from '@/utils/request.js';
import { registerMicroApps, start } from 'qiankun';
// 引入ui 库
// import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 引入ui icon
// 将自动注册所有组件为全局组件
// import dataV from '@jiaminghi/data-view'
const app = createApp(App)
// for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
// app.component(key, component)
// }
app.config.globalProperties.$http = Axios
app.use(createPinia())
app.use(router)
// app.use(ElementPlus)
app.mount('#app')
router/index.ts 不能使用懒加载
{ path: '/ppt', component: ppt },
{ path: '/ppt/home', component: ppt },
{ path: '/agent', component: agent },
agent/index.vue
<template>
<div
ref="agentContainer"
id="agentContainer"
style="width: 100%;height: 100%;"
>
react
</div>
</template>
<script lang="ts" setup>
</script>
<style>
#pptContainer {
width: 100vw;
height: 100vh;
}
</style>
router
{ path: '/ppt', component: ppt },
{ path: '/ppt/home', component: ppt },
ppt/index.vue
<template>
<div ref="pptContainer" id="pptContainer" style="width: 100%;height: 100%;">
zzzzzzzzz
</div>
</template>
<script lang="ts" setup>
})
</script>
<style>
#pptContainer {
width: 100vw;
height: 100vh;
}
</style>
</style>
layout/inde.vue
<template>
<el-container class="layout-container">
<!-- 顶部导航 -->
<el-header>
<Header />
</el-header>
<!-- 右侧主区域 -->
<el-container>
<!-- 左侧菜单 -->
<!-- <el-aside style="height: 100%;"> -->
<Menu style="height: 100%;" />
<!-- </el-aside> -->
<!-- 内容区域 -->
<el-main>
<router-view
v-show="!routeHasQIANKUN"
v-slot="{ Component }"
style="height: 100%;"
>
<component :is="Component" />
</router-view>
<div
v-show="routeHasQIANKUN"
style="height: 100%;"
ref="qiankunContainer"
id="qiankunContainer"
>
</div>
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts" name="layout">
defineOptions({
name: 'layout', // 自定义组件名
});
import Menu from "@/views/menu/index.vue";
import Header from '@/views/header/index.vue';
import { onMounted, ref, watch } from "vue";
import { registerMicroApps, start } from "qiankun";
import { useRoute } from "vue-router";
let routeHasQIANKUN = ref(true)
const route = useRoute();
routeHasQIANKUN.value = route.path.includes('ppt') || route.path.includes('agent')
const qiankunContainer = ref(null);
onMounted(() => {
registerMicroApps([
{
name: 'ppt',
entry: 'http://localhost:5173/ppt/',
container: qiankunContainer.value as unknown as HTMLElement, // 老版本这里使用的是 #pptContainer,
activeRule: '/ppt',
props: {
// 传递给子应用的数据
data: {
name: 'ppt',
age: 18,
},
},
},
{
name: 'agent',
entry: 'http://localhost:83/agent/',
container: qiankunContainer.value as unknown as HTMLElement,
activeRule: '/agent',
props: {
// 传递给子应用的数据
data: {
name: 'ppt',
age: 18,
},
},
}
], {
beforeLoad: [
(app: any): any => {
// console.log('before load', app);
// 挂载前回调
}
],
beforeMount: [
(app: any): any => {
// console.log('beforeMount', app);
// 挂载后回调
}
],
afterUnmount: [
(app: any): any => {
// console.log('afterUnmount', app);
// 挂载后回调
}
]
})
// setTimeout(() => {
start({
prefetch: 'all', // 预加载子应用
sandbox: { experimentalStyleIsolation: true }, // 样式隔离
});
// }, 100);
})
watch(route, (newRoute, oldRoute) => {
routeHasQIANKUN.value = newRoute.path.includes('ppt') || newRoute.path.includes('agent')
}
)
</script>
<style scoped>
.layout-container {
height: 100vh;
}
.el-header {
background-color: blue;
padding: 0;
height: 50px;
}
.el-aside {
background-color: #304156;
color: white;
height: calc(100vh - 55px);
}
.el-main {
background-color: #e9eef3;
height: calc(100vh - 50px);
padding: 0 !important;
margin: 0 !important;
--el-main-padding: 0 !important;
}
</style>
vue3 ts服务
vite.cong.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
import path from 'path';
// import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import viteCompression from 'vite-plugin-compression';
const packName = require('./package').name
// https://vite.dev/config/
export default defineConfig({
base: '/' + packName + '/',
plugins: [vue(),
viteCompression({
ext: '.gz', // 输出的压缩文件扩展名
algorithm: 'gzip', // 使用 Gzip 算法
threshold: 10240, // 仅压缩大于 10KB 的文件
deleteOriginFile: false, // 是否删除源文件
}),
qiankun(`${packName}`, { // 子应用名称,与package.json的name一致
useDevMode: true // 开发模式下需要设置为true
}),
// createSvgIconsPlugin({
// iconDirs: [path.resolve(process.cwd(), './src/assets/svg/')],
// symbolId: 'icon-[dir]-[name]',
// })
],
server: {
host: "0.0.0.0",
port: 5173, // 设置子应用端口
cors: true, // 允许跨域
headers: {
'Access-Control-Allow-Origin': '*' // 允许跨域
}
},
resolve: {
// Vite路径别名配置
alias: {
'@': path.resolve('./src'), // @代替src
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js'
},
},
css: {
preprocessorOptions: {
scss: {
// additionalData: '@import "./src/style/index.scss";' // 修复:改为单个字符串
// charset: false
}
}
},
// 打包
build: {
lib: {
entry: './src/main.js', // 库的入口文件
name: 'm-vue', // UMD 格式下挂载到全局的变量名 (window['m-vue'])
formats: ['umd'], // 指定打包格式
fileName: (format) => `my-vue-app.${format}.js`
},
minify: 'terser',
chunkSizeWarningLimit: 1500,
terserOptions: {
// 清除代码中console和debugger
compress: {
drop_console: false,
drop_debugger: true,
},
},
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
}
},
})
main.ts
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import './style/base.scss'
import router from './router/index.ts'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
// const app = createApp(App)
// app.use(router)
// app.mount('#app')
let instance: any = null
function render(props?: {} | undefined) {
console.log(props,"pros")
instance = createApp(App)
instance.use(router)
instance.mount('#app')
}
console.log(qiankunWindow.__POWERED_BY_QIANKUN__,"window.__POWERED_BY_QIANKUN__")
// // 独立运行时
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render()
}
renderWithQiankun({
mount(props: any) {
render(props)
},
bootstrap() {
// console.log('%c', 'color:green;', ' ChildOne bootstrap')
},
update() {
// console.log('%c', 'color:green;', ' ChildOne update')
},
unmount(props: any) {
instance.unmount()
instance._container.innerHTML = ''
instance = null
}
})
如果报错 app-errors.js:11 Uncaught TypeError: application ‘ppt’ died in status SKIP_BECAUSE_BROKEN: Cannot read properties of undefined (reading ‘instances’) 使用下边这个
import { createApp } from 'vue'
import App from './App.vue'
import './style/base.scss'
import router from './router'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
let app: ReturnType<typeof createApp> | null = null
function render(props?: { container?: HTMLElement }) {
const container = props?.container || '#app'
app = createApp(App)
app.use(router)
app.mount(container)
}
// 独立运行逻辑
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render()
}
// 乾坤生命周期
renderWithQiankun({
bootstrap() {
console.log('[子应用] bootstrap')
return Promise.resolve()
},
mount(props) {
console.log('[子应用] mount', props)
render(props)
},
update() {
console.log('[子应用] update')
},
unmount() {
console.log('[子应用] unmount')
app?.unmount()
app = null
}
})
router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(
window.__POWERED_BY_QIANKUN__ ? '/ppt' : '/ppt'
),
routes: [
// 你的路由配置
{
path: '/',
name: 'home',
component: () => import('../views/home/index.vue'),
},
{
path: '/home',
name: 'home1',
component: () => import('../views/home/index.vue'),
},
]
})
export default router
react 18
package.json
"qiankun": "^2.10.16",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^7.5.2",
"vite-plugin-qiankun": "^1.0.15"
vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
// 1. vite环境下安装qiankun插件
import qiankun from "vite-plugin-qiankun";
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
console.log(mode);
const isDev = mode === 'development'
const env = loadEnv(mode, process.cwd());
console.log(env);
return {
plugins: [
// 2. 引用qiankun插件,需要注意,这里的microReact是子应用名称,需要和主应用中注册的子应用名称一致
qiankun(env.VITE_APP_NAME, {
useDevMode: true,
}),
// 3. react()插件会跟vite-plugin-qiankun插件冲突,所以需要判断是否是开发环境
!isDev && react(),
],
// 4. 同域配置二级域名,异域配置不需要可修改为:isDev ? "/" : 'http://xxx.com/'
base: isDev ? "/"+env.VITE_APP_NAME : '/'+env.VITE_APP_NAME,
server: {
host: "0.0.0.0",
port: 83,
headers: {
'Access-Control-Allow-Origin': '*'
},
proxy: {
'^/reactApi': {
target: 'http://localhost:9528/',
rewrite: path => path.replace(/^\/reactApi/, ''),
changeOrigin: true
}
}
},
}
})
.env.development 和 .env.production
VITE_APP_BASE_API='/gateway'
VITE_APP_NAME='agent'
main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
// 1. 引用vite-plugin-qiankun
import { renderWithQiankun, qiankunWindow, QiankunProps } from 'vite-plugin-qiankun/dist/helper'
let root: ReactDOM.Root | null = null
// 2. qiankun渲染函数
function render(props: QiankunProps) {
console.log(props,"xxxxxxxxx")
const { container } = props
const root = ReactDOM.createRoot(
(container
? container.querySelector('#root')
: document.querySelector('#root')) as HTMLElement
)
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
)
return root
}
renderWithQiankun({
mount(props) {
root = render(props)
},
bootstrap() {
console.log('bootstrap')
},
unmount() {
root?.unmount()
},
update() {
},
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
root = render({})
}
router/index.tsx
// src/router/index.tsx
import React, { Suspense } from 'react'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { qiankunWindow } from "vite-plugin-qiankun/dist/helper";
// 路由懒加载
const Home = React.lazy(() => import('../views/home'))
// const List = React.lazy(() => import('../views/list'))
// const NotFound = React.lazy(() => import('../views/notFound'))
export default function Router() {
return (
// 同域:判断是否为qiankun引用,给出不同路由;异域分别修改为 '/micro-react' : '/'
<BrowserRouter basename={qiankunWindow.__POWERED_BY_QIANKUN__ ? "/"+import.meta.env.VITE_APP_NAME : "/"+import.meta.env.VITE_APP_NAME}>
<Routes>
<Route path='/' element={<Suspense><Home /></Suspense>}></Route>
<Route path='/home' element={<Suspense><Home /></Suspense>}></Route>
{/* <Route path='/list' element={<Suspense><List/></Suspense>}></Route> */}
{/* 定义404路由*/}
{/* <Route path='/404' element={<Suspense><NotFound/></Suspense>}></Route> */}
{/* 未匹配的路由使用Navigate重定向到此页面 这里即notFound.jsx */}
{/* <Route path='/*' element={<Navigate to='/404' />}></Route> */}
</Routes>
</BrowserRouter>
)
}
更多推荐


所有评论(0)