EmDash 插件以两种格式之一交付:沙盒式或原生。这个选择会影响插件的安装方式、运行时获得的强制执行以及可用的功能。
默认使用沙盒式。 沙盒式插件可以发布到市场并从管理界面一键安装。原生插件需要修改代码、执行 npm install 并在每个想要使用它们的站点上重新部署。沙盒式是最终用户想要的。
仅在需要沙盒无法提供的功能时才选择原生。
概览
| 沙盒式 | 原生 | |
|---|---|---|
描述符上的 format 字段 | "standard" | "native" |
| 安装方法 | 从管理市场一键安装 | 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 组件。 插件可以使用
format: "standard"声明自定义块类型,但在公共站点上渲染它的 Astro 组件必须在构建时从 npm 加载。只有原生插件可以提供componentsEntry。 -
将原始 HTML、脚本或样式表注入公共页面。
page:fragments钩子将第一方代码发送到访问者的浏览器 — 在任何沙盒边界之外。它仅限于原生插件。沙盒式插件仍然可以通过page:metadata钩子为公共页面做出贡献,它涵盖了许多实际用例:meta标签(name+content)— SEO 描述、robots 指令、Twitter Cardsproperty标签 — OpenGraph 和其他基于属性的元数据- 具有安全锁定 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 存根和桥接绑定,因为存根和绑定与调用请求的 I/O 上下文绑定。其他平台(通过 workerd 的 Node.js 以及可能的 Deno)的运行器正在开发中。
如果未配置运行器,或者如果配置的运行器报告在当前平台上不可用,则在启动时跳过 sandboxed: [] 下列出的插件,并记录调试级别日志。
如果您希望标准格式插件在没有沙盒运行器的平台上运行,请将其从 sandboxed: [] 移动到 plugins: [] 数组 — 它将在进程中执行。功能声明仍然受到尊重(相同的 PluginContext 工厂限制 ctx.content、ctx.http 等),但没有隔离边界,没有资源限制,有错误或恶意的插件可以直接调用 fetch()、读取环境变量或阻止事件循环。如果没有活动的沙盒运行器,出于信任目的,请将每个插件视为原生插件。