插件系统
我们很高兴地宣布,在 Paperlib 3.0 中,我引入插件系统,这意味着你可以为 Paperlib 中开发插件进行功能扩展了!🎉🎉🎉
前言
本文介绍插件系统的整体设计,便于理解开发过程中可能涉及的每个部分。如果你只是想开发一个简易插件,可以跳过此文。如果你在开发一个相对复杂的插件,强烈推荐阅读本文。
进程与插件运行环境
为了妥协多平台开发,Paperlib 选择基于 Electron。因此在整个程序中,我们有三个主要的进程:
- 主进程 (Main Process):负责管理整个程序的生命周期,以及与系统进行交互,如上下文菜单等。
- 渲染进程 (Renderer Process):负责渲染界面,以及大部分的程序逻辑。
- 插件进程 (Extension Process):负责插件的管理和运行。
每个插件都运行在插件进程中,且代码在单独的 node VM 中执行,因此,插件的崩溃并不会导致 Paperlib 的崩溃,各个插件之间也互不干扰。因此每个插件运行的环境都是 node
环境,没有 html
等相关环境(New Window 插件例外)。
进程间通信
插件进程除了运行插件的代码之外,还负责插件的下载更新、加载、卸载,以及偏好设置。而大部分的逻辑代码都运行在主或者渲染进程里。因此 Paperlib 通过扩展 MessagePort
,实现了 Remote Procedure Calling (RPC)
来暴露主/渲染进程中的各个服务(service)的方法来供插件调用。
每一个跨进程方法调用,都会在内部被转换为一个 json
字符串并发给对应进程。这里面包含了想要调用的方法,传入的参数等必须信息。对应进程收到消息之后,会解析 json
,运行相应方法,得到结果并返回给调用者所在的进程。除此之外,我们还实现了跨进程事件监听,让开发更为方便。具体的实现细节请浏览 Github。
服务 Service
在每个进程中,都有许多服务提供各种各样的方法,来完成 Paperlib 的功能。比如主进程的 ContextMenuService
负责右键菜单相关的功能,渲染进程里面的 PaperService
负责最主要的论文相关的增删改查。相关实现可以在如 Github 找到。
Paperlib 中的服务的几乎所有方法都暴露给了插件进程以供调用。在插件进程中几乎可以实现操作 Paperlib 的全部部分。
服务事件 Service Event
几乎所有的服务都是 Eventable
的。这意味着每个服务都会在不同时机触发一些事件。在其他代码位置、进程可以监听对应的事件触发,来执行自己的代码。比如你可以监听用户选择的论文变化了,然后运行你的方法。
跨进程调用 API
为了方便开发,我们对插件进程暴露了主进程、渲染进程,以及插件进程的服务,并把他们集中在了三个对应的 API 中。你在接下来的文档中将会时常遇到这三个 API 组:
PLMainAPI
: 包含了所有的主进程服务。PLAPI
: 包含了所有的渲染进程服务。PLExtAPI
:包含了所有的插件进程服务。
当你想调用一个进程对应服务的方法的时候,只需要在你的插件代码中编写如下:
// const result = await APIGroup.serviceName.methodName(...)
const papers = await PLAPI.paperService.load(...)
因为是跨进程调用,所以几乎任何调用我们都需要使用 await
来等待异步结果的返回。如果你是在调用 PLExtAPI
,因为是同一个进程,所以同步或异步视情况而定,请参考开发时的类型提示。
插件类型
我们设计了五种不同形式的插件:
- Simple Extension:简单的功能,自己运行一些东西。
- Command Extension:用户通过 3.0 版本引入的 command bar 触发命令,然后运行相应功能。
- Hook Extension:通过在 Paperlib 生命流程中的不同钩子点注册钩子,来截断、修改流程中的内容。
- UI Extension:修改 UI 界面的部分内容。
- New Window Extension:创建一个全新的窗口,实现完全自定义的复杂的功能。
这五种插件涵盖了大部分插件场景,并可以相互混合。我们提供了对应的例子,会在之后详细介绍。
插件发布与下载
每一个插件,都是一个 npm
包,发布时与你发布一个 npm
包类似。其余的约定和限制我们会在之后解释。
在 Paperlib 设置界面的插件页面中,插件可以通过本地路径加载,或者搜索插件市场来下载。我们的插件市场依托于 npmjs.com
。
总结
总的来说。插件是运行在一个单独进程中,通过我们暴露的 API 进行操作 Paperlib 的 npm
包形式的一些代码。接下来我们推荐阅读开发环境设置,来开始开发你的插件吧!