本指南适用于基于旧版 definePlugin() 形式编写的沙盒插件作者。按顺序处理这些破坏性变更。它们都不会改变您的钩子或路由在运行时的行为方式;它们改变的是插件的声明、构建和发布方式。
有关每个包中的完整变更列表,请参阅 EmDash 更新日志。
破坏性变更
重命名:@emdash-cms/registry-cli 现在是 @emdash-cms/plugin-cli
早期版本将 CLI 作为 @emdash-cms/registry-cli 发布,带有 emdash-registry 二进制文件。
该包现在是 @emdash-cms/plugin-cli,二进制文件是 emdash-plugin。旧包不再发布。
我应该怎么做?
替换依赖项:
pnpm remove @emdash-cms/registry-cli
pnpm add -D @emdash-cms/plugin-cli
在所有调用位置将 emdash-registry 替换为 emdash-plugin。每个子命令保持其名称(bundle、publish、login、whoami、switch、validate),并添加了 init、build 和 dev。参见插件 CLI。
变更:沙盒插件使用 satisfies SandboxedPlugin 定义
早期版本将插件的钩子和路由包装在从 emdash 导入的 definePlugin() 中,每个处理器的参数都需要手动注解。
沙盒插件现在是一个用 satisfies SandboxedPlugin 注解的纯默认导出。类型来自 emdash/plugin,这是一个仅类型的入口点,打包器会将其删除。TypeScript 从钩子或路由名称推断每个处理器的 event 和 ctx,因此处理器参数不需要注解。
我应该怎么做?
对插件的源文件进行四项更改。替换导入:
import { definePlugin, type ContentHookEvent, type PluginContext } from "emdash";
import type { SandboxedPlugin } from "emdash/plugin";
将 definePlugin() 包装器替换为纯对象和 satisfies 注解:
export default definePlugin({ /* hooks, routes */ });
export default { /* hooks, routes */ } satisfies SandboxedPlugin;
从每个处理器中删除参数注解:
handler: async (event: ContentHookEvent, ctx: PluginContext) => {
handler: async (event, ctx) => {
结果是一个默认导出的对象:
import type { SandboxedPlugin } from "emdash/plugin";
export default {
hooks: {
"content:beforeSave": {
handler: async (event, ctx) => {
return event.content;
},
},
},
} satisfies SandboxedPlugin;
要在辅助函数中命名事件类型,从 emdash/plugin 导入:
import type { ContentHookEvent, PluginContext } from "emdash/plugin";
处理器的 event 始终是该钩子的规范类型。使用更窄的接口注解处理器不再通过类型检查。使用 typeof 检查或守卫在运行时验证您依赖的任何字段,这是处理来自类型系统外部数据的正确方法。
变更:插件是一个 src/plugin.ts 加 emdash-plugin.jsonc
早期版本将插件拆分为两个文件:src/index.ts 返回一个 PluginDescriptor(id、version、capabilities、storage、entrypoint),src/sandbox-entry.ts 包含钩子和路由。
插件现在是一个运行时文件 src/plugin.ts(钩子和路由)和一个手动编辑的清单 emdash-plugin.jsonc(身份和信任合约)。entrypoint 和 format 字段已消失;构建会连接它们。
我应该怎么做?
使用上述形式将钩子和路由移动到 src/plugin.ts。将描述符的元数据移动到 package.json 旁边的 emdash-plugin.jsonc。描述符 id 变成清单 slug;capabilities、allowedHosts 和 storage 保持其形式;version 从 package.json 读取,因此省略它。
以下示例显示了声明一个存储集合的描述符的清单等效项:
{
"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",
"slug": "plugin-hello",
"publisher": "did:plc:abc123def456",
"license": "MIT",
"author": { "name": "Jane Doe", "url": "https://example.com" },
"security": { "email": "security@example.com" },
"capabilities": [],
"allowedHosts": [],
"storage": { "events": { "indexes": ["timestamp"] } }
}
有关所有字段,请参见插件清单,有关 publisher 字段,请参见发布者锁定。
在 package.json 中,将 "./sandbox" 导出指向构建的运行时文件:
"./sandbox": "./dist/sandbox-entry.mjs"
"./sandbox": "./dist/plugin.mjs"
将清单添加到 files,以便随包一起发布:
"files": ["dist"]
"files": ["dist", "emdash-plugin.jsonc"]
变更:使用 emdash-plugin build 构建
早期版本使用手写的 tsdown 脚本构建两个源文件。
emdash-plugin build 读取 emdash-plugin.jsonc 和 src/plugin.ts 并生成 dist/ 构件。emdash-plugin dev 监视并重新构建。
我应该怎么做?
替换构建脚本并添加监视脚本:
"scripts": {
"build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean"
"build": "emdash-plugin build",
"dev": "emdash-plugin dev"
}
然后验证并构建:
emdash-plugin validate
emdash-plugin build
移除:从 emdash 导出的标准格式类型和函数
早期版本从 emdash 导出 StandardPluginDefinition、StandardHookHandler、StandardHookEntry、StandardRouteHandler、StandardRouteEntry 和函数 isStandardPluginDefinition。
这些已被移除。它们是旧版 definePlugin 形式的辅助别名。
我应该怎么做?
使用 emdash/plugin 中的 SandboxedPlugin 实现相同目的。沙盒插件的默认导出已经通过其 satisfies SandboxedPlugin 注解进行了类型化,因此没有 isStandardPluginDefinition 的替代品;如果需要,通过结构({ hooks?, routes? })识别插件。
重命名:运行时 SandboxedPlugin 类型现在是 SandboxedPluginInstance
这仅影响自定义 SandboxRunner 的作者,例如 @emdash-cms/cloudflare。大多数插件作者可以跳过此部分。
emdash 中的 SandboxedPlugin 现在指的是面向作者的源形式。SandboxRunner.load 返回的运行时句柄是 SandboxedPluginInstance。
我应该怎么做?
如果您从 emdash 导入 SandboxedPlugin 来类型化沙盒运行器或持有运行时插件句柄,请将导入更改为 SandboxedPluginInstance:
import type { SandboxedPlugin } from "emdash";
import type { SandboxedPluginInstance } from "emdash";
告知您的用户
安装您插件的站点也需要更改其导入。向他们指出新形式:删除花括号和 ()。
import { helloPlugin } from "@my-org/plugin-hello";
import hello from "@my-org/plugin-hello";
export default defineConfig({
integrations: [
emdash({
sandboxed: [helloPlugin()],
sandboxed: [hello],
}),
],
});
如果您的插件通过其工厂接受配置,该配置将移至管理界面的插件设置。在运行时通过 ctx.kv 或 settings 读取它。参见设置。