EmDash 插件使用两种格式之一:sandboxed(沙箱)或 native(原生)。请在编写插件之前选择格式,因为编写形态、安装路径与信任边界不同。
除非插件需要仅原生可用的集成,否则请选择沙箱插件。沙箱插件可发布到注册表并从管理 UI 安装。原生插件是站点运营者在项目中安装、并在重新部署前加入 astro.config.mjs 的 npm 包。
一览
| Sandboxed | Native | |
|---|---|---|
| Authoring shape | emdash-plugin.jsonc + src/plugin.ts | definePlugin() descriptor |
| Install method | One-click from the admin registry | npm install + edit astro.config |
| Runs in | An isolated runtime provided by a sandbox runner | Same process as your Astro site |
Capability-gated ctx APIs | Enforced by the sandbox bridge | Gated by PluginContext, but not a security boundary |
| Resource limits | Runner limits for CPU, subrequests, and wall time; platform memory ceiling | No per-plugin limits |
| Network access | ctx.http, restricted to declared access | ctx.http follows declarations; native code can also call fetch() |
Direct fetch() / process.env | Blocked by the runner | Possible (plugin code shares the runtime) |
| Distribution | Signed release in the plugin registry | npm package |
| Admin UI | Block Kit (JSON-described) routes | React components, or Block Kit |
| Settings UI | Block Kit page + ctx.settings | admin.settingsSchema (auto-form) or Block Kit |
| Portable Text rendering components | Not available | componentsEntry provides Astro components |
| Page metadata contributions | page:metadata hook — meta/property tags, allowlisted <link> rels, JSON-LD | page:metadata hook (same surface) |
| Page fragment injection | Not available — meta/JSON-LD only via page:metadata | page:fragments hook — inline scripts, external scripts, raw HTML |
| Constructor options | None — read settings from KV at runtime | options on the descriptor |
原生插件的代价
原生插件有不同的安装与信任模型:
- 项目级安装。 每个站点都必须安装你的 npm 包、编辑
astro.config.mjs并重新部署。 - 无隔离。 插件中的 bug 可能使宿主进程崩溃或耗尽其 CPU 预算。钩子中未处理的 rejection 可能拖垮周围的请求。
- 用户侧的信任负担。 原生插件拥有与宿主站点相同的访问权限。仅靠能力声明无法展示其代码能做的一切。
如果插件能在沙箱中完成工作,就应该这样做。
何时选择原生
为需要与宿主站点进行构建时集成的功能选择原生:
-
自定义 React 管理页面或小组件。 沙箱插件用 Block Kit——管理端代表插件渲染的 JSON schema——描述其管理 UI。若你需要完整 React(自定义 hooks、第三方组件、复杂状态),就需要原生。
-
自定义 Portable Text 块类型。 其编辑配置与 Astro 渲染组件从已安装的 npm 包加载。只有原生插件能提供该构建时表面。
-
向公开页面注入原始 HTML、脚本或样式表。
page:fragments钩子向访客浏览器投递第一方代码——在任何沙箱边界之外。它仅限原生插件。沙箱插件仍可通过page:metadata钩子向公开页面贡献,该钩子覆盖许多真实用例:meta标签(name+content)— SEO 描述、robots 指令、Twitter cardsproperty标签 — OpenGraph 及其他基于 property 的 meta- 带安全锁定 rel 允许列表的
link标签(canonical、alternate、author、license、nlweb、site.standard.document)—stylesheet、prefetch及类似资源加载 rel 被有意禁止 - JSON-LD 图
若你的「页面注入」需求是结构化数据或 SEO 元数据,请留在沙箱并使用
page:metadata。若你确实需要向访客浏览器投递 JavaScript 或 HTML,那就是选择原生的情形。
若以上功能都不适用,请使用沙箱格式。
沙箱运行器与平台支持
沙箱本身是可插拔的。EmDash 暴露 sandboxRunner 配置选项,由运行器决定如何隔离插件代码——插件格式本身没有 Cloudflare 特有内容。
EmDash 附带两个运行器:来自 @emdash-cms/cloudflare 的 sandbox(),通过 Cloudflare 的 Worker Loader 将每个插件作为 Dynamic Worker 运行;以及 @emdash-cms/sandbox-workerd/sandbox,在 Node.js 上的 workerd 子进程中运行插件。Plugin Sandbox 涵盖每个运行器的设置、其强制的资源限制,以及两者的差异。
若未配置运行器,列在 sandboxed: [] 下的插件不会被加载。若配置的运行器在当前平台上不可用,它们也不会被加载,EmDash 会在启动时记录警告。
若希望沙箱插件在没有沙箱运行器的平台上运行,请将其从 sandboxed: [] 移到 plugins: [] 数组——它将在进程内执行。能力声明仍会被遵守(同一 PluginContext 工厂对 ctx.content、ctx.http 等设门),但没有隔离边界、没有资源限制,有缺陷或恶意的插件可直接调用 fetch()、读取环境变量或阻塞事件循环。在没有活动沙箱运行器时,出于信任目的,将每个插件视为原生插件。