docs: update documentations for plugin development (#504)

```release-note
None
```
This commit is contained in:
Ryan Wang
2025-06-24 15:15:13 +08:00
committed by GitHub
parent 7e097c93f9
commit 90d3104d0d
15 changed files with 285 additions and 471 deletions

View File

@@ -9,7 +9,7 @@ Devtools 还提供了一些其他的构建任务,如插件打包、插件检
## 安装
Devtools 是使用 Java 开发的一个 [Gradle](https://gradle.org/) 插件,如果你使用的 [plugin-starter](https://github.com/halo-sigs/plugin-starter) 创建的插件项目,那么你无需任何操作,它已经默认集成了 Devtools 插件。
Devtools 是使用 Java 开发的一个 [Gradle](https://gradle.org/) 插件,如果你使用的 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建的插件项目,那么你无需任何操作,它已经默认集成了 Devtools 插件。
你可以在项目的 `build.gradle` 中找到它:

View File

@@ -3,19 +3,19 @@ title: 构建
description: UI 部分的构建说明
---
在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中,我们已经配置好了 UI 的构建工具和流程,此文档主要说明一些构建细节以及其他可能的构建选项。
在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 工具中,我们已经配置好了 UI 的构建工具和流程,此文档主要说明一些构建细节以及其他可能的构建选项。
## 原理
Halo 插件的 UI 部分Console / UC的实现方式其实很简单本质上就是构建一个结构固定的大对象交给 Halo 去解析,其中包括全局注册的组件、路由定义、扩展点等。在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中,我们使用 `index.ts` 作为入口文件,并在构建之后将 `main.js``style.css` 放到插件项目的 `src/main/resources/console` 目录中,后续 Halo 在内部会自动合并所有插件的 `main.js``style.css` 文件,并生成最终的 `bundle.js``bundle.css` 文件,然后在 Console 和 UC 中加载这两个资源并解析。
Halo 插件的 UI 部分Console / UC的实现方式其实很简单本质上就是构建一个结构固定的大对象交给 Halo 去解析,其中包括全局注册的组件、路由定义、扩展点等。在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 工具创建的项目中,我们使用 `index.ts` 作为入口文件,并在构建之后将 `main.js``style.css` 放到插件项目的 `src/main/resources/console` 目录中,后续 Halo 在内部会自动合并所有插件的 `main.js``style.css` 文件,并生成最终的 `bundle.js``bundle.css` 文件,然后在 Console 和 UC 中加载这两个资源并解析。
所以本质上,我们只需要使用支持将 `index.ts` 编译为 `main.js``style.css` 的工具,然后输出到插件项目的 `src/main/resources/console` 目录中即可,在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中可以看到,我们提供了一个名为 `@halo-dev/ui-plugin-bundler-kit` 的库,这个库包含了 [Vite](https://vite.dev/) 和 [Rsbuild](https://rsbuild.dev/) 的预配置,插件项目只需要通过简单的配置即可使用。
所以本质上,我们只需要使用支持将 `index.ts` 编译为 `main.js``style.css` 的工具,然后输出到插件项目的 `src/main/resources/console` 目录中即可,在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 模板中可以看到,我们提供了一个名为 `@halo-dev/ui-plugin-bundler-kit` 的库,这个库包含了 [Vite](https://vite.dev/) 和 [Rsbuild](https://rsbuild.dev/) 的预配置,插件项目只需要通过简单的配置即可使用。
## @halo-dev/ui-plugin-bundler-kit
在这个库中,我们提供了三个预配置,分别是:
1. `viteConfig`: Vite 的预配置[halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中默认使用的配置
1. `viteConfig`: Vite 的预配置
2. `rsbuildConfig`: Rsbuild 的预配置
3. `HaloUIPluginBundlerKit`:已过时,迁移方式可以参考下面的文档
@@ -23,7 +23,33 @@ Halo 插件的 UI 部分Console / UC的实现方式其实很简单
#### 使用
如果你想要使用 Vite 构建 UI 部分,那么使用 `viteConfig` 即可,并且已经在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中配置,直接使用即可
如果你在通过 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建项目时没有选择使用 Vite 作为 UI 的构建工具,那么可以通过以下方式改为使用 Vite
安装依赖:
```bash
pnpm install @halo-dev/ui-plugin-bundler-kit@2.21.1 vite -D
```
创建 vite.config.ts:
```js
import { viteConfig } from "@halo-dev/ui-plugin-bundler-kit";
export default viteConfig()
```
更新 package.json:
```json
{
"type": "module",
"scripts": {
"dev": "vite build --watch --mode=development",
"build": "vite build"
}
}
```
#### 配置
@@ -83,7 +109,7 @@ Rsbuild 是基于 Rspack 开发的上层构建工具,其优势在于兼容 Web
#### 使用
因为在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中,默认采用 Vite 构建,所以如果想要使用 Rsbuild 构建,需要手动配置,以下是切换到 Rsbuild 的过程:
如果你在通过 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建项目时没有选择使用 Rsbuild 作为 UI 的构建工具,那么可以通过以下方式改为使用 Rsbuild
安装依赖:
@@ -91,7 +117,7 @@ Rsbuild 是基于 Rspack 开发的上层构建工具,其优势在于兼容 Web
pnpm install @halo-dev/ui-plugin-bundler-kit@2.21.1 @rsbuild/core -D
```
创建 rsbuild.config.mjs:
创建 rsbuild.config.ts:
```js
import { rsbuildConfig } from "@halo-dev/ui-plugin-bundler-kit";
@@ -255,74 +281,56 @@ export default definePlugin({
3. 更新项目根目录的 `build.gradle` 文件
```diff
```gradle
plugins {
id 'java'
- id "com.github.node-gradle.node" version "7.0.2"
- id "io.freefair.lombok" version "8.0.1"
- id "run.halo.plugin.devtools" version "0.2.0"
+ id "io.freefair.lombok" version "8.13"
+ id "run.halo.plugin.devtools" version "0.6.0"
id "io.freefair.lombok" version "8.13"
id "run.halo.plugin.devtools" version "0.6.0"
}
group 'run.halo.starter'
-sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
- maven { url 'https://s01.oss.sonatype.org/content/repositories/releases' }
- maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
- maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
- implementation platform('run.halo.tools.platform:plugin:2.20.0-SNAPSHOT')
+ implementation platform('run.halo.tools.platform:plugin:2.21.0')
implementation platform('run.halo.tools.platform:plugin:2.21.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'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
test {
useJUnitPlatform()
}
-tasks.withType(JavaCompile).configureEach {
- options.encoding = "UTF-8"
-}
-
-node {
- nodeProjectDir = file("${project.projectDir}/ui")
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
-tasks.register('buildFrontend', PnpmTask) {
- args = ['build']
- dependsOn('installDepsForUI')
+tasks.withType(JavaCompile).configureEach {
+ options.encoding = "UTF-8"
+ options.release = 21
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.release = 21
}
-tasks.register('installDepsForUI', PnpmTask) {
- args = ['install']
+tasks.register('processUiResources', Copy) {
+ from project(':ui').tasks.named('buildFrontend')
+ into layout.buildDirectory.dir('resources/main/console')
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')
}
-build {
- // build frontend before build
- tasks.named('compileJava').configure {
- dependsOn('buildFrontend')
- }
+tasks.named('processResources', ProcessResources) {
+ dependsOn tasks.named('processUiResources')
tasks.named('classes') {
dependsOn tasks.named('processUiResources')
}
halo {
version = '2.21'
}
```
@@ -330,41 +338,42 @@ export default definePlugin({
```gradle
plugins {
id 'base'
id "com.github.node-gradle.node" version "7.1.0"
id 'base'
id "com.github.node-gradle.node" version "7.1.0"
}
group 'run.halo.starter.ui'
tasks.register('buildFrontend', PnpmTask) {
args = ['build']
dependsOn tasks.named('pnpmInstall')
inputs.dir(layout.projectDirectory.dir('src'))
inputs.files(fileTree(
dir: layout.projectDirectory,
includes: ['*.cjs', '*.ts', '*.js', '*.json', '*.yaml']))
outputs.dir(layout.buildDirectory.dir('dist'))
shouldRunAfter(tasks.named('check'))
group = 'build'
description = 'Builds the UI project using pnpm.'
args = ['build']
dependsOn tasks.named('pnpmInstall')
inputs.dir(layout.projectDirectory.dir('src'))
inputs.files(fileTree(
dir: layout.projectDirectory,
includes: ['*.cjs', '*.ts', '*.js', '*.json', '*.yaml']))
outputs.dir(layout.buildDirectory.dir('dist'))
}
tasks.register('checkFrontend', PnpmTask) {
args = ['test:unit']
dependsOn tasks.named('pnpmInstall')
tasks.register('pnpmCheck', PnpmTask) {
group = 'verification'
description = 'Runs unit tests using pnpm.'
args = ['test:unit']
dependsOn tasks.named('pnpmInstall')
}
tasks.named('check') {
dependsOn tasks.named('checkFrontend')
dependsOn tasks.named('pnpmCheck')
}
tasks.named('build') {
dependsOn tasks.named('buildFrontend')
tasks.named('assemble') {
dependsOn tasks.named('buildFrontend')
}
```
进行此变更的主要目的是保证 UI 构建的产物不直接输出到源码目录的 resources 目录中,而是通过 Gradle 构建插件时复制到 `src/main/resources/console` 目录中。
完整变更过程可参考:[halo-dev/plugin-starter#52](https://github.com/halo-dev/plugin-starter/pull/52)
如果你不想使用新的 Gradle 构建配置,也可以修改 viteConfig 或 rsbuildConfig 的输出目录,和旧版本保持一致:
viteConfig:

View File

@@ -5,7 +5,7 @@ description: UI 扩展部分的入口文件
入口文件即 Halo 核心会加载的文件,所有插件有且只有一个入口文件,构建之后会放置在插件项目的 `src/resources/console` 下,名为 `main.js`
为了方便开发者,我们已经在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 配置好了基础项目结构,包括构建配置,后续文档也会以此为准。
为了方便开发者,我们已经在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 配置好了基础项目结构,包括构建配置,后续文档也会以此为准。
## 定义入口文件

View File

@@ -5,104 +5,9 @@ description: 这个例子展示了如何开发 Todo List 插件
本示例用于展示如何从插件模板创建一个插件并写一个 Todo List
首先通过模板仓库创建一个插件,例如叫 `halo-plugin-todolist`
首先参考 [入门 - 创建插件项目](../hello-world.md#创建插件项目) 文档创建一个新的插件项目并运行。
## 配置你的插件
1. 修改 `build.gradle` 中的 `group` 为你自己的,如:
```groovy
group = 'run.halo.tutorial'
```
2. 修改 `settings.gradle` 中的 `rootProject.name`
```groovy
rootProject.name = 'halo-plugin-todolist'
```
3. 修改插件的描述文件 `plugin.yaml`,它位于 `src/main/resources/plugin.yaml`。示例:
```yaml
apiVersion: plugin.halo.run/v1alpha1
kind: Plugin
metadata:
name: todolist
spec:
enabled: true
requires: ">=2.0.0"
author:
name: halo-dev
website: https://www.halo.run
logo: https://www.halo.run/logo
homepage: https://github.com/halo-dev/plugin-starter#readme
repo: https://github.com/halo-dev/plugin-starter
issues: https://github.com/halo-dev/plugin-starter/issues
displayName: "插件 Todo List"
description: "插件开发的 hello world用于学习如何开发一个简单的 Halo 插件"
license:
- name: "GPL-3.0"
url: "https://github.com/halo-dev/plugin-starter/blob/main/LICENSE"
```
参考链接:
- [SemVer expression](https://github.com/zafarkhaja/jsemver#semver-expressions-api-ranges)
- [表单定义](../../form-schema.md)
此时我们已经准备好了可以开发一个 TodoList 插件的一切,下面让我们正式进入 TodoList 插件开发教程。
## 运行插件
为了看到效果,首先我们需要让插件能最简单的运行起来。
1. 在 `src/main/java` 下创建包,如 `run.halo.tutorial`,在创建一个类 `TodoListPlugin`,它继承自 `BasePlugin` 类内容如下:
```java
package run.halo.tutorial;
import run.halo.app.plugin.PluginContext;
import org.springframework.stereotype.Component;
import run.halo.app.plugin.BasePlugin;
@Component
public class TodoListPlugin extends BasePlugin {
public TodoListPlugin(PluginContext pluginContext) {
super(pluginContext);
}
}
```
`src/main/java` 下的文件结构如下:
```text
.
└── run
└── halo
└── tutorial
└── TodoListPlugin.java
```
2. 然后在项目目录执行命令
```shell
./gradlew build
```
3. 使用 `IntelliJ IDEA` 打开 Halo参考 [Halo 开发环境运行](../../core/run.md) 及 [插件入门](../hello-world.md) 配置插件的运行模式和路径:
```yaml
halo:
plugin:
runtime-mode: development
fixed-plugin-path:
# 配置为插件绝对路径
- /Users/guqing/halo-plugin-todolist
```
4. 启动 Halo然后访问 `http://localhost:8090/console`
在插件列表将能看到插件已经被正确启用:
如果能在插件列表中看到插件已经被正确启用,则说明插件已经运行成功。
![plugin-todolist-in-list-view](/img/todolist-in-list.png)

View File

@@ -7,25 +7,38 @@ description: 了解如何构建你的第一个插件并在 Halo 中使用它。
## 创建插件项目
1. 打开 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter)
我们为插件开发者提供了一个插件创建工具,可以帮助你快速创建一个插件项目
> 这是一个插件的初始模板,你可以基于它来开发自己的插件。
2. 点击 `Use this template` -> `Create a new repository`
3. 如图所示填写仓库名后点击 `Create repository from template`
![create-repository-for-hello-world-plugin](/img/create-repository-for-hello-world-plugin.png)
你现在已经基于 Halo 插件模板创建了自己的存储库。接下来,你需要将它克隆到你的计算机上。
```shell
# clone your repository
git clone https://github.com/<your-username>/halo-plugin-hello-world.git
# enter the directory
cd halo-plugin-hello-world
```bash
pnpm create halo-plugin
```
```bash
🚀 Welcome to Halo Plugin Creator!
✔ Plugin name: hello-world
✔ Domain (for group and package name): com.example
✔ Author name: Halo
✔ Choose UI build tool: Rsbuild
📋 Project Configuration:
Name: hello-world
Domain: com.example
Package: com.example.hello-world
Author: Halo
UI Tool: rsbuild
Output Directory: /path/to/hello-world
✔ Create project? yes
```
- **Plugin name**: 插件的名称,用于插件的标识,此字段必须由小写字母、数字和连字符组成
- **Domain**: 插件的包名
- **Author name**: 插件的作者
- **Choose UI build tool**: 插件的 UI 构建工具,目前支持 `Rsbuild``Vite`
更多关于插件创建工具的信息可查阅:[halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin)
## 运行插件
现在有了一个空项目,我们需要让插件能最最小化的运行起来,这里提供两种运行方式。
@@ -36,17 +49,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
使用 DevTools 运行插件的前提是需要你的电脑上已经安装了 Docker 环境,这是我们推荐的用户开发时运行插件的方式,只需要执行以下命令即可。
1. 执行前端部分的依赖安装命令
```shell
# macOS / Linux
./gradlew pnpmInstall
# Windows
./gradlew.bat pnpmInstall
```
2. 运行插件:
1. 运行插件
```shell
# macOS / Linux
@@ -58,7 +61,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
执行此命令后,会自动创建一个 Halo 的 Docker 容器并加载当前的插件。
3. 启动成功后,可以看到如下日志输出:
2. 启动成功后,可以看到如下日志输出:
```shell
Halo 初始化成功访问http://localhost:8090/console
@@ -78,17 +81,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
但由于此方式需要先使用源码运行 Halo 才能启动插件,请确保已经在开发环境运行了 Halo可以参考 [Halo 开发环境运行](../core/run.md)
1. 安装前端部分的依赖
```shell
# macOS / Linux
./gradlew pnpmInstall
# Windows
./gradlew.bat pnpmInstall
```
2. 编译插件
1. 编译插件
```shell
# macOS / Linux
@@ -98,7 +91,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
./gradlew.bat build
```
3. 修改 Halo 配置文件:
2. 修改 Halo 配置文件:
```shell
# 进入 Halo 项目根目录后,使用 cd 命令进入配置文件目录
@@ -128,7 +121,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
- C:\path\to\halo-plugin-hello-world
```
4. 启动 Halo
3. 启动 Halo
```shell
# macOS / Linux

View File

@@ -11,7 +11,7 @@ description: 了解如何与我们的社区分享你的插件
## 自动构建
如果你是基于 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 创建的插件项目,那么已经包含了适用于 GitHub Action 的 `ci.yaml``cd.yaml` 文件,里面包含了构建插件和发布插件资源到 Release 的步骤,可以根据自己的实际需要进行修改,以下是示例:
如果你是使用 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建的插件项目,那么已经包含了适用于 GitHub Action 的 `ci.yaml``cd.yaml` 文件,里面包含了构建插件和发布插件资源到 Release 的步骤,可以根据自己的实际需要进行修改,以下是示例:
```yaml
name: CI

View File

@@ -80,7 +80,7 @@ export default definePlugin({
});
```
参考:[plugin-starter](https://github.com/halo-dev/plugin-starter/blob/5a4a25db252a7986900368a5fbf35e8d27f5257f/ui/src/index.ts#L6-L29)
参考:[halo-dev/create-halo-plugin#template/ui/src/index.ts](https://github.com/halo-dev/create-halo-plugin/blob/a4ce935a637faff4a7f00fecbdee08f55fd66ffd/template/ui/src/index.ts)
> 该配置示例为在插件前端部分入口文件 `index.ts`

View File

@@ -9,6 +9,10 @@
"message": "页面已崩溃。",
"description": "The title of the fallback page when the page crashed"
},
"theme.BackToTopButton.buttonAriaLabel": {
"message": "回到顶部",
"description": "The ARIA label for the back to top button"
},
"theme.blog.archive.title": {
"message": "历史博文",
"description": "The page & hero title of the blog archive page"
@@ -17,10 +21,6 @@
"message": "历史博文",
"description": "The page & hero description of the blog archive page"
},
"theme.BackToTopButton.buttonAriaLabel": {
"message": "回到顶部",
"description": "The ARIA label for the back to top button"
},
"theme.blog.paginator.navAriaLabel": {
"message": "博文列表分页导航",
"description": "The ARIA label for the blog pagination"
@@ -65,14 +65,14 @@
"message": "切换浅色/暗黑模式(当前为{mode}",
"description": "The ARIA label for the color mode toggle"
},
"theme.docs.DocCard.categoryDescription.plurals": {
"message": "{count} 个项目",
"description": "The default description for a category card in the generated index about how many items this category includes"
},
"theme.docs.breadcrumbs.navAriaLabel": {
"message": "页面路径",
"description": "The ARIA label for the breadcrumbs"
},
"theme.docs.DocCard.categoryDescription.plurals": {
"message": "{count} 个项目",
"description": "The default description for a category card in the generated index about how many items this category includes"
},
"theme.docs.paginator.navAriaLabel": {
"message": "文件选项卡",
"description": "The ARIA label for the docs pagination"
@@ -96,6 +96,10 @@
"theme.docs.versionBadge.label": {
"message": "版本:{versionLabel}"
},
"theme.common.editThisPage": {
"message": "编辑此页",
"description": "The link label to edit the current page"
},
"theme.docs.versions.unreleasedVersionLabel": {
"message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
"description": "The label used to tell the user that he's browsing an unreleased doc version"
@@ -112,10 +116,6 @@
"message": "最新版本",
"description": "The label used for the latest version suggestion link label"
},
"theme.common.editThisPage": {
"message": "编辑此页",
"description": "The link label to edit the current page"
},
"theme.common.headingLinkTitle": {
"message": "{heading}的直接链接",
"description": "Title for link to heading"
@@ -168,14 +168,14 @@
"message": "注意",
"description": "The default label used for the Warning admonition (:::warning)"
},
"theme.blog.sidebar.navAriaLabel": {
"message": "最近博文导航",
"description": "The ARIA label for recent posts in the blog sidebar"
},
"theme.AnnouncementBar.closeButtonAriaLabel": {
"message": "关闭",
"description": "The ARIA label for close button of announcement bar"
},
"theme.blog.sidebar.navAriaLabel": {
"message": "最近博文导航",
"description": "The ARIA label for recent posts in the blog sidebar"
},
"theme.DocSidebarItem.expandCategoryAriaLabel": {
"message": "展开侧边栏分类 '{label}'",
"description": "The ARIA label to expand the sidebar category"
@@ -204,6 +204,10 @@
"message": "本页总览",
"description": "The label used by the button on the collapsible TOC component"
},
"theme.blog.post.readingTime.plurals": {
"message": "阅读需 {readingTime} 分钟",
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.blog.post.readMore": {
"message": "阅读更多",
"description": "The label used in blog post item excerpts to link to full blog posts"
@@ -212,21 +216,9 @@
"message": "阅读 {title} 的全文",
"description": "The ARIA label for the link to full blog posts from excerpts"
},
"theme.blog.post.readingTime.plurals": {
"message": "阅读需 {readingTime} 分钟",
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.CodeBlock.copy": {
"message": "复制",
"description": "The copy button label on code blocks"
},
"theme.CodeBlock.copied": {
"message": "复制成功",
"description": "The copied button label on code blocks"
},
"theme.CodeBlock.copyButtonAriaLabel": {
"message": "复制代码到剪贴板",
"description": "The ARIA label for copy code blocks button"
"theme.docs.breadcrumbs.home": {
"message": "主页面",
"description": "The ARIA label for the home page in the breadcrumbs"
},
"theme.CodeBlock.wordWrapToggle": {
"message": "切换自动换行",
@@ -244,13 +236,17 @@
"message": "文档侧边栏",
"description": "The ARIA label for the sidebar navigation"
},
"theme.docs.breadcrumbs.home": {
"message": "主页面",
"description": "The ARIA label for the home page in the breadcrumbs"
"theme.CodeBlock.copy": {
"message": "复制",
"description": "The copy button label on code blocks"
},
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
"message": "关闭导航栏",
"description": "The ARIA label for close button of mobile sidebar"
"theme.CodeBlock.copied": {
"message": "复制成功",
"description": "The copied button label on code blocks"
},
"theme.CodeBlock.copyButtonAriaLabel": {
"message": "复制代码到剪贴板",
"description": "The ARIA label for copy code blocks button"
},
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
"message": "← 回到主菜单",
@@ -260,6 +256,10 @@
"message": "切换导航栏",
"description": "The ARIA label for hamburger menu button of mobile navigation"
},
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
"message": "关闭导航栏",
"description": "The ARIA label for close button of mobile sidebar"
},
"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel": {
"message": "Expand the dropdown",
"description": "The ARIA label of the button to expand the mobile dropdown navbar item"

View File

@@ -9,7 +9,7 @@ Devtools 还提供了一些其他的构建任务,如插件打包、插件检
## 安装
Devtools 是使用 Java 开发的一个 [Gradle](https://gradle.org/) 插件,如果你使用的 [plugin-starter](https://github.com/halo-sigs/plugin-starter) 创建的插件项目,那么你无需任何操作,它已经默认集成了 Devtools 插件。
Devtools 是使用 Java 开发的一个 [Gradle](https://gradle.org/) 插件,如果你使用的 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建的插件项目,那么你无需任何操作,它已经默认集成了 Devtools 插件。
你可以在项目的 `build.gradle` 中找到它:

View File

@@ -3,19 +3,19 @@ title: 构建
description: UI 部分的构建说明
---
在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中,我们已经配置好了 UI 的构建工具和流程,此文档主要说明一些构建细节以及其他可能的构建选项。
在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 工具中,我们已经配置好了 UI 的构建工具和流程,此文档主要说明一些构建细节以及其他可能的构建选项。
## 原理
Halo 插件的 UI 部分Console / UC的实现方式其实很简单本质上就是构建一个结构固定的大对象交给 Halo 去解析,其中包括全局注册的组件、路由定义、扩展点等。在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中,我们使用 `index.ts` 作为入口文件,并在构建之后将 `main.js``style.css` 放到插件项目的 `src/main/resources/console` 目录中,后续 Halo 在内部会自动合并所有插件的 `main.js``style.css` 文件,并生成最终的 `bundle.js``bundle.css` 文件,然后在 Console 和 UC 中加载这两个资源并解析。
Halo 插件的 UI 部分Console / UC的实现方式其实很简单本质上就是构建一个结构固定的大对象交给 Halo 去解析,其中包括全局注册的组件、路由定义、扩展点等。在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 工具创建的项目中,我们使用 `index.ts` 作为入口文件,并在构建之后将 `main.js``style.css` 放到插件项目的 `src/main/resources/console` 目录中,后续 Halo 在内部会自动合并所有插件的 `main.js``style.css` 文件,并生成最终的 `bundle.js``bundle.css` 文件,然后在 Console 和 UC 中加载这两个资源并解析。
所以本质上,我们只需要使用支持将 `index.ts` 编译为 `main.js``style.css` 的工具,然后输出到插件项目的 `src/main/resources/console` 目录中即可,在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 模板中可以看到,我们提供了一个名为 `@halo-dev/ui-plugin-bundler-kit` 的库,这个库包含了 [Vite](https://vite.dev/) 和 [Rsbuild](https://rsbuild.dev/) 的预配置,插件项目只需要通过简单的配置即可使用。
所以本质上,我们只需要使用支持将 `index.ts` 编译为 `main.js``style.css` 的工具,然后输出到插件项目的 `src/main/resources/console` 目录中即可,在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 模板中可以看到,我们提供了一个名为 `@halo-dev/ui-plugin-bundler-kit` 的库,这个库包含了 [Vite](https://vite.dev/) 和 [Rsbuild](https://rsbuild.dev/) 的预配置,插件项目只需要通过简单的配置即可使用。
## @halo-dev/ui-plugin-bundler-kit
在这个库中,我们提供了三个预配置,分别是:
1. `viteConfig`: Vite 的预配置[halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中默认使用的配置
1. `viteConfig`: Vite 的预配置
2. `rsbuildConfig`: Rsbuild 的预配置
3. `HaloUIPluginBundlerKit`:已过时,迁移方式可以参考下面的文档
@@ -23,7 +23,33 @@ Halo 插件的 UI 部分Console / UC的实现方式其实很简单
#### 使用
如果你想要使用 Vite 构建 UI 部分,那么使用 `viteConfig` 即可,并且已经在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中配置,直接使用即可
如果你在通过 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建项目时没有选择使用 Vite 作为 UI 的构建工具,那么可以通过以下方式改为使用 Vite
安装依赖:
```bash
pnpm install @halo-dev/ui-plugin-bundler-kit@2.21.1 vite -D
```
创建 vite.config.ts:
```js
import { viteConfig } from "@halo-dev/ui-plugin-bundler-kit";
export default viteConfig()
```
更新 package.json:
```json
{
"type": "module",
"scripts": {
"dev": "vite build --watch --mode=development",
"build": "vite build"
}
}
```
#### 配置
@@ -83,7 +109,7 @@ Rsbuild 是基于 Rspack 开发的上层构建工具,其优势在于兼容 Web
#### 使用
因为在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 中,默认采用 Vite 构建,所以如果想要使用 Rsbuild 构建,需要手动配置,以下是切换到 Rsbuild 的过程:
如果你在通过 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建项目时没有选择使用 Rsbuild 作为 UI 的构建工具,那么可以通过以下方式改为使用 Rsbuild
安装依赖:
@@ -91,7 +117,7 @@ Rsbuild 是基于 Rspack 开发的上层构建工具,其优势在于兼容 Web
pnpm install @halo-dev/ui-plugin-bundler-kit@2.21.1 @rsbuild/core -D
```
创建 rsbuild.config.mjs:
创建 rsbuild.config.ts:
```js
import { rsbuildConfig } from "@halo-dev/ui-plugin-bundler-kit";
@@ -255,74 +281,56 @@ export default definePlugin({
3. 更新项目根目录的 `build.gradle` 文件
```diff
```gradle
plugins {
id 'java'
- id "com.github.node-gradle.node" version "7.0.2"
- id "io.freefair.lombok" version "8.0.1"
- id "run.halo.plugin.devtools" version "0.2.0"
+ id "io.freefair.lombok" version "8.13"
+ id "run.halo.plugin.devtools" version "0.6.0"
id "io.freefair.lombok" version "8.13"
id "run.halo.plugin.devtools" version "0.6.0"
}
group 'run.halo.starter'
-sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
- maven { url 'https://s01.oss.sonatype.org/content/repositories/releases' }
- maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
- maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
- implementation platform('run.halo.tools.platform:plugin:2.20.0-SNAPSHOT')
+ implementation platform('run.halo.tools.platform:plugin:2.21.0')
implementation platform('run.halo.tools.platform:plugin:2.21.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'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
test {
useJUnitPlatform()
}
-tasks.withType(JavaCompile).configureEach {
- options.encoding = "UTF-8"
-}
-
-node {
- nodeProjectDir = file("${project.projectDir}/ui")
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
-tasks.register('buildFrontend', PnpmTask) {
- args = ['build']
- dependsOn('installDepsForUI')
+tasks.withType(JavaCompile).configureEach {
+ options.encoding = "UTF-8"
+ options.release = 21
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.release = 21
}
-tasks.register('installDepsForUI', PnpmTask) {
- args = ['install']
+tasks.register('processUiResources', Copy) {
+ from project(':ui').tasks.named('buildFrontend')
+ into layout.buildDirectory.dir('resources/main/console')
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')
}
-build {
- // build frontend before build
- tasks.named('compileJava').configure {
- dependsOn('buildFrontend')
- }
+tasks.named('processResources', ProcessResources) {
+ dependsOn tasks.named('processUiResources')
tasks.named('classes') {
dependsOn tasks.named('processUiResources')
}
halo {
version = '2.21'
}
```
@@ -330,41 +338,42 @@ export default definePlugin({
```gradle
plugins {
id 'base'
id "com.github.node-gradle.node" version "7.1.0"
id 'base'
id "com.github.node-gradle.node" version "7.1.0"
}
group 'run.halo.starter.ui'
tasks.register('buildFrontend', PnpmTask) {
args = ['build']
dependsOn tasks.named('pnpmInstall')
inputs.dir(layout.projectDirectory.dir('src'))
inputs.files(fileTree(
dir: layout.projectDirectory,
includes: ['*.cjs', '*.ts', '*.js', '*.json', '*.yaml']))
outputs.dir(layout.buildDirectory.dir('dist'))
shouldRunAfter(tasks.named('check'))
group = 'build'
description = 'Builds the UI project using pnpm.'
args = ['build']
dependsOn tasks.named('pnpmInstall')
inputs.dir(layout.projectDirectory.dir('src'))
inputs.files(fileTree(
dir: layout.projectDirectory,
includes: ['*.cjs', '*.ts', '*.js', '*.json', '*.yaml']))
outputs.dir(layout.buildDirectory.dir('dist'))
}
tasks.register('checkFrontend', PnpmTask) {
args = ['test:unit']
dependsOn tasks.named('pnpmInstall')
tasks.register('pnpmCheck', PnpmTask) {
group = 'verification'
description = 'Runs unit tests using pnpm.'
args = ['test:unit']
dependsOn tasks.named('pnpmInstall')
}
tasks.named('check') {
dependsOn tasks.named('checkFrontend')
dependsOn tasks.named('pnpmCheck')
}
tasks.named('build') {
dependsOn tasks.named('buildFrontend')
tasks.named('assemble') {
dependsOn tasks.named('buildFrontend')
}
```
进行此变更的主要目的是保证 UI 构建的产物不直接输出到源码目录的 resources 目录中,而是通过 Gradle 构建插件时复制到 `src/main/resources/console` 目录中。
完整变更过程可参考:[halo-dev/plugin-starter#52](https://github.com/halo-dev/plugin-starter/pull/52)
如果你不想使用新的 Gradle 构建配置,也可以修改 viteConfig 或 rsbuildConfig 的输出目录,和旧版本保持一致:
viteConfig:

View File

@@ -5,7 +5,7 @@ description: UI 扩展部分的入口文件
入口文件即 Halo 核心会加载的文件,所有插件有且只有一个入口文件,构建之后会放置在插件项目的 `src/resources/console` 下,名为 `main.js`
为了方便开发者,我们已经在 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 配置好了基础项目结构,包括构建配置,后续文档也会以此为准。
为了方便开发者,我们已经在 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 配置好了基础项目结构,包括构建配置,后续文档也会以此为准。
## 定义入口文件

View File

@@ -5,104 +5,9 @@ description: 这个例子展示了如何开发 Todo List 插件
本示例用于展示如何从插件模板创建一个插件并写一个 Todo List
首先通过模板仓库创建一个插件,例如叫 `halo-plugin-todolist`
首先参考 [入门 - 创建插件项目](../hello-world.md#创建插件项目) 文档创建一个新的插件项目并运行。
## 配置你的插件
1. 修改 `build.gradle` 中的 `group` 为你自己的,如:
```groovy
group = 'run.halo.tutorial'
```
2. 修改 `settings.gradle` 中的 `rootProject.name`
```groovy
rootProject.name = 'halo-plugin-todolist'
```
3. 修改插件的描述文件 `plugin.yaml`,它位于 `src/main/resources/plugin.yaml`。示例:
```yaml
apiVersion: plugin.halo.run/v1alpha1
kind: Plugin
metadata:
name: todolist
spec:
enabled: true
requires: ">=2.0.0"
author:
name: halo-dev
website: https://www.halo.run
logo: https://www.halo.run/logo
homepage: https://github.com/halo-dev/plugin-starter#readme
repo: https://github.com/halo-dev/plugin-starter
issues: https://github.com/halo-dev/plugin-starter/issues
displayName: "插件 Todo List"
description: "插件开发的 hello world用于学习如何开发一个简单的 Halo 插件"
license:
- name: "GPL-3.0"
url: "https://github.com/halo-dev/plugin-starter/blob/main/LICENSE"
```
参考链接:
- [SemVer expression](https://github.com/zafarkhaja/jsemver#semver-expressions-api-ranges)
- [表单定义](../../form-schema.md)
此时我们已经准备好了可以开发一个 TodoList 插件的一切,下面让我们正式进入 TodoList 插件开发教程。
## 运行插件
为了看到效果,首先我们需要让插件能最简单的运行起来。
1. 在 `src/main/java` 下创建包,如 `run.halo.tutorial`,在创建一个类 `TodoListPlugin`,它继承自 `BasePlugin` 类内容如下:
```java
package run.halo.tutorial;
import run.halo.app.plugin.PluginContext;
import org.springframework.stereotype.Component;
import run.halo.app.plugin.BasePlugin;
@Component
public class TodoListPlugin extends BasePlugin {
public TodoListPlugin(PluginContext pluginContext) {
super(pluginContext);
}
}
```
`src/main/java` 下的文件结构如下:
```text
.
└── run
└── halo
└── tutorial
└── TodoListPlugin.java
```
2. 然后在项目目录执行命令
```shell
./gradlew build
```
3. 使用 `IntelliJ IDEA` 打开 Halo参考 [Halo 开发环境运行](../../core/run.md) 及 [插件入门](../hello-world.md) 配置插件的运行模式和路径:
```yaml
halo:
plugin:
runtime-mode: development
fixed-plugin-path:
# 配置为插件绝对路径
- /Users/guqing/halo-plugin-todolist
```
4. 启动 Halo然后访问 `http://localhost:8090/console`
在插件列表将能看到插件已经被正确启用:
如果能在插件列表中看到插件已经被正确启用,则说明插件已经运行成功。
![plugin-todolist-in-list-view](/img/todolist-in-list.png)

View File

@@ -7,25 +7,38 @@ description: 了解如何构建你的第一个插件并在 Halo 中使用它。
## 创建插件项目
1. 打开 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter)
我们为插件开发者提供了一个插件创建工具,可以帮助你快速创建一个插件项目
> 这是一个插件的初始模板,你可以基于它来开发自己的插件。
2. 点击 `Use this template` -> `Create a new repository`
3. 如图所示填写仓库名后点击 `Create repository from template`
![create-repository-for-hello-world-plugin](/img/create-repository-for-hello-world-plugin.png)
你现在已经基于 Halo 插件模板创建了自己的存储库。接下来,你需要将它克隆到你的计算机上。
```shell
# clone your repository
git clone https://github.com/<your-username>/halo-plugin-hello-world.git
# enter the directory
cd halo-plugin-hello-world
```bash
pnpm create halo-plugin
```
```bash
🚀 Welcome to Halo Plugin Creator!
✔ Plugin name: hello-world
✔ Domain (for group and package name): com.example
✔ Author name: Halo
✔ Choose UI build tool: Rsbuild
📋 Project Configuration:
Name: hello-world
Domain: com.example
Package: com.example.hello-world
Author: Halo
UI Tool: rsbuild
Output Directory: /path/to/hello-world
✔ Create project? yes
```
- **Plugin name**: 插件的名称,用于插件的标识,此字段必须由小写字母、数字和连字符组成
- **Domain**: 插件的包名
- **Author name**: 插件的作者
- **Choose UI build tool**: 插件的 UI 构建工具,目前支持 `Rsbuild``Vite`
更多关于插件创建工具的信息可查阅:[halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin)
## 运行插件
现在有了一个空项目,我们需要让插件能最最小化的运行起来,这里提供两种运行方式。
@@ -36,17 +49,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
使用 DevTools 运行插件的前提是需要你的电脑上已经安装了 Docker 环境,这是我们推荐的用户开发时运行插件的方式,只需要执行以下命令即可。
1. 执行前端部分的依赖安装命令
```shell
# macOS / Linux
./gradlew pnpmInstall
# Windows
./gradlew.bat pnpmInstall
```
2. 运行插件:
1. 运行插件
```shell
# macOS / Linux
@@ -58,7 +61,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
执行此命令后,会自动创建一个 Halo 的 Docker 容器并加载当前的插件。
3. 启动成功后,可以看到如下日志输出:
2. 启动成功后,可以看到如下日志输出:
```shell
Halo 初始化成功访问http://localhost:8090/console
@@ -78,17 +81,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
但由于此方式需要先使用源码运行 Halo 才能启动插件,请确保已经在开发环境运行了 Halo可以参考 [Halo 开发环境运行](../core/run.md)
1. 安装前端部分的依赖
```shell
# macOS / Linux
./gradlew pnpmInstall
# Windows
./gradlew.bat pnpmInstall
```
2. 编译插件
1. 编译插件
```shell
# macOS / Linux
@@ -98,7 +91,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
./gradlew.bat build
```
3. 修改 Halo 配置文件:
2. 修改 Halo 配置文件:
```shell
# 进入 Halo 项目根目录后,使用 cd 命令进入配置文件目录
@@ -128,7 +121,7 @@ Halo 提供了一个用于插件开发的 DevTools它可以帮助你快速的
- C:\path\to\halo-plugin-hello-world
```
4. 启动 Halo
3. 启动 Halo
```shell
# macOS / Linux

View File

@@ -11,7 +11,7 @@ description: 了解如何与我们的社区分享你的插件
## 自动构建
如果你是基于 [halo-dev/plugin-starter](https://github.com/halo-dev/plugin-starter) 创建的插件项目,那么已经包含了适用于 GitHub Action 的 `ci.yaml``cd.yaml` 文件,里面包含了构建插件和发布插件资源到 Release 的步骤,可以根据自己的实际需要进行修改,以下是示例:
如果你是使用 [halo-dev/create-halo-plugin](https://github.com/halo-dev/create-halo-plugin) 创建的插件项目,那么已经包含了适用于 GitHub Action 的 `ci.yaml``cd.yaml` 文件,里面包含了构建插件和发布插件资源到 Release 的步骤,可以根据自己的实际需要进行修改,以下是示例:
```yaml
name: CI

View File

@@ -80,7 +80,7 @@ export default definePlugin({
});
```
参考:[plugin-starter](https://github.com/halo-dev/plugin-starter/blob/5a4a25db252a7986900368a5fbf35e8d27f5257f/ui/src/index.ts#L6-L29)
参考:[halo-dev/create-halo-plugin#template/ui/src/index.ts](https://github.com/halo-dev/create-halo-plugin/blob/a4ce935a637faff4a7f00fecbdee08f55fd66ffd/template/ui/src/index.ts)
> 该配置示例为在插件前端部分入口文件 `index.ts`