跳到主要内容

生命周期与结构

本章描述第三方插件运行规则与数据流。

1) Breeze 如何调用插件​

  1. Breeze 加载插件 bundle
  2. Breeze 按 fnPath 找到同名函数
  3. Breeze 把参数传给这个函数
  4. Breeze 渲染函数返回的数据

核心规则:fnPath 必须与 export default 的键名一致。

2) 参数模型​

Breeze 调用时,通用入参模型可以理解成:

type PluginPayload<T extends Record<string, unknown>> = T & {
extern?: Record<string, unknown>;
};

推荐约定:

  • 业务主参数(如 comicId/page/keyword)放顶层
  • 会话/上下文透传信息放 extern

3) 返回模型​

绝大多数接口可返回:

type PluginEnvelope = {
source: string;
scheme?: Record<string, unknown>;
data?: Record<string, unknown>;
extern?: Record<string, unknown>;
};

说明:

  • source:插件 ID
  • scheme:页面渲染协议(可选)
  • data:业务数据
  • extern:透传上下文。宿主会把返回的 extern 存下来,下次请求时原样传回

4) 运行时 API​

Breeze 插件运行在 QuickJS-NG 引擎中,不是 Node.js 也不是浏览器环境。

可用的全局 API(fetch、bridge、crypto、Temporal、console 等)详见 运行时 API。

5) 调试与状态​

调试模式下,如果 bundle 文件发生变更,宿主会重建 QJS 实例。

这意味着:

  • 插件内的内存状态不会保留
  • 模块级变量会重新初始化

如果需要存储数据,建议按生命周期拆分:

  • 短期数据放 cache(随宿主进程存在,QuickJS 实例重建后仍可保留)
  • 长期数据放 config(跨应用重启保留)

两者都由 breeze-plugin-kit 提供便捷封装,详见 breeze-plugin-kit 工具包。

6) 兼容性​

  • API 新增时优先保持向后兼容
  • 对可选字段做默认值兜底

7) 常见陷阱​

QJS 实例重建​

调试模式下每次 bundle 变更都重建 QJS 实例。这意味着:

  • 顶层模块代码(除了 export default)每次都会重新执行
  • init 也会重新调用
  • 不要依赖模块级变量保存状态

getInfo 变更需要重装​

getInfo() 返回的 function 入口列表在插件加载时读取一次。修改后需要:

  • 重启软件,或
  • 卸载后重新安装插件

热更新不会触发 getInfo 重新读取。

单文件 bundle​

构建产物是单文件 .cjs,所有依赖必须通过 Rspack 打包进去。不能有运行时 npm 外部依赖。

bridge.callSync 限制​

同步调用会阻塞宿主线程,仅适合极短操作。不要在 bridge.callSync 中执行网络请求或文件读写。

extern 闭环​

插件返回的 extern 会被宿主存储,下次请求同一上下文时会原样传回。利用这个机制可以在 extern 中携带分页 token、会话状态等上下文数据。

ImageItem.url 规则​

ImageItem 有 url 字段,且 fetchImageBytes 会收到这个 url,但宿主本身不会用 url 来下载图片——图片下载完全由插件在 fetchImageBytes 中自行处理。

不过这并不意味着 url 可以乱填。不能为 404 地址,也不能是空字符串,必须是一个有效格式的占位符字符串(如 "https://example.com/placeholder.jpg"),否则宿主会拒绝渲染。