直接开发扩展

不推荐此开发方式,除非你非常清楚自己在做什么,并且需要很高的自由度,否则请使用 extprg 工具链

扩展包格式

com.example.hello-world.prg/
├── metadata.msgpack (必须存在)
├── extension.js (必须存在)
├── README.md (插件说明文件)
├── icon.png (插件图标文件)
└── ...

一个扩展就是一个文件夹或者 prg 文件(没错,就是工程文件的格式),里面必须包含 metadata.msgpackextension.js 两个文件

插件的图标支持 png, jpg, svg, webp 等常见格式,建议使用正方形、同时避免文件体积过大。如果同时存在 icon.pngicon.svg,会优先使用 svg 格式的图标。

具体的优先级顺序:svg > webp > png > jpg

最简插件整体开发流程

  1. 创建一个插件项目文件夹
  2. 在项目中创建 metadata.jsonextension.js 文件、并按正确格式编写它们
  3. metadata.json 中的内容转换成 metadata.msgpack 二进制文件
  4. 将插件项目文件夹打包成一个 prg 文件

metadata文件

其中 metadata.msgpack 和工程文件有所不同,扩展包的元数据需要写在 extension 字段里

{
  "version": "2.0.0",
  "extension": {
    "id": "com.example.hello-world",
    "name": "示例扩展",
    "description": "这是一个用于演示的示例扩展包",
    "version": "1.0.0",
    "author": "Author <[email protected]>"
  }
}

metadata字段解释

  • id: 扩展的唯一标识符,建议使用反向域名命名法,例如 com.example.hello-world,将会与文件名保持一致
  • name: 扩展的名称,仅作展示
  • description: 扩展的描述,仅作展示
  • version: 扩展最低支持的软件的prg文件版本,不是软件本身的版本号
  • extension.version: 扩展本身的版本号,建议遵循语义化版本规范
  • author: 扩展的作者信息,邮箱可选填

json文件 转 msgpack文件

如何生成或者编辑msgpack二进制文件?可以先写json文件,然后将json文件中的内容一次性转换成msgpack二进制文件,可以使用这个在线工具:

https://graphif.github.io/json2msgpack/

插件的metadata文件是否可以直接支持使用json文件,以便于编辑和维护,有待商榷。

extension.js 文件

extension.js 是扩展的入口文件

此示例展示了如何注册一个快捷键,当用户依次按下 q u e s 时,给当前选中的节点添加一个问号,并修改节点颜色

await prg.keybinds_register(
  "ques",
  { $lucide: "User" },
  "q u e s",
  Comlink.proxy(async () => {
    const project = await prg.tabs_getCurrentProject();
    const stageManager = await project.stageManager;
    const selectedEntities = await stageManager.getSelectedEntities();
    const first = await selectedEntities[0];
    const text = await first.text;
    await first.rename(`❓ ${text}`);
    first.color = { _: "Color", r: 255, g: 0, b: 0 };
    await prg.toast_success("添加了问号并修改了节点颜色");
  }),
);

不需要 import prg,直接就可以使用API。

运行环境

  • Web Worker: 扩展在一个独立的线程中运行,无法直接访问 DOM 和主线程的变量
  • ES Module: 不能用 importScripts
  • Blob URL: 不能导入其他模块,但是可以用 CDN 的方式导入第三方库
  • Async IIFE: 可以用顶层 await

自动注入的 API

扩展在启动时会自动且强制地注入一些 API

  • Comlink: 用于和主线程之间通信,建议使用 prg 来调用主线程的 API,Comlink 用于调用 Comlink.proxy 等方法
  • Comlink.transferHandlers: 详见 Transfer Handlers
  • prg: Comlink.wrap(self) 的结果,可以通过它调用主线程暴露的 API

打包prg文件

最终的插件产物是一个prg文件。如何将插件项目文件夹打包成一个 prg 文件?

  1. 进入插件项目文件夹
  2. 多选、选中所有文件
  3. 右键 -> 压缩(Compress) -> 会生成一个 zip 文件
  4. 将 zip 文件的后缀改成 prg 即可

为什么不能直接把整个文件右键压缩成一个 zip 文件?因为如果直接右键压缩整个文件夹,解压后会多一层文件夹,而插件需要的结构是所有文件直接放在根目录下。