perf(X-Pack): 插件管理-前端分布式加载静态资源

This commit is contained in:
fit2cloud-chenyw 2024-06-20 16:32:02 +08:00
parent f6a8f2b947
commit 54d254e290
16 changed files with 82 additions and 55 deletions

View File

@ -1 +1,20 @@
ALTER TABLE `core_export_task` ADD COLUMN `msg` LONGTEXT NULL COMMENT '错误信息' AFTER `params`;
ALTER TABLE `core_export_task`
ADD COLUMN `msg` LONGTEXT NULL COMMENT '错误信息' AFTER `params`;
DROP TABLE IF EXISTS `xpack_plugin`;
CREATE TABLE `xpack_plugin`
(
`id` bigint NOT NULL COMMENT 'ID',
`name` varchar(255) NOT NULL COMMENT '插件名称',
`icon` longtext NOT NULL COMMENT '图标',
`version` varchar(255) NOT NULL COMMENT '版本',
`install_time` bigint NOT NULL COMMENT '安装时间',
`flag` varchar(255) NOT NULL COMMENT '类型',
`developer` varchar(255) NOT NULL COMMENT '开发者',
`config` longtext NOT NULL COMMENT '插件配置',
`require_version` varchar(255) NOT NULL COMMENT 'DE最低版本',
`module_name` varchar(255) NOT NULL COMMENT '模块名称',
`jar_name` varchar(255) NOT NULL COMMENT 'Jar包名称',
PRIMARY KEY (`id`)
) COMMENT ='插件表';

View File

@ -14,7 +14,7 @@ export default {
],
build: {
rollupOptions: {
external: id => /de-xpack/.test(id) || /extensions-view-3dpie/.test(id),
external: id => /de-xpack/.test(id) || /extensions/.test(id),
output: {
// 用于命名代码拆分时创建的共享块的输出命名
chunkFileNames: `assets/chunk/[name]-${pkg.version}-${pkg.name}.js`,

View File

@ -1490,25 +1490,6 @@ defineExpose({
@linkJumpSetOpen="linkJumpSetOpen(item)"
@linkageSetOpen="linkageSetOpen(item)"
>
<!--如果是图表 则动态获取预存的chart-view数据-->
<!-- <PluginComponent
v-if="item['isPlugin']"
:jsname="item['pluginFlag'] || 'L2NvbXBvbmVudC9pbmRleA=='"
class="component"
:id="'component' + item.id"
:active="item.id === curComponentId"
:dv-type="dvInfo.type"
:scale="curBaseScale"
:style="getComponentStyle(item.style)"
:prop-value="item.propValue"
:is-edit="true"
:view="canvasViewInfo[item.id]"
:element="item"
:request="item.request"
@input="handleInput"
:dv-info="dvInfo"
:canvas-active="canvasActive"
/> -->
<component
:is="findComponent(item.component)"
v-if="item.component === 'UserView' || item['isPlugin']"

View File

@ -2,7 +2,7 @@
import noLic from './nolic.vue'
import { ref, useAttrs, onMounted } from 'vue'
import { execute, randomKey, formatArray } from './convert'
import { loadPluginApi, loadDistributed, xpackModelApi } from '@/api/plugin'
import { loadPluginApi, xpackModelApi } from '@/api/plugin'
import { useCache } from '@/hooks/web/useCache'
import { i18n } from '@/plugins/vue-i18n'
import * as Vue from 'vue'
@ -10,7 +10,7 @@ import axios from 'axios'
import * as Pinia from 'pinia'
import * as vueRouter from 'vue-router'
import { useEmitt } from '@/hooks/web/useEmitt'
import request from '@/config/axios'
const { wsCache } = useCache()
const plugin = ref()
@ -33,15 +33,12 @@ const generateRamStr = (len: number) => {
}
const importProxy = (bytesArray: any[]) => {
/* const promise = import(
`../../../../../../../${formatArray(bytesArray[7])}/${formatArray(bytesArray[8])}/${formatArray(
bytesArray[9]
)}/${formatArray(bytesArray[10])}/${formatArray(bytesArray[11])}.vue`
) */
const promise = import(
`../../../../../../../extensions-view-3dpie/${formatArray(bytesArray[8])}/${formatArray(
`../../../../../../../extensions/${formatArray(bytesArray[8])}/${formatArray(
bytesArray[9]
)}/${formatArray(bytesArray[10])}/${formatArray(bytesArray[11])}.vue`
)}/${formatArray(bytesArray[10])}/${formatArray(bytesArray[11])}/${formatArray(
bytesArray[12]
)}.vue`
)
promise
.then((res: any) => {
@ -53,16 +50,23 @@ const importProxy = (bytesArray: any[]) => {
})
}
const getModuleName = () => {
const jsPath = window.atob(attrs.jsname.toString())
return jsPath.split('/')[0]
}
const loadComponent = () => {
const moduleName = getModuleName()
loading.value = true
const byteArray = wsCache.get(`de-plugin-proxy-plugin`)
const byteArray = wsCache.get(`de-plugin-proxy-${moduleName}`)
if (byteArray) {
importProxy(JSON.parse(byteArray))
loading.value = false
return
}
const key = generateRamStr(randomKey())
loadPluginApi(key)
const moduleNameKey = window.btoa(moduleName)
const saltKey = `${key},${moduleNameKey}`
loadPluginApi(saltKey)
.then(response => {
let code = response.data
const byteArray = execute(code, key)
@ -82,7 +86,8 @@ const storeCacheProxy = byteArray => {
byteArray.forEach(item => {
result.push([...item])
})
wsCache.set(`de-plugin-proxy-plugin`, JSON.stringify(result))
const moduleName = getModuleName()
wsCache.set(`de-plugin-proxy-${moduleName}`, JSON.stringify(result))
}
const pluginProxy = ref(null)
const invokeMethod = param => {
@ -104,8 +109,9 @@ onMounted(async () => {
distributed = wsCache.get(key)
}
if (distributed) {
if (window['DEXPack']) {
const xpack = await window['DEXPack'].mapping[attrs.jsname]
const moduleName = getModuleName()
if (window[moduleName]) {
const xpack = await window[moduleName].mapping[attrs.jsname]
plugin.value = xpack.default
} else {
window['Vue'] = Vue
@ -114,9 +120,10 @@ onMounted(async () => {
window['vueRouter'] = vueRouter
window['MittAll'] = useEmitt().emitter.all
window['I18n'] = i18n
loadDistributed().then(async res => {
new Function(res.data)()
const xpack = await window['DEXPack'].mapping[attrs.jsname]
const url = `/xpackComponent/pluginStaticInfo/${moduleName}`
request.get({ url }).then(async res => {
new Function(res.data || res)()
const xpack = await window[moduleName].mapping[attrs.jsname]
plugin.value = xpack.default
})
}

View File

@ -173,6 +173,8 @@ service.interceptors.response.use(
return response
} else if (response.config.url.includes('DEXPack.umd.js')) {
return response
} else if (response.config.url.startsWith('/xpackComponent/pluginStaticInfo/extensions-')) {
return response
} else {
if (
!response?.config?.url.startsWith('/xpackComponent/content') &&

View File

@ -48,8 +48,8 @@ const anchorPosition = anchor => {
scrollTo(element.offsetTop)
}
const newComponent = (innerType, isPlugin) => {
eventBus.emit('handleNew', { componentName: 'UserView', innerType: innerType, isPlugin })
const newComponent = (innerType, staticMap) => {
eventBus.emit('handleNew', { componentName: 'UserView', innerType: innerType, staticMap })
}
const handleDragStart = e => {
@ -66,14 +66,15 @@ const groupActiveChange = category => {
}
const loadPluginCategory = data => {
data.forEach(item => {
const { category, title, render, chartValue, chartTitle, icon } = item
const { category, title, render, chartValue, chartTitle, icon, staticMap } = item
const node = {
render,
category,
icon,
value: chartValue,
title: chartTitle,
isPlugin: true
isPlugin: true,
staticMap
}
const stack = [...state.chartGroupList]
let findParent = false
@ -128,7 +129,7 @@ const loadPluginCategory = data => {
:key="chartInfo.title"
>
<div
v-on:click="newComponent(chartInfo.value, chartInfo['isPlugin'])"
v-on:click="newComponent(chartInfo.value, chartInfo['staticMap'])"
class="item-top"
draggable="true"
:data-id="'UserView&' + chartInfo.value"

View File

@ -518,8 +518,9 @@ export function findNewComponentFromList(
componentName,
innerType,
curOriginThemes,
isPlugin?: boolean
staticMap?: object
) {
const isPlugin = !!staticMap
let newComponent
list.forEach(comp => {
if (comp.component === componentName) {
@ -540,6 +541,9 @@ export function findNewComponentFromList(
newComponent.label = viewConfig?.title
newComponent.render = viewConfig?.render
newComponent.isPlugin = !!isPlugin
if (isPlugin) {
newComponent.staticMap = staticMap
}
}
return newComponent
}

View File

@ -1,4 +1,4 @@
declare interface ChartPlugin {
isPlugin: boolean
pluginResourceId?: string
staticMap?: object
}

View File

@ -391,7 +391,7 @@ export const dvMainStore = defineStore('dataVisualization', {
render: component.render,
plugin: {
isPlugin: component.isPlugin,
pluginResourceId: component.pluginResourceId
staticMap: component.staticMap
}
} as unknown as ChartObj
// 处理配置项默认值不同图表的同一配置项默认值不同

View File

@ -73,10 +73,9 @@ const editStyle = computed(() => {
//
const handleNewFromCanvasMain = newComponentInfo => {
const { componentName, innerType, isPlugin } = newComponentInfo
const { componentName, innerType, staticMap } = newComponentInfo
if (componentName) {
const component = findNewComponentFromList(componentName, innerType, curOriginThemes, isPlugin)
component.isPlugin = !!isPlugin
const component = findNewComponentFromList(componentName, innerType, curOriginThemes, staticMap)
syncShapeItemStyle(component, baseWidth.value, baseHeight.value)
component.id = guid()
component.y = 200

View File

@ -1605,7 +1605,7 @@ const deleteChartFieldItem = id => {
</div>
<plugin-component
v-else-if="view.plugin?.isPlugin"
jsname="L2NvbXBvbmVudC9lZGl0b3IvaW5kZXg="
:jsname="view.plugin.staticMap['editor']"
:view="view"
:dimension="state.dimension"
:quota="state.quota"

View File

@ -762,7 +762,7 @@ const showActionIcons = computed(() => {
<div v-if="chartAreaShow" style="flex: 1; overflow: hidden">
<plugin-component
v-if="view.plugin?.isPlugin"
jsname="L2NvbXBvbmVudC9pbmRleA=="
:jsname="view.plugin.staticMap['index']"
:scale="scale"
:dynamic-area-id="dynamicAreaId"
:view="view"

View File

@ -20,4 +20,7 @@ public interface XpackComponentApi {
@GetMapping("/viewPlugins")
List<XpackPluginsViewVO> viewPlugins();
@GetMapping("/pluginStaticInfo/{moduleName}")
void pluginStaticInfo(@PathVariable("moduleName") String moduleName);
}

View File

@ -63,6 +63,7 @@ public class WhitelistUtils {
|| StringUtils.startsWithAny(requestURI, "/appearance/image/")
|| StringUtils.startsWithAny(requestURI, "/share/proxyInfo")
|| StringUtils.startsWithAny(requestURI, "/xpackComponent/content")
|| StringUtils.startsWithAny(requestURI, "/xpackComponent/pluginStaticInfo")
|| StringUtils.startsWithAny(requestURI, "/geo/")
|| StringUtils.startsWithAny(requestURI, "/websocket")
|| StringUtils.startsWithAny(requestURI, "/map/")

View File

@ -1,7 +1,10 @@
package io.dataease.extensions.view.factory;
import io.dataease.exception.DEException;
import io.dataease.extensions.view.template.PluginsChartTemplate;
import io.dataease.extensions.view.vo.XpackPluginsViewVO;
import io.dataease.license.utils.LogUtil;
import io.dataease.plugins.factory.DataEasePluginFactory;
import java.util.List;
import java.util.Map;
@ -11,6 +14,7 @@ public class PluginsChartFactory {
private static final Map<String, PluginsChartTemplate> templateMap = new ConcurrentHashMap<>();
public static PluginsChartTemplate getInstance(String render, String type) {
String key = render + "_" + type;
return templateMap.get(key);
@ -20,13 +24,16 @@ public class PluginsChartFactory {
String key = render + "_" + type;
if (templateMap.containsKey(key)) return;
templateMap.put(key, template);
try {
String moduleName = template.getPluginInfo().getModuleName();
DataEasePluginFactory.loadTemplate(moduleName, template);
} catch (Exception e) {
LogUtil.error(e.getMessage(), new Throwable(e));
DEException.throwException(e);
}
}
public static List<XpackPluginsViewVO> getViewConfigList() {
return templateMap.values().stream().map(PluginsChartTemplate::getConfig).toList();
}
public static List<String> getAllPlugins() {
return null;
}
}

View File

@ -4,6 +4,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
@Data
public class XpackPluginsViewVO implements Serializable {
@ -26,4 +27,6 @@ public class XpackPluginsViewVO implements Serializable {
private String render;
private Map<String, String> staticMap;
}