跳至主要内容

Spark Workbench Dashboard Gadget 插件開發指南

本篇面向需要二次擴展 Spark Workbench Dashboard Gadget 的開發者。目標是把一個 Gadget 插件做成自包含工程:後端擴展點、前端 Vue 組件、前端建構產物都放在同一個插件模組中,平台主工程只負責載入和運行。

1. Gadget 插件模型​

Spark Workbench 的 Gadget 由兩部分組成:

  • 後端擴展點:透過 Lattice Ability 註冊 Gadget 描述資訊,並在運行期渲染資料。
  • 前端組件:透過 Vue 組件展示資料,打包成 UMD 資源後由 Workbench 動態載入。

預設插件位於:

spark-plugins/spark-workbench-default-plugin/

此模組同時包含 Java 與前端程式碼。第三方插件也建議採用相同結構,避免具體 Gadget 程式碼散落在平台主工程中。

2. 建議工程結構​

my-workbench-gadget-plugin/
pom.xml
src/main/java/
.../MyGadgetRegistryExt.java
src/main/frontend/
package.json
vite.config.js
src/
index.js
GadgetMyChart.vue
GadgetMyList.vue
  • MyGadgetRegistryExt.java 負責宣告 Gadget 類型、標題、分類、圖示、前端資源 URL,並返回運行期資料。
  • src/main/frontend/src/index.js 是前端入口,負責把 Vue 組件註冊給 Workbench。
  • vite.config.js 使用 library 模式建構 UMD 檔案,並把產物輸出到插件 jar 的靜態資源目錄。

3. 後端擴展點​

插件需要實作 SparkEraTaskGadgetRegistryExt,通常繼承空實作:

@Realization(codes = "my.workbench.gadget")
public class MyGadgetRegistryExt extends BlankSparkEraTaskGadgetRegistryExt {

private static final String FRONTEND_RESOURCE =
"/spark-gadgets/my-workbench-gadget/index.umd.js";

@Override
public List<SparkEraTaskGadgetDescriptor> listGadgetDescriptors(SparkEraTaskGadgetCatalogContext context) {
SparkEraTaskGadgetDescriptor descriptor = new SparkEraTaskGadgetDescriptor();
descriptor.setCode("myChart");
descriptor.setTitle("My Chart");
descriptor.setCategory("charts");
descriptor.setIcon("bar");
descriptor.setComponent("spark$gadget-my-chart");
descriptor.setFrontendResource(FRONTEND_RESOURCE);
descriptor.setConfigurable(true);
return List.of(descriptor);
}

@Override
public SparkEraTaskGadgetRenderResult renderGadget(SparkEraTaskGadgetRenderContext context) {
if (!StringUtils.equals(context.getGadgetType(), "myChart")) {
return null;
}
SparkEraTaskGadgetRenderResult result =
SparkEraTaskGadgetRenderResult.of("myChart", "spark$gadget-my-chart");
result.getData().put("bars", List.of(Map.of("label", "Open", "value", 12)));
return result;
}
}

關鍵欄位:

  • code:Gadget 類型編碼,要求全域唯一。
  • component:前端組件註冊 key,建議使用 spark$gadget-xxx。
  • frontendResource:插件前端入口 JS 的運行期 URL。
  • configurable:是否允許在 Dashboard 中打開設定面板。

4. 前端自註冊入口​

Gadget 前端入口在腳本載入後註冊組件:

import GadgetMyChart from "./GadgetMyChart.vue";

const COMPONENTS = {
"spark$gadget-my-chart": GadgetMyChart
};

const api = typeof window === "undefined" ? null : window.__SPARK_DASHBOARD__;
if (api && typeof api.registerGadgetComponent === "function") {
Object.entries(COMPONENTS).forEach(([key, component]) => {
api.registerGadgetComponent(key, component);
});
}

Workbench 載入 Dashboard catalog 後,會收集所有 frontendResource,去重後動態注入 <script>。腳本執行完成後,組件會進入宿主註冊表。

5. Vite 建構配置​

插件前端應使用 Vite library 模式,並將 Vue 設為 external。插件不打包自己的 Vue,而是使用宿主提供的 window.__SPARK_VUE__。

import { resolve } from "node:path";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
plugins: [vue()],
build: {
outDir: resolve(__dirname, "../../../target/classes/META-INF/resources/spark-gadgets/my-workbench-gadget"),
lib: {
entry: resolve(__dirname, "src/index.js"),
name: "MyWorkbenchGadget",
formats: ["umd"],
fileName: () => "index.umd.js",
cssFileName: "index"
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "__SPARK_VUE__"
}
}
}
}
});

建構後會得到:

target/classes/META-INF/resources/spark-gadgets/my-workbench-gadget/index.umd.js
target/classes/META-INF/resources/spark-gadgets/my-workbench-gadget/index.css

Spring Boot 會自動服務 META-INF/resources 下的靜態資源,因此運行期入口是:

/spark-gadgets/my-workbench-gadget/index.umd.js

6. Maven 打包​

插件 pom.xml 可透過 frontend-maven-plugin 在 prepare-package 階段建構前端。打包完成後,插件 jar 會同時包含 Java 擴展點與前端資源,平台只需要依賴這個插件 jar。

7. 組件開發約定​

  • 組件只接收 data 和 t 等宿主傳入的 props,不直接請求平台 API。
  • 樣式使用 scoped 與 Spark 主題變數,例如 --text-main、--card-bg、--primary。
  • 不要在插件中重新建立 Vue app,也不要打包獨立 Vue 運行時。
  • 資料結構由 renderGadget 返回,前端組件只負責展示。
  • 可配置項寫入 Gadget instance 的 config,由後端 render 時讀取。

8. 本機驗證清單​

cd src/main/frontend
npm ci
npm run build

然後在插件模組執行:

mvn -DskipTests package

檢查 jar 中是否包含:

META-INF/resources/spark-gadgets/<plugin-code>/index.umd.js
META-INF/resources/spark-gadgets/<plugin-code>/index.css

啟動 Spark Console 後,瀏覽:

/spark-gadgets/<plugin-code>/index.umd.js

如果能返回 JavaScript,表示插件前端已正確由 jar 提供。

9. 常見問題​

Gadget 顯示 Unsupported

通常是 component key 與 index.js 註冊 key 不一致,或 frontendResource 沒有正確載入。

樣式沒有生效

確認 Vite 是否生成 index.css,並確認入口腳本已注入同路徑 CSS。

Vue 運行期報錯

確認 Vite 中 Vue 已 external,且 output.globals.vue 指向 __SPARK_VUE__。插件不應打包第二份 Vue。

Catalog 中沒有出現插件

確認插件 jar 已被 Spark Console 依賴,且 @Realization(codes = "...") 的業務身份已被 Lattice 掃描。

10. 交付原則​

Dashboard Gadget 插件應遵循一個 artifact 自包含原則:

  • Java 擴展點在插件模組。
  • Vue 組件在插件模組。
  • 前端建構產物進入插件 jar。
  • 平台主工程只保留註冊表、動態載入器、卡片外殼與兜底組件。

這樣新增業務 Gadget 時,平台不需要修改核心程式碼,只需引入插件依賴即可完成擴展。