Files
Serendipity edbf78f236 feat: 初始化 Halo 暗色模式插件
- Halo Plugin 后端(Java/Gradle),含 DarkModePlugin 主类和测试
- Vue 3 + TypeScript 前端 UI,包含主题切换组件和设置页面
- 暗色模式 CSS 变量和覆盖样式(布局/编辑器/表单/滚动条等)
- 设计文档和调查文档
- Halo 插件/主题开发 Agent Skills

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-06 21:03:00 +08:00

4.1 KiB

UI Build (@halo-dev/ui-plugin-bundler-kit)

Halo plugins use @halo-dev/ui-plugin-bundler-kit to build Vue/TypeScript frontend code into main.js + style.css.

Build Tool Options

Feature Vite Rsbuild (recommended for complex plugins)
Code splitting Limited Excellent
Build performance Good Excellent
Vue ecosystem Excellent Good
Dev experience Excellent Excellent
Dynamic imports Limited Excellent

Vite Setup

pnpm install @halo-dev/ui-plugin-bundler-kit@2.22.0 vite -D
// vite.config.ts
import { viteConfig } from "@halo-dev/ui-plugin-bundler-kit";

export default viteConfig();
// package.json
{
  "type": "module",
  "scripts": {
    "dev": "vite build --watch --mode=development",
    "build": "vite build"
  }
}

With Customizations

import { viteConfig } from "@halo-dev/ui-plugin-bundler-kit";
import path from "path";

export default viteConfig({
  vite: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
      },
    },
    plugins: [
      // Additional Vite plugins (Vue plugin is pre-configured)
    ],
  },
});

Rsbuild Setup

pnpm install @halo-dev/ui-plugin-bundler-kit@2.22.0 @rsbuild/core -D
// rsbuild.config.ts
import { rsbuildConfig } from "@halo-dev/ui-plugin-bundler-kit";

export default rsbuildConfig();
// package.json
{
  "type": "module",
  "scripts": {
    "dev": "rsbuild build --env-mode development --watch",
    "build": "rsbuild build"
  }
}

With Customizations

import { rsbuildConfig } from "@halo-dev/ui-plugin-bundler-kit";

export default rsbuildConfig({
  rsbuild: {
    source: {
      alias: {
        "@": "./src",
      },
    },
    plugins: [
      // Additional Rsbuild plugins
    ],
  },
});

Output Directories

Environment Output Path
Development build/resources/main/console/
Production ui/build/dist/ (temporary, Gradle copies to src/main/resources/console/ during build)

Dynamic Imports (Rsbuild)

import { definePlugin } from "@halo-dev/ui-shared";
import { defineAsyncComponent } from "vue";
import { VLoading } from "@halo-dev/components";

export default definePlugin({
  routes: [
    {
      parentName: "Root",
      route: {
        path: "heavy-page",
        name: "HeavyPage",
        component: defineAsyncComponent({
          loader: () => import("./views/HeavyPage.vue"),
          loadingComponent: VLoading,
        }),
      },
    },
  ],
});

Gradle Integration

In the root build.gradle:

tasks.register('processUiResources', Copy) {
    from project(':ui').layout.buildDirectory.dir('dist')
    into layout.buildDirectory.dir('resources/main/console')
    dependsOn project(':ui').tasks.named('assemble')
    shouldRunAfter tasks.named('processResources')
}

tasks.named('classes') {
    dependsOn tasks.named('processUiResources')
}

In ui/build.gradle:

plugins {
    id 'base'
    id "com.github.node-gradle.node" version "7.1.0"
}

tasks.register('buildFrontend', PnpmTask) {
    group = 'build'
    args = ['build']
    dependsOn tasks.named('pnpmInstall')
    inputs.dir(layout.projectDirectory.dir('src'))
    outputs.dir(layout.buildDirectory.dir('dist'))
}

tasks.named('assemble') {
    dependsOn tasks.named('buildFrontend')
}