选择插件格式

本页内容

EmDash 插件以两种格式之一提供:sandboxed(沙箱)或 native(原生)。这个选择影响插件的安装方式、运行时的执行方式以及可用的功能。

默认选择沙箱。 沙箱插件可以发布到市场,并通过管理界面一键安装。原生插件需要代码更改、npm install 以及在每个想要使用它们的站点上重新部署。沙箱是终端用户想要的。

只有在需要沙箱无法提供的功能时才选择原生。

快速对比

SandboxedNative
编写形式emdash-plugin.jsonc + src/plugin.tsdefinePlugin() 描述符
安装方法从管理市场一键安装npm install + 编辑 astro.config
运行环境由沙箱运行器提供的隔离运行时与 Astro 站点相同的进程
功能由沙箱桥强制执行由同一桥在进程内强制执行
资源限制由运行器强制执行 — 通常是 CPU、子请求、墙上时间、内存
网络访问ctx.http,限制为 allowedHostsctx.http,限制为 allowedHosts
直接 fetch() / process.env被运行器阻止可能(插件代码共享运行时)
分发市场上的 .tar.gznpm 包
管理界面Block Kit(JSON 描述)路由React 组件,或 Block Kit
设置界面Block Kit 页面 + KV 读取admin.settingsSchema(自动表单)或 Block Kit
Portable Text 渲染组件不可用componentsEntry 提供 Astro 组件
页面元数据贡献page:metadata 钩子 — meta/property 标签、允许列表的 <link> rels、JSON-LDpage:metadata 钩子(相同表面)
页面片段注入不可用 — 仅通过 page:metadata 的 meta/JSON-LDpage:fragments 钩子 — 内联脚本、外部脚本、原始 HTML
构造函数选项无 — 在运行时从 KV 读取设置描述符上的 options

选择原生会失去什么

原生插件看起来像是同一事物的更强大版本,确实如此 — 但成本很高:

  • 没有市场。 每个站点都必须安装你的 npm 包,编辑 astro.config.mjs,并重新部署。
  • 没有隔离。 插件中的错误可能会使主机进程崩溃或耗尽其 CPU 预算。钩子中未处理的拒绝可能会连同周围的请求一起崩溃。
  • 用户的信任负担。 原生插件拥有与主机站点相同的访问权限。最终用户无法仅通过功能声明来审计它们。

如果你的插件可以在沙箱中完成其工作,它就应该这样做。

何时选择原生

选择原生有三个原因,它们都是关于需要与主机站点进行构建时集成的功能:

  1. 自定义 React 管理页面或小部件。 沙箱插件使用 Block Kit 描述其管理界面 — 这是一个 JSON 模式,管理员代表插件渲染它。如果你需要完整的 React(自定义钩子、第三方组件、复杂状态),你需要原生。

  2. 用于在公共站点上渲染 Portable Text 块的 Astro 组件。 沙箱插件可以声明自定义块类型,但在公共站点上渲染它的 Astro 组件必须在构建时从 npm 加载。只有原生插件可以提供 componentsEntry

  3. 将原始 HTML、脚本或样式表注入公共页面。 page:fragments 钩子将第一方代码发送到访问者的浏览器 — 在任何沙箱边界之外。它仅限于原生插件。沙箱插件仍然可以通过 page:metadata 钩子为公共页面做出贡献,它涵盖了许多实际用例:

    • meta 标签(name + content) — SEO 描述、robots 指令、Twitter 卡片
    • property 标签 — OpenGraph 和其他基于属性的 meta
    • 带有安全锁定的 rel 允许列表的 link 标签(canonicalalternateauthorlicensenlwebsite.standard.document) — stylesheetprefetch 和类似的资源加载 rels 被故意禁止
    • JSON-LD 图

    如果你的”页面注入”需求是结构化数据或 SEO 元数据,保持沙箱并使用 page:metadata。如果你确实需要向访问者的浏览器发送 JavaScript 或 HTML,那就是选择原生的情况。

如果你不确定,选择沙箱。你总是可以稍后迁移到原生 — 但反过来更难,因为原生专用功能没有沙箱等效物。

沙箱运行器和平台支持

沙箱本身是可插拔的。EmDash 公开了一个 sandboxRunner 配置选项,运行器决定如何隔离插件代码 — 插件格式本身没有任何 Cloudflare 特定的内容。

今天大多数站点使用的运行器是来自 @emdash-cms/cloudflaresandbox(),它使用 Cloudflare Workers 的 Dynamic Worker Loader。Worker Loader 按插件 ID 缓存 V8 隔离,因此隔离冷启动成本只支付一次;运行器在每次调用时构造一个新的 worker stub 和桥绑定,因为 stub 和绑定与调用请求的 I/O 上下文绑定。其他平台的运行器(通过 workerd 的 Node.js,以及潜在的 Deno)正在开发中。

如果没有配置运行器,或者如果配置的运行器报告在当前平台上不可用,则在启动时跳过 sandboxed: [] 下列出的插件,并记录调试级别日志。

如果你想让沙箱插件在没有沙箱运行器的平台上运行,将它从 sandboxed: [] 移动到 plugins: [] 数组 — 它将在进程内执行。功能声明仍然得到遵守(相同的 PluginContext 工厂控制 ctx.contentctx.http 和其他),但没有隔离边界,没有资源限制,有错误或恶意的插件可以直接调用 fetch()、读取环境变量或阻塞事件循环。在没有活动的沙箱运行器的情况下,出于信任目的将每个插件视为原生插件。

下一步