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

5.4 KiB

DevTools (run.halo.plugin.devtools)

A Gradle plugin for streamlined plugin development. Requires Docker.

Quick Commands

Command Purpose
./gradlew haloServer Start Halo in Docker with plugin loaded in dev mode
./gradlew reload Reload plugin changes without restarting Halo
./gradlew watch Auto-reload on file changes
./gradlew build Build plugin JAR (includes frontend build)
./gradlew generateApiClient Generate TypeScript API client from OpenAPI
./gradlew generateRoleTemplates Generate role template YAML from OpenAPI

build.gradle Setup

plugins {
    id 'java'
    id "io.freefair.lombok" version "8.13"
    id "run.halo.plugin.devtools" version "0.6.0"
}

group = 'com.example.myplugin'

repositories {
    mavenCentral()
}

dependencies {
    implementation platform('run.halo.tools.platform:plugin:2.22.0')
    compileOnly 'run.halo.app:api'

    testImplementation 'run.halo.app:api'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

test {
    useJUnitPlatform()
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

tasks.withType(JavaCompile).configureEach {
    options.encoding = "UTF-8"
    options.release = 21
}

// UI build integration (if UI is in a separate subproject)
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')
}

halo {
    version = '2.22'
    superAdminUsername = 'admin'
    superAdminPassword = 'admin'
    port = 8090
    // debug = true
    // debugPort = 5005
    // suspend = true
    externalUrl = 'http://localhost:8090'
}

halo {} Block Options

Option Description Default
version Halo Docker image version '2.9.1'
superAdminUsername Auto-created admin username 'admin'
superAdminPassword Auto-created admin password 'admin'
port Halo server port 8090
externalUrl External access URL 'http://localhost:8090'
debug Enable JDWP debug false
debugPort JDWP port auto-assigned
suspend Suspend on startup until debugger connects false
docker.url Docker daemon URL unix:///var/run/docker.sock (Mac/Linux)
docker.apiVersion Docker API version '1.42'

Watch Configuration

haloPlugin {
    watchDomains {
        consoleSource {
            files files('ui/src/')
            // exclude '**/node_modules/**'
        }
    }
}

Generate API Client

Requires OpenAPI grouping configuration in build.gradle:

haloPlugin {
    openApi {
        groupingRules {
            extensionApis {
                displayName = 'Extension API for MyPlugin'
                pathsToMatch = ['/apis/my-plugin.halo.run/v1alpha1/**']
            }
        }
        groupedApiMappings = [
            '/v3/api-docs/extensionApis': 'extensionApis.json'
        ]
        generator {
            outputDir = file("${projectDir}/ui/src/api/generated")
            additionalProperties = [
                useES6: true,
                useSingleRequestParameter: true,
                withSeparateModelsAndApi: true,
                apiPackage: "api",
                modelPackage: "models"
            ]
            typeMappings = [
                set: "Array"
            ]
        }
    }
}

Usage in TypeScript:

import { axiosInstance } from "@halo-dev/api-client";
import { MyResourceV1alpha1Api } from "./api/generated";

const api = new MyResourceV1alpha1Api(undefined, "", axiosInstance);
const { data } = await api.listMyResources({});

Generate Role Templates

After configuring OpenApi grouping, run:

./gradlew generateRoleTemplates

Generates roleTemplates.yaml in the workplace/ directory. Review and customize before adding to src/main/resources/extensions/.

Custom Halo Config

Place workplace/config/application.yaml to override Halo defaults:

logging:
  level:
    run.halo.app: DEBUG