|
1 | 1 | # halo-plugin-extra-api |
2 | 2 |
|
3 | | -halo-plugin-extra-api - Halo 插件 |
4 | | - |
5 | 3 | ## 简介 |
6 | 4 |
|
7 | 5 | 一个为 Halo CMS 提供额外 API 的轻量级插件。 |
8 | 6 |
|
9 | | -## 已提供 API |
| 7 | +## 核心理念 |
| 8 | + |
| 9 | +> CMS 的价值就是在服务端管理和处理内容,为什么要把简单的数据处理推到前端去增加复杂度呢? |
| 10 | +
|
| 11 | +让 CMS 回归"内容即数据"的本质,减少**不必要**的前端异步请求和动态渲染。 |
| 12 | + |
| 13 | +这个插件正是基于这个理念: |
| 14 | +- 让复杂的逻辑在后端处理 |
| 15 | +- 前端模板只负责展示 |
| 16 | +- 提供简洁的 Finder API |
| 17 | +- 减少不必要的 JavaScript 依赖 |
| 18 | + |
| 19 | +<details><summary>前端动态加载方式 vs 后端服务端渲染方式</summary> |
| 20 | + |
| 21 | +| 对比维度 | 前端动态加载方式 | 后端服务端渲染方式 | |
| 22 | +|---------|-----------------|-------------------| |
| 23 | +| **性能表现** | ❌ 需要额外 HTTP 请求,增加延迟 | ✅ 服务端渲染,一次性输出 | |
| 24 | +| **用户体验** | ❌ 页面闪烁,先显示占位符后填充数据 | ✅ 内容立即可见,无加载状态 | |
| 25 | +| **SEO 友好** | ❌ 搜索引擎难以抓取动态内容 | ✅ 服务端渲染,完全 SEO 友好 | |
| 26 | +| **错误处理** | ❌ 需要处理网络失败、超时等异常 | ✅ 服务端统一异常处理,减轻主题作者心智负担 | |
| 27 | +| **开发复杂度** | ❌ 需要编写 JS 代码、状态管理、DOM 操作 | ✅ 模板中直接调用,代码简洁 | |
| 28 | +| **缓存策略** | ❌ 需要前端缓存逻辑或重复请求 | ✅ 可利用模板缓存和服务端缓存 | |
| 29 | +| **首屏渲染 (FCP)** | ❌ 需要等待 JS 执行和 API 响应 | ✅ HTML 直接包含内容,渲染更快 | |
| 30 | +| **最大内容绘制 (LCP)** | ❌ 动态内容加载延迟主要内容显示 | ✅ 关键内容随页面一起渲染 | |
| 31 | +| **累积布局偏移 (CLS)** | ❌ 内容异步加载可能导致页面跳动 | ✅ 静态布局,无意外的布局变化 | |
| 32 | +| **交互响应 (INP)** | ❌ JS 执行和 DOM 操作影响交互性能 | ✅ 减少 JS 负担,交互更流畅 | |
| 33 | + |
| 34 | +</details> |
| 35 | + |
| 36 | +## TODO |
| 37 | + |
| 38 | +- [] 缓存文章字数统计 API 结果 |
| 39 | +- [] 提供随机文章 API |
| 40 | +- [] 提供预计阅读时间 API,及相关配置项 |
| 41 | + |
| 42 | +## API 文档 |
| 43 | + |
| 44 | +### 检测本插件是否启用 |
| 45 | + |
| 46 | +**描述** |
| 47 | + |
| 48 | +检测 ExtraAPI 插件是否已安装并启用。建议在主题中使用本插件 API 前先进行检测,以确保插件可用性。 |
| 49 | + |
| 50 | +**参数** |
| 51 | +- `extra-api` - 本插件的标识符(`metadata.name`) |
10 | 52 |
|
11 | | -### 文章字数统计 |
| 53 | +**返回值** |
| 54 | +- `boolean` - 插件可用时返回 true,否则返回 false |
12 | 55 |
|
13 | | -本插件提供了一个 API 用于查询文章字数,可查询指定文章/全部文章总和。 |
| 56 | +**示例** |
| 57 | +```html |
| 58 | +<!--/* 先检测插件可用性,再使用 API */--> |
| 59 | +<th:block th:if="${pluginFinder.available('extra-api')}"> |
| 60 | + <span |
| 61 | + th:text="|总字数:${extraApiStatsFinder.wordCount()}|" |
| 62 | + ></span> |
| 63 | +</th:block> |
| 64 | + |
| 65 | +<!--/* 写在一个标签内也可以,th:if 的优先级比 th:text 高 */--> |
| 66 | +<span |
| 67 | + th:if="${pluginFinder.available('extra-api')}" |
| 68 | + th:text="|总字数:${extraApiStatsFinder.wordCount()}|" |
| 69 | +></span> |
| 70 | + |
| 71 | +<!--/* 自然模板写法 */--> |
| 72 | +<span th:if="${pluginFinder.available('extra-api')}">总字数:[[${extraApiStatsFinder.wordCount()}]]</span> |
| 73 | +``` |
| 74 | + |
| 75 | +**说明** |
| 76 | + |
| 77 | +使用 `pluginFinder.available('extra-api')` 可以优雅地处理插件依赖,避免在插件未安装时出现模板错误,提升主题的兼容性和用户体验。 |
| 78 | + |
| 79 | +### 统计信息 API |
| 80 | + |
| 81 | +**Finder 名称:** `extraApiStatsFinder` |
| 82 | + |
| 83 | +#### 文章字数统计 |
| 84 | + |
| 85 | +```javascript |
| 86 | +extraApiStatsFinder.wordCount({ |
| 87 | + name: 'post-metadata-name', // 可选,未传入则统计全部文章字数总和 |
| 88 | + version: 'release' | 'draft' // 可选,默认 'release' |
| 89 | +}); |
| 90 | +``` |
| 91 | + |
| 92 | +```javascript |
| 93 | +extraApiStatsFinder.wordCount(); |
| 94 | +``` |
| 95 | + |
| 96 | +**描述** |
| 97 | + |
| 98 | +- 参数说明: |
| 99 | + - `name`:文章的 `metadata.name`,可选参数。未传入时统计全部文章字数总和。 |
| 100 | + - `version`:统计版本,可选 `release`(默认)或 `draft`。 |
| 101 | +- 计数规则: |
| 102 | + - 中文、日文、韩文等 CJK 字符按每个字符计 1。 |
| 103 | + - ASCII 连续字母/数字按 1 个单词计数。 |
| 104 | + - 标点符号和空格不计入统计。 |
| 105 | +- 错误处理: |
| 106 | + - 输入为空或文章不存在时返回 0,不会抛出异常。 |
| 107 | +- 性能说明: |
| 108 | + - 单次调用开销较小,适合在模板中直接使用。 |
| 109 | + |
| 110 | +**参数** |
| 111 | +- `name:string` – 文章 `metadata.name`(可选,不传则统计全站) |
| 112 | +- `version:string` – 统计版本,可选 `release`(默认)或 `draft` |
| 113 | + |
| 114 | +**返回值** |
| 115 | +- `int` – 字数统计结果(非负),不存在或参数缺失时返回 0 |
| 116 | + |
| 117 | +**使用示例** |
| 118 | +```html |
| 119 | +<!--/* 统计文章已发布版本的字,适用于 /templates/post.html */--> |
| 120 | +<span th:text="${extraApiStatsFinder.wordCount({name: post.metadata.name})}"></span> |
| 121 | + |
| 122 | +<!--/* 统计文章最新版本的字数(含草稿),适用于 /templates/post.html */--> |
| 123 | +<span th:text="${extraApiStatsFinder.wordCount({name: post.metadata.name, version: 'draft'})}"></span> |
| 124 | + |
| 125 | +<!--/* 统计全站已发布文章的总字数,适用于全部模板 */--> |
| 126 | +<span th:text="${extraApiStatsFinder.wordCount()}"></span> |
| 127 | +<!--/* 与下方写法等价 */--> |
| 128 | + <span th:text="${extraApiStatsFinder.wordCount({})}"></span> |
| 129 | + |
| 130 | +<!--/* 统计全站所有文章最新版本的总字数(含草稿),适用于全部模板 */--> |
| 131 | +<span th:text="${extraApiStatsFinder.wordCount({version: 'draft'})}"></span> |
| 132 | +``` |
14 | 133 |
|
15 | 134 | ## 开发环境 |
16 | 135 |
|
@@ -40,4 +159,4 @@ pnpm dev |
40 | 159 |
|
41 | 160 | ## 许可证 |
42 | 161 |
|
43 | | -[AGPL-3.0](./LICENSE) © HowieHz |
| 162 | +[AGPL-3.0](./LICENSE) © HowieHz |
0 commit comments