「WordPressみたいに、あとからプラグインで機能を足せますか?」。EmDashでの構築を検討している制作会社なら、まず気になるのがここだと思います。答えは「足せます。ただし入れ方が2種類あって、任せられる範囲がまったく違います」。

WordPressのプラグインは、入れた瞬間にサイト本体と同じ権限で動きます。EmDashには、それと同じ動き方をするネイティブ型と、申告した権限しか持てないサンドボックス型があります。どちらで入れるかで、クライアントに管理画面から触らせてよいかどうかが変わるんです。

2種類のプラグインは「どこで動くか」が違う

  • サンドボックス型:サイトとは別の実行環境で動きます。管理画面のレジストリから選んでインストールでき、デプロイは要りません。
  • ネイティブ型:サイトと同じプロセスで動きます。npmで入れて astro.config.mjs に書き、デプロイし直して初めて有効になります。

公式ドキュメントの方針は「ネイティブでなければできないこと以外はサンドボックス型を選ぶ」です。ネイティブでしかできないのは、React製の管理画面、本文の独自ブロックの描画、公開ページへのスクリプトや生HTMLの差し込みといった、サイトの組み立てに食い込む機能に限られます。本文ブロックの拡張は 本文にCTAや動くデモを入れる4つの方法 で詳しく書いています。

このサイトで使っているプラグインは1本だけ。ACFのリピーターのような入力欄を足す Field Kit の1本だけです。管理画面にReactの入力ウィジェットを追加するものなので、ネイティブ型として plugins: [] に登録しています。

サンドボックス型とネイティブ型の比較表。動く場所、入れ方、権限、外部通信、向く用途

サンドボックス型は、申告した権限しか持てない

サンドボックス型のプラグインは、使う権限をマニフェスト(設定ファイル)の capabilities に書いておく必要があります。content:read を書いていないプラグインには、記事を読むための道具がそもそも渡されません。呼んで拒否される、のではありません。呼ぶ手段が無い作りです。

インストール済みの emdash 0.32.0 の実装と公式ドキュメントで、次の挙動を確認しました。

  • 外部への通信は許可リスト制:allowedHosts に書いたホストにしか届きません。*.example.com と書くと、サブドメインに加えて example.com そのものも通ります。リダイレクトされた先も1回ずつ検査されます。上限は5回です。
  • 環境変数・ファイル・バインディングは見えない:サイトのWorkerにAPIキーを置いていても、プラグインからは読めません。
  • 使いすぎたら止まる:Cloudflare上では、1回の呼び出しあたりCPU時間50ミリ秒・サブリクエスト10件・実時間30秒が上限です。超えた呼び出しは失敗扱いです。フックの場合はログを残してリクエストがそのプラグイン抜きで進みます。
  • 更新で権限が増えたら、もう一度同意が要る:インストール時の同意画面に権限の一覧が出ます。新しいバージョンが権限を追加していると CAPABILITY_ESCALATION で止まり、承認し直すまで更新されません。

最後の点は、WordPressの運用でも起きうる、自動更新で知らないうちに通信先が増えていたという事故を、仕組みで防いでくれるところだと感じています。

サンドボックスが守る4つ。権限は申告制、通信は許可制、環境変数やファイルは見えない、更新で権限が増えたら再同意

権限を絞っても防げないこと

ただし、万能ではありません。公式ドキュメントも、強制できないことをはっきり書いています。

  • 権限の粒度は粗い:content:write を持つプラグインは、自分が作った記事に限らずどの記事でも書き換えられます。
  • 編集中のロックは効かない:編集者が記事を開いていても、プラグインからの更新や削除は止まりません。
  • 通信先を自由に決められる権限がある:network:request:unrestricted は、送信先URLを運用者が入力するWebhook系プラグイン用です。決まったAPIしか呼ばないプラグインがこれを要求していたら、理由を確認したほうがいいでしょう。
  • ネイティブ型には何も効かない:同じプロセスで動くので、fetch() も環境変数も直接触れます。サイト本体と同じ信頼が要ります。

入れる前に見るべきは2点。何の権限を要求しているか、その権限が機能に見合っているか、です。

Cloudflareで動かすには、有料プランと設定が要る

サンドボックス型は、Cloudflare Workersでは Dynamic Worker(サイトのWorkerから別のWorkerを起動する仕組み)として動きます。これは Workers の有料プラン限定です。無料プランのままなら、使えるのはネイティブ型だけになります。

有効にするには3か所を触ります。

// wrangler.jsonc
"worker_loaders": [{ "binding": "LOADER" }]

// src/worker.ts(PluginBridge をエントリから再エクスポート)
export { default, PluginBridge } from "@emdash-cms/cloudflare/worker";

// astro.config.mjs
import { sandbox } from "@emdash-cms/cloudflare";
emdash({ sandboxRunner: sandbox(), /* ... */ });
Cloudflareでサンドボックス型を有効にする4手順。有料プラン、LOADERバインディング、PluginBridgeの再エクスポート、sandboxRunnerの指定

LOADER が無いと、ビルド時に警告が出てサンドボックスは無効のままです。その状態で管理画面からインストールしようとすると SANDBOX_NOT_AVAILABLE で失敗します。サイトの他の部分は普通に動きます。気づくのはインストールを試したときです。

このサイトは今この状態です。PluginBridge の再エクスポートは 予約投稿を公開させるcron のために済ませてありますが、LOADER と sandboxRunner は入れていません。サンドボックスを無理やり外す sandbox: false はWorkersでは起動自体を拒否されるので、とりあえず本体の中で動かす、という逃げ道もありません。

納品前に、プラグインの扱いを決めておく

案件の最初に決めておきたいのは次の3つです。

  • 誰がインストールするか:レジストリからのインストールには plugins:manage 権限、つまり管理者(Admin)が必要です。クライアント側に管理者を置くかどうかは 管理画面をどこまで渡すか と一緒に決めます。
  • サンドボックスを有効にするか:有料プランにしないならネイティブ型だけの運用になり、追加のたびにこちらでデプロイします。
  • 入っているプラグインを1枚にまとめる:名前、型(サンドボックス/ネイティブ)、要求している権限を一覧にして納品物に含めます。引き継いだ人が「これは何のために入っているのか」で止まらないようにするためです。

プラグインの多い構成で困るのは、たいてい、誰がいつ何のために入れたか分からないプラグインです。EmDashなら権限が一覧で見えます。そこを最初から整理した状態で渡せます。

EmDashやヘッドレスCMSでの構築・機能追加を任せられる実装パートナーを探している制作会社の方は、お問い合わせ からお気軽にご相談ください。

本記事は2026年9月時点の情報です(emdash 0.32.0 の実装と公式ドキュメントで確認)。