From 047e82788459727311dc2da33f2b0e05819c07b6 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 5 May 2025 21:26:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20@originjs/vite-plugin-fede?= =?UTF-8?q?ration=20=E4=BE=9D=E8=B5=96=EF=BC=8C=E5=B9=B6=E5=9C=A8=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E7=BB=84=E4=BB=B6=E4=B8=AD=E5=AE=9E=E7=8E=B0=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E7=BB=84=E4=BB=B6=E5=8A=A0=E8=BD=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auto-imports.d.ts | 4 +- components.d.ts | 1 + package.json | 1 + src/components/dialog/PluginConfigDialog.vue | 45 +++---- src/components/dialog/PluginDataDialog.vue | 45 +++---- src/components/misc/DashboardElement.vue | 35 ++--- src/utils/remoteFederationLoader.ts | 129 +++++++++++++++++++ vite.config.ts | 27 ++-- yarn.lock | 39 +++++- 9 files changed, 230 insertions(+), 96 deletions(-) create mode 100644 src/utils/remoteFederationLoader.ts diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 8634bad3..595fcc7b 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -328,7 +328,7 @@ declare global { // for type re-export declare global { // @ts-ignore - export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' + export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' import('vue') } @@ -356,6 +356,7 @@ declare module 'vue' { readonly createPinia: UnwrapRef readonly createProjection: UnwrapRef readonly createReactiveFn: UnwrapRef + readonly createRef: UnwrapRef readonly createReusableTemplate: UnwrapRef readonly createSharedComposable: UnwrapRef readonly createTemplatePromise: UnwrapRef @@ -490,6 +491,7 @@ declare module 'vue' { readonly useCloned: UnwrapRef readonly useColorMode: UnwrapRef readonly useConfirmDialog: UnwrapRef + readonly useCountdown: UnwrapRef readonly useCounter: UnwrapRef readonly useCssModule: UnwrapRef readonly useCssVar: UnwrapRef diff --git a/components.d.ts b/components.d.ts index c065f42a..703fab76 100644 --- a/components.d.ts +++ b/components.d.ts @@ -2,6 +2,7 @@ // @ts-nocheck // Generated by unplugin-vue-components // Read more: https://github.com/vuejs/core/pull/3399 +// biome-ignore lint: disable export {} /* prettier-ignore */ diff --git a/package.json b/package.json index d94641e6..0a47f639 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "@iconify/tools": "^4.0.4", "@iconify/vue": "^4.3.0", "@intlify/unplugin-vue-i18n": "^6.0.3", + "@originjs/vite-plugin-federation": "^1.4.1", "@tailwindcss/aspect-ratio": "^0.4.2", "@types/lodash-es": "^4.17.12", "@types/mousetrap": "^1.6.15", diff --git a/src/components/dialog/PluginConfigDialog.vue b/src/components/dialog/PluginConfigDialog.vue index 24f27127..e3101a38 100644 --- a/src/components/dialog/PluginConfigDialog.vue +++ b/src/components/dialog/PluginConfigDialog.vue @@ -7,6 +7,7 @@ import { useToast } from 'vue-toast-notification' import FormRender from '../render/FormRender.vue' import ProgressDialog from '../dialog/ProgressDialog.vue' import { useI18n } from 'vue-i18n' +import { loadRemoteComponent, clearRemoteComponentCache } from '@/utils/remoteFederationLoader' // 国际化 const { t } = useI18n() @@ -51,32 +52,12 @@ const vueComponentUrl = ref(null) // Vue 模式:动态加载的组件 const dynamicComponent = computed(() => { if (renderMode.value === 'vue' && vueComponentUrl.value) { - const url = vueComponentUrl.value - return defineAsyncComponent(() => - api - .get(url) - .then((response: any) => { - if (response) { - const blob = new Blob([response.data], { type: 'text/javascript' }) - const blobUrl = URL.createObjectURL(blob) - return import(/* @vite-ignore */ blobUrl) - } else { - return { render: () => h('div', '组件加载失败: 未读取到文件数据') } - } - }) - .then(module => { - if (module.default) { - return module.default - } else { - console.error(`无法从 ${url} 加载默认导出的 Vue 组件`) - return { render: () => h('div', '组件加载失败: 无默认导出') } - } - }) - .catch(err => { - console.error(`无法加载插件组件: ${url}`, err) - return { render: () => h('div', `组件加载失败:${err}`) } - }), - ) + return loadRemoteComponent(vueComponentUrl.value, { + onError: error => { + console.error(`加载插件组件失败: ${vueComponentUrl.value}`, error) + $toast.error(`加载插件组件失败: ${error.message || '未知错误'}`) + }, + }) } return null }) @@ -88,6 +69,11 @@ async function loadPluginUIData() { pluginFormItems = [] pluginConfigForm.value = {} renderMode.value = 'vuetify' + + // 如果存在旧的组件URL,清除其缓存 + if (vueComponentUrl.value) { + clearRemoteComponentCache(vueComponentUrl.value) + } vueComponentUrl.value = null try { @@ -151,6 +137,13 @@ async function savePluginConf() { onBeforeMount(async () => { await loadPluginUIData() }) + +// 组件卸载时清理资源 +onUnmounted(() => { + if (vueComponentUrl.value) { + clearRemoteComponentCache(vueComponentUrl.value) + } +})