Przeglądaj źródła

支持微服务

tongshangming 1 rok temu
rodzic
commit
e675caae60

+ 26 - 0
env.d.ts

@@ -2,3 +2,29 @@
 
 declare module 'splitpanes'
 declare module 'element-plus/dist/locale/zh-cn.mjs'
+
+declare interface Window {
+  // 是否存在无界
+  __POWERED_BY_WUJIE__?: boolean
+  // 子应用公共加载路径
+  __WUJIE_PUBLIC_PATH__: string
+  // 原生的querySelector
+  __WUJIE_RAW_DOCUMENT_QUERY_SELECTOR__: typeof Document.prototype.querySelector
+  // 原生的querySelectorAll
+  __WUJIE_RAW_DOCUMENT_QUERY_SELECTOR_ALL__: typeof Document.prototype.querySelectorAll
+  // 原生的window对象
+  __WUJIE_RAW_WINDOW__: Window
+  // 子应用沙盒实例
+  __WUJIE: WuJie
+  // 子应用mount函数
+  __WUJIE_MOUNT: () => void
+  // 子应用unmount函数
+  __WUJIE_UNMOUNT: () => void
+  // 注入对象
+  $wujie: {
+    bus: EventBus
+    shadowRoot?: ShadowRoot
+    props?: { [key: string]: any }
+    location?: Object
+  }
+}

+ 2 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "fs-admin",
-  "version": "1.9.0",
+  "version": "2.0.0",
   "type": "module",
   "scripts": {
     "dev": "vite --host",
@@ -28,6 +28,7 @@
     "vue-router": "^4.2.5",
     "vuedraggable": "^4.1.0",
     "vxe-table": "^4.5.13",
+    "wujie-vue3": "^1.0.22",
     "xe-utils": "^3.5.14"
   },
   "devDependencies": {

+ 18 - 0
pnpm-lock.yaml

@@ -56,6 +56,9 @@ dependencies:
   vxe-table:
     specifier: ^4.5.13
     version: 4.5.13(vue@3.3.8)(xe-utils@3.5.14)
+  wujie-vue3:
+    specifier: ^1.0.22
+    version: 1.0.22(vue@3.3.8)
   xe-utils:
     specifier: ^3.5.14
     version: 3.5.14
@@ -5956,6 +5959,21 @@ packages:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
     dev: true
 
+  /wujie-vue3@1.0.22(vue@3.3.8):
+    resolution: {integrity: sha512-/FD52+3rEg4vQb6EhSq+V9WMhaHYyVliUsVDBIzePcX0yUsep+4oC8r3EmyeS2dfEl3DCmMwLz5MnBGL3c4Msw==}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      vue: 3.3.8(typescript@5.3.2)
+      wujie: 1.0.22
+    dev: false
+
+  /wujie@1.0.22:
+    resolution: {integrity: sha512-gzx13fp9hgTHdV9XetkVmp794uDSR93Zs9jLr891RaWRuMiLFoxh3Pe4qbmW604SxI8nMTHeIRydbgC7YxQ50Q==}
+    dependencies:
+      '@babel/runtime': 7.23.4
+    dev: false
+
   /xe-utils@3.5.14:
     resolution: {integrity: sha512-Xq6mS8dWwHBQsQUEBXcZYSaBV0KnNLoVWd0vRRDI3nKpbNxfs/LSCK0W21g1edLFnXYfKqg7hh5dakr3RtYY0A==}
     dev: false

+ 21 - 0
src/App.vue

@@ -1,10 +1,31 @@
 <script setup lang="ts">
 import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
 import { useThemeStore } from '@/stores/theme'
+import { isMicro } from '@/config/mainMicro'
+import { microName } from '@/config/subMicro'
+
 const locale = zhCn
 
 const themeStore = useThemeStore()
 themeStore.initTheme()
+
+if (isMicro) {
+  const router = useRouter()
+  const route = useRoute()
+  watch(
+    () => route.path,
+    () => {
+      window.$wujie?.bus.$emit('sub-route-change', microName, route.path)
+    },
+    {
+      immediate: true
+    }
+  )
+
+  window.$wujie?.bus.$on(`${microName}-router-change`, (route: string) => {
+    router.push(route)
+  })
+}
 </script>
 
 <template>

+ 4 - 2
src/assets/base.css

@@ -63,9 +63,11 @@
   box-sizing: border-box;
   margin: 0;
 }
-
+html{
+  height: 100%;
+}
 body {
-  min-height: 100vh;
+  height: 100%;
   color: var(--color-text);
   background: var(--color-background);
   transition: color 0.5s, background-color 0.5s;

+ 27 - 0
src/config/mainMicro.ts

@@ -0,0 +1,27 @@
+const microConfig = [
+  {
+    name: 'system',
+    url: {
+      development: 'http://localhost:5174',
+      production: ''
+    },
+    exec: true,
+    alive: true
+  },
+  {
+    name: 'mini',
+    url: {
+      development: 'http://localhost:5175',
+      production: ''
+    },
+    exec: true,
+    alive: true
+  }
+]
+
+export const microList = microConfig.map((item: any) => {
+  item.url = item.url[import.meta.env.MODE]
+  return item
+})
+
+export const isMicro = window.__POWERED_BY_WUJIE__

+ 1 - 0
src/config/subMicro.ts

@@ -0,0 +1 @@
+export const microName = ''

+ 54 - 0
src/hooks/useMainMicro.ts

@@ -0,0 +1,54 @@
+import WujieVue from 'wujie-vue3'
+import { isMicro, microList } from '@/config/mainMicro'
+import router from '@/router'
+import type { App } from 'vue'
+
+export const useMainMicro = (microName?: string) => {
+  const getMicroByName = (name: string) => {
+    return microList.find(item => item.name === name)
+  }
+  const micro = getMicroByName(microName || '')
+
+  const initWatch = () => {
+    const route = useRoute()
+    watch(
+      () => route.path,
+      () => {
+        WujieVue.bus.$emit(microName + '-router-change', route.path)
+      },
+      {
+        immediate: true
+      }
+    )
+  }
+
+  const initMicro = (app: App) => {
+    // 主服务初始化微服务
+    if (!isMicro) {
+      const { setupApp, preloadApp, bus } = WujieVue
+
+      microList.forEach((item: any) => {
+        setupApp(item)
+        preloadApp({ name: item.name, url: item.url })
+      })
+
+      // 在 xxx-sub 路由下子应用将激活路由同步给主应用,主应用跳转对应路由高亮菜单栏
+      bus.$on('sub-route-change', (name: string, path: string) => {
+        const mainPath = `/${name}${path}`
+        const currentName = router.currentRoute.value.name
+        const currentPath = router.currentRoute.value.path
+        if (name === currentName && mainPath !== currentPath) {
+          router.push({ path: mainPath })
+        }
+      })
+
+      app.use(WujieVue)
+    }
+  }
+
+  return {
+    micro,
+    initWatch,
+    initMicro
+  }
+}

+ 12 - 0
src/hooks/useSubMicro.ts

@@ -0,0 +1,12 @@
+import { microList } from '@/config/mainMicro'
+
+export const useSubMicro = (microName?: string) => {
+  const getMicroByName = (name: string) => {
+    return microList.find(item => item.name === name)
+  }
+  const micro = getMicroByName(microName || '')
+
+  return {
+    micro
+  }
+}

+ 9 - 1
src/layouts/BasicLayout.vue

@@ -1,13 +1,21 @@
 <script setup lang="ts">
 import { useRouterStore } from '@/stores/router'
 import { useThemeStore } from '@/stores/theme'
+import { isMicro } from '@/config/mainMicro'
 
 const routerStore = useRouterStore()
 const themeStore = useThemeStore()
 </script>
 
 <template>
-  <el-container class="layout-container">
+  <div class="h-full" v-if="isMicro">
+    <router-view v-slot="{ Component }">
+      <keep-alive :include="themeStore.keepAliveTabs ? routerStore.keepAliveRouter : []">
+        <component :is="Component" />
+      </keep-alive>
+    </router-view>
+  </div>
+  <el-container class="layout-container" v-else>
     <el-aside>
       <global-aside />
     </el-aside>

+ 7 - 2
src/main.ts

@@ -6,11 +6,10 @@ import 'uno.css'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+import { install } from '@icon-park/vue-next/es/all'
 
 import registerComponent from '@/components/index'
 
-import { install } from '@icon-park/vue-next/es/all'
-
 import 'xe-utils'
 import {
   // VXETable,
@@ -60,6 +59,8 @@ import router from './router'
 import './assets/main.css'
 import 'virtual:svg-icons-register'
 
+// import { useMainMicro } from '@/hooks/useMainMicro'
+
 function useTable(app: any) {
   // 表格功能
   app.use(Filter).use(Edit).use(Menu).use(Export).use(Keyboard).use(Validator)
@@ -116,4 +117,8 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
 
 install(app)
 
+// 主服务初始化微服务
+// const { initMicro } = useMainMicro()
+// initMicro(app)
+
 app.mount('#app')

+ 15 - 0
src/views/micro/Micro.vue

@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { useMainMicro } from '@/hooks/useMainMicro'
+
+const microName = 'system'
+const { micro, initWatch } = useMainMicro(microName)
+initWatch()
+
+const route = useRoute()
+</script>
+
+<template>
+  <WujieVue width="100%" height="100%" :name="microName" :url="micro.url + route.path" :sync="true"></WujieVue>
+</template>
+
+<style lang="scss" scoped></style>