EmDash 插件以两种格式之一提供:sandboxed(沙箱)或 native(原生)。这个选择影响插件的安装方式、运行时的执行方式以及可用的功能。
默认选择沙箱。 沙箱插件可以发布到市场,并通过管理界面一键安装。原生插件需要代码更改、npm install 以及在每个想要使用它们的站点上重新部署。沙箱是终端用户想要的。
只有在需要沙箱无法提供的功能时才选择原生。
快速对比
| Sandboxed | Native | |
|---|---|---|
| 编写形式 | emdash-plugin.jsonc + src/plugin.ts | definePlugin() 描述符 |
| 安装方法 | 从管理市场一键安装 | npm install + 编辑 astro.config |
| 运行环境 | 由沙箱运行器提供的隔离运行时 | 与 Astro 站点相同的进程 |
| 功能 | 由沙箱桥强制执行 | 由同一桥在进程内强制执行 |
| 资源限制 | 由运行器强制执行 — 通常是 CPU、子请求、墙上时间、内存 | 无 |
| 网络访问 | 仅 ctx.http,限制为 allowedHosts | 仅 ctx.http,限制为 allowedHosts |
直接 fetch() / process.env | 被运行器阻止 | 可能(插件代码共享运行时) |
| 分发 | 市场上的 .tar.gz 包 | npm 包 |
| 管理界面 | Block Kit(JSON 描述)路由 | React 组件,或 Block Kit |
| 设置界面 | Block Kit 页面 + KV 读取 | admin.settingsSchema(自动表单)或 Block Kit |
| Portable Text 渲染组件 | 不可用 | componentsEntry 提供 Astro 组件 |
| 页面元数据贡献 | page:metadata 钩子 — meta/property 标签、允许列表的 <link> rels、JSON-LD | page:metadata 钩子(相同表面) |
| 页面片段注入 | 不可用 — 仅通过 page:metadata 的 meta/JSON-LD | page:fragments 钩子 — 内联脚本、外部脚本、原始 HTML |
| 构造函数选项 | 无 — 在运行时从 KV 读取设置 | 描述符上的 options |
选择原生会失去什么
原生插件看起来像是同一事物的更强大版本,确实如此 — 但成本很高:
- 没有市场。 每个站点都必须安装你的 npm 包,编辑
astro.config.mjs,并重新部署。 - 没有隔离。 插件中的错误可能会使主机进程崩溃或耗尽其 CPU 预算。钩子中未处理的拒绝可能会连同周围的请求一起崩溃。
- 用户的信任负担。 原生插件拥有与主机站点相同的访问权限。最终用户无法仅通过功能声明来审计它们。
如果你的插件可以在沙箱中完成其工作,它就应该这样做。
何时选择原生
选择原生有三个原因,它们都是关于需要与主机站点进行构建时集成的功能:
-
自定义 React 管理页面或小部件。 沙箱插件使用 Block Kit 描述其管理界面 — 这是一个 JSON 模式,管理员代表插件渲染它。如果你需要完整的 React(自定义钩子、第三方组件、复杂状态),你需要原生。
-
用于在公共站点上渲染 Portable Text 块的 Astro 组件。 沙箱插件可以声明自定义块类型,但在公共站点上渲染它的 Astro 组件必须在构建时从 npm 加载。只有原生插件可以提供
componentsEntry。 -
将原始 HTML、脚本或样式表注入公共页面。
page:fragments钩子将第一方代码发送到访问者的浏览器 — 在任何沙箱边界之外。它仅限于原生插件。沙箱插件仍然可以通过page:metadata钩子为公共页面做出贡献,它涵盖了许多实际用例:meta标签(name+content) — SEO 描述、robots 指令、Twitter 卡片property标签 — OpenGraph 和其他基于属性的 meta- 带有安全锁定的 rel 允许列表的
link标签(canonical、alternate、author、license、nlweb、site.standard.document) —stylesheet、prefetch和类似的资源加载 rels 被故意禁止 - JSON-LD 图
如果你的”页面注入”需求是结构化数据或 SEO 元数据,保持沙箱并使用
page:metadata。如果你确实需要向访问者的浏览器发送 JavaScript 或 HTML,那就是选择原生的情况。
如果你不确定,选择沙箱。你总是可以稍后迁移到原生 — 但反过来更难,因为原生专用功能没有沙箱等效物。
沙箱运行器和平台支持
沙箱本身是可插拔的。EmDash 公开了一个 sandboxRunner 配置选项,运行器决定如何隔离插件代码 — 插件格式本身没有任何 Cloudflare 特定的内容。
今天大多数站点使用的运行器是来自 @emdash-cms/cloudflare 的 sandbox(),它使用 Cloudflare Workers 的 Dynamic Worker Loader。Worker Loader 按插件 ID 缓存 V8 隔离,因此隔离冷启动成本只支付一次;运行器在每次调用时构造一个新的 worker stub 和桥绑定,因为 stub 和绑定与调用请求的 I/O 上下文绑定。其他平台的运行器(通过 workerd 的 Node.js,以及潜在的 Deno)正在开发中。
如果没有配置运行器,或者如果配置的运行器报告在当前平台上不可用,则在启动时跳过 sandboxed: [] 下列出的插件,并记录调试级别日志。
如果你想让沙箱插件在没有沙箱运行器的平台上运行,将它从 sandboxed: [] 移动到 plugins: [] 数组 — 它将在进程内执行。功能声明仍然得到遵守(相同的 PluginContext 工厂控制 ctx.content、ctx.http 和其他),但没有隔离边界,没有资源限制,有错误或恶意的插件可以直接调用 fetch()、读取环境变量或阻塞事件循环。在没有活动的沙箱运行器的情况下,出于信任目的将每个插件视为原生插件。