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()、讀取環境變數或阻塞事件迴圈。在沒有作用中沙箱執行器時,出於信任目的,將每個外掛視為原生外掛。