4040## 功能介绍
4141
4242本插件现版本已提供以下功能:
43+
4344- 无需主题适配即可使用的功能:
44- - [ 代码高亮处理器] ( #代码高亮处理器 ) (仅全量版可用)
45+ - [ 代码高亮处理器] ( #代码高亮处理器 ) (仅全量版可用)
4546- 需要主题适配的 Finder API:
46- - [ 文章字数统计 API] ( #文章字数统计-api )
47- - [ 代码高亮 API] ( #代码高亮-api ) (仅全量版可用)
47+ - [ 文章字数统计 API] ( #文章字数统计-api )
48+ - [ 代码高亮 API] ( #代码高亮-api ) (仅全量版可用)
4849
49- 未来将实现的功能:[ TODO] ( #TODO )
50+ 未来将实现的功能:[ TODO] ( #todo )
5051
5152欢迎为此插件提 [ Issue] ( https://github.com/HowieHz/halo-plugin-extra-api/issues/new ) ,任何你需要的功能都可以在此处提出,我将在能力范围内尽力实现。
5253
7273### 轻量版本缺少的功能
7374
7475- 代码高亮(Shiki.js 渲染)
76+
7577<!-- - 图表渲染(Mermaid)
7678- 公式渲染(KaTeX) -->
79+
7780- 其他 JS 运行时相关功能
7881
7982如果您需要上述功能,请使用全量版。
8790### 基本使用要求
8891
89921 . ** 请勿热重载更新** : 请勿直接覆盖更新(如使用应用商店/插件列表的快捷更新操作)
90- 2 . ** 正确的更新流程** :
91- - 方法一:停止插件 → 卸载插件 → ** 重启 Halo** → 安装新版本 → 启动插件
92- - 方法二:停止插件 → 卸载插件 → 安装新版本 → ** 重启 Halo** → 启动插件
93+ 2 . ** 正确的更新流程** :
94+ - 方法一:停止插件 → 卸载插件 → ** 重启 Halo** → 安装新版本 → 启动插件
95+ - 方法二:停止插件 → 卸载插件 → 安装新版本 → ** 重启 Halo** → 启动插件
93963 . ** 卸载推荐做法** : 在卸载全量版后** 重启 Halo** 确保原生库资源完全释放。
9497
9598### 全量版已知问题
9699
97100- 问题一:卸载后重新安装全量版插件,不重启就启用。调用 JS 相关 API 时会出现错误:
98- - ** 首次安装并启动** : 正常工作
99- - ** 禁用后重新启用** : 正常工作
100- - ** 卸载后重新安装** : ❌ 会出现 ` JavetException: Javet library is not loaded ` 错误
101- - ** 重启 Halo 后** : 恢复正常工作
101+ - ** 首次安装并启动** : 正常工作
102+ - ** 禁用后重新启用** : 正常工作
103+ - ** 卸载后重新安装** : ❌ 会出现 ` JavetException: Javet library is not loaded ` 错误
104+ - ** 重启 Halo 后** : 恢复正常工作
102105
103106#### 问题一解决方案
104107
114117
115118** 问题根源** :
116119
117- 1 . ** Halo 插件架构** : 根据 [ Halo 开发文档 - 插件架构] ( https://docs.halo.run/developer-guide/core/framework ) , Halo 使用 Spring Plugin Framework 实现插件隔离
118- - 每个插件拥有独立的 Spring ApplicationContext
119- - 每个插件使用独立的 classloader 加载资源
120- - 插件间通过 ExtensionPoint 机制通信
121- - classloader 完全隔离,无法跨插件共享类或资源
120+ 1 . ** Halo 插件架构** : 根据 [ Halo 开发文档 - 插件架构] ( https://docs.halo.run/developer-guide/core/framework ) , Halo 使用
121+ Spring Plugin Framework 实现插件隔离
122+ - 每个插件拥有独立的 Spring ApplicationContext
123+ - 每个插件使用独立的 classloader 加载资源
124+ - 插件间通过 ExtensionPoint 机制通信
125+ - classloader 完全隔离,无法跨插件共享类或资源
122126
1231272 . ** Javet 原生库加载机制** :
124- - Javet 需要从 JAR 中提取原生库文件(` .dll ` /` .so ` /` .dylib ` )到临时目录
125- - JVM 通过 JNI 加载这些原生库文件
126- - 原生库文件一旦加载,会被 JVM 锁定
128+ - Javet 需要从 JAR 中提取原生库文件(` .dll ` /` .so ` /` .dylib ` )到临时目录
129+ - JVM 通过 JNI 加载这些原生库文件
130+ - 原生库文件一旦加载,会被 JVM 锁定
127131
1281323 . ** 冲突发生过程** :
129- - 安装插件时,Javet 提取原生库文件到 ` C:\Users\用户名\AppData\Local\Temp\javet\进程ID\ ` (以 Windows 举例)
130- - JVM 加载这些文件并锁定
131- - 卸载插件时,虽然 classloader 被销毁,但原生库文件仍被 JVM 锁定,无法删除
132- - 重新安装时,Javet 尝试提取新文件到同一位置
133- - 因为文件被锁定,提取失败
134- - Javet 初始化失败,报错 ` Javet library is not loaded because <null> `
133+ - 安装插件时,Javet 提取原生库文件到 ` C:\Users\用户名\AppData\Local\Temp\javet\进程ID\ ` (以 Windows 举例)
134+ - JVM 加载这些文件并锁定
135+ - 卸载插件时,虽然 classloader 被销毁,但原生库文件仍被 JVM 锁定,无法删除
136+ - 重新安装时,Javet 尝试提取新文件到同一位置
137+ - 因为文件被锁定,提取失败
138+ - Javet 初始化失败,报错 ` Javet library is not loaded because <null> `
135139
136140** 典型错误日志解读** :
137141
@@ -142,6 +146,7 @@ ERROR - JavetException: Javet library is not loaded because <null>
142146```
143147
144148这三条日志清晰地展示了整个失败过程:
149+
1451501 . 尝试写入文件失败(文件被锁定)
1461512 . 检测到库已在其他 classloader 中加载
1471523 . 初始化失败,因为无法提取必要的库文件
@@ -156,6 +161,7 @@ ERROR - JavetException: Javet library is not loaded because <null>
156161** 为什么 Javet 文档中提到的 JVM 参数无效** :
157162
158163` -Djavet.lib.loading.suppress.error=true ` 这个参数的作用是:
164+
159165- 抑制 Javet 在检测到"already loaded in another classloader"时的错误日志
160166- ** 但无法解决文件锁定问题**
161167- 当库文件无法提取时,Javet 根本无法完成初始化
@@ -164,12 +170,14 @@ ERROR - JavetException: Javet library is not loaded because <null>
164170** 架构层面的限制** :
165171
166172这个问题是 JVM/JNI + 插件 classloader 隔离的固有矛盾:
173+
167174- Halo 的插件隔离设计保证了安全性和稳定性
168175- 但也导致原生库这类 JVM 级别资源难以管理
169176- 类似问题在所有使用 classloader 隔离的插件系统中都存在
170177- 这不是 Javet 或本插件的 bug,而是架构层面的限制
171178
172179** 相关技术文档** :
180+
173181- [ Javet - Load and Unload] ( https://www.caoccao.com/Javet/reference/resource_management/load_and_unload.html )
174182- [ Javet Issue #124 - Classloader Reload] ( https://github.com/caoccao/Javet/issues/124 )
175183- [ Halo - Plugin Framework] ( https://docs.halo.run/developer-guide/core/framework )
@@ -192,38 +200,38 @@ ERROR - JavetException: Javet library is not loaded because <null>
192200## 文档目录
193201
194202- [ halo-plugin-extra-api] ( #halo-plugin-extra-api )
195- - [ 简介] ( #简介 )
196- - [ 核心理念] ( #核心理念 )
197- - [ 功能介绍] ( #功能介绍 )
198- - [ 版本说明] ( #版本说明 )
199- - [ 轻量版的优势] ( #轻量版的优势 )
200- - [ 轻量版本缺少的功能] ( #轻量版本缺少的功能 )
201- - [ 全量版使用须知] ( #全量版使用须知 )
202- - [ 基本使用要求] ( #基本使用要求 )
203- - [ 全量版已知问题] ( #全量版已知问题 )
204- - [ 问题一解决方案] ( #问题一解决方案 )
205- - [ TODO] ( #todo )
206- - [ 文档目录] ( #文档目录 )
207- - [ 处理器文档] ( #处理器文档 )
208- - [ 代码高亮处理器] ( #代码高亮处理器 )
209- - [ 特点] ( #特点 )
210- - [ 配置选项] ( #配置选项 )
211- - [ 支持的主题] ( #支持的主题 )
212- - [ 补充说明] ( #补充说明 )
213- - [ Finder API 文档] ( #finder-api-文档 )
214- - [ 插件本体信息相关 API] ( #插件本体信息相关-api )
215- - [ 检测本插件是否启用] ( #检测本插件是否启用 )
216- - [ 插件版本检测 API] ( #插件版本检测-api )
217- - [ 统计信息 API] ( #统计信息-api )
218- - [ 文章字数统计 API] ( #文章字数统计-api )
219- - [ 渲染 API] ( #渲染-api )
220- - [ 代码高亮 API] ( #代码高亮-api )
221- - [ 下载和安装] ( #下载和安装 )
222- - [ 稳定版] ( #稳定版 )
223- - [ 开发版] ( #开发版 )
224- - [ 下载步骤] ( #下载步骤 )
225- - [ 开发指南/贡献指南] ( #开发指南贡献指南 )
226- - [ 许可证] ( #许可证 )
203+ - [ 简介] ( #简介 )
204+ - [ 核心理念] ( #核心理念 )
205+ - [ 功能介绍] ( #功能介绍 )
206+ - [ 版本说明] ( #版本说明 )
207+ - [ 轻量版的优势] ( #轻量版的优势 )
208+ - [ 轻量版本缺少的功能] ( #轻量版本缺少的功能 )
209+ - [ 全量版使用须知] ( #全量版使用须知 )
210+ - [ 基本使用要求] ( #基本使用要求 )
211+ - [ 全量版已知问题] ( #全量版已知问题 )
212+ - [ 问题一解决方案] ( #问题一解决方案 )
213+ - [ TODO] ( #todo )
214+ - [ 文档目录] ( #文档目录 )
215+ - [ 处理器文档] ( #处理器文档 )
216+ - [ 代码高亮处理器] ( #代码高亮处理器 )
217+ - [ 特点] ( #特点 )
218+ - [ 配置选项] ( #配置选项 )
219+ - [ 支持的主题] ( #支持的主题 )
220+ - [ 补充说明] ( #补充说明 )
221+ - [ Finder API 文档] ( #finder-api-文档 )
222+ - [ 插件本体信息相关 API] ( #插件本体信息相关-api )
223+ - [ 检测本插件是否启用] ( #检测本插件是否启用 )
224+ - [ 插件版本检测 API] ( #插件版本检测-api )
225+ - [ 统计信息 API] ( #统计信息-api )
226+ - [ 文章字数统计 API] ( #文章字数统计-api )
227+ - [ 渲染 API] ( #渲染-api )
228+ - [ 代码高亮 API] ( #代码高亮-api )
229+ - [ 下载和安装] ( #下载和安装 )
230+ - [ 稳定版] ( #稳定版 )
231+ - [ 开发版] ( #开发版 )
232+ - [ 下载步骤] ( #下载步骤 )
233+ - [ 开发指南/贡献指南] ( #开发指南贡献指南 )
234+ - [ 许可证] ( #许可证 )
227235
228236## 处理器文档
229237
@@ -241,12 +249,21 @@ ERROR - JavetException: Javet library is not loaded because <null>
241249 - 从 ` class ` 属性中提取语言标识(如 ` language-java ` 、` lang-python ` )
242250- 容错处理:
243251 - 渲染失败时保持原始代码块不变
244- - 性能说明:
245- - 使用 V8 引擎池和异步处理,提升渲染效率
246252- 默认自动渲染范围:
247253 - 处理器会自动处理以下页面内容并在页面 ` head ` 注入自定义 CSS 样式:
248254 - 文章内容 (` post ` )
249255 - 页面内容 (` page ` )
256+ - 性能说明:
257+ - 命中缓存时响应速度极快(微秒级),首次渲染需要 1-3 秒初始化 JS 环境
258+ - 批量处理策略:
259+ - 智能分组:根据 V8 引擎池大小动态分配任务(例如 14 个任务 + 5 个引擎 → 5 组,每组 2-3 个任务)
260+ - 并行执行:多个任务组并行处理,充分利用多核性能
261+ - 批量渲染:同一组内的任务在单个引擎中通过一次 JS 通信批量处理,减少引擎切换开销
262+ - 优先缓存:先检查缓存,只对未命中的请求进行实际渲染
263+ - 缓存策略:
264+ - LRU + TTL 双重策略:最多缓存 10,000 个代码块,每个条目 24 小时自动过期
265+ - 智能去重:相同代码内容+语言+主题的重复渲染会自动去重,避免重复计算
266+ - 缓存键:基于代码内容的 SHA-256 哈希值,避免长代码占用过多内存
250267
251268#### 配置选项
252269
0 commit comments