EmDash のプラグインシステムを使用すると、コアコードを変更することなく CMS を拡張できます。プラグインは、コンテンツライフサイクルイベントにフックし、独自のデータを保存し、管理者に設定を公開し、管理パネルにカスタム UI を追加できます。
設計哲学
EmDash プラグインには、サンドボックス化とネイティブの 2 つのタイプがあります。サンドボックス化されたプラグインは分離された V8 ワーカーで実行され、マーケットプレイスからワンクリックでインストールできます。ネイティブプラグインはインプロセスで実行され、コードで設定されます。
サンドボックス化されたプラグインを優先してください。 管理 UI からコードに触れることなく、または再デプロイすることなくインストール、更新、削除できます。ビルド時統合が必要な機能(React 管理ページ、Portable Text レンダリングコンポーネント、またはページフラグメント注入)が必要な場合にのみ、ネイティブプラグインを使用してください。
主要な原則:
- サンドボックス優先 — サンドボックス用に設計し、必要な場合にのみネイティブモードを使用
- 宣言的 — フック、ストレージ、およびルートは定義時に宣言され、動的に登録されない
- 型安全 — 型付きコンテキストオブジェクトを使用した完全な TypeScript サポート
- 能力ベース — プラグインは必要なものを宣言し、サンドボックスがそれを強制する
プラグインができること
イベントにフック
コンテンツ保存、メディアアップロード、プラグインライフサイクルイベントの前後にコードを実行します。
データを保存
データベース移行を書くことなく、インデックス付きコレクションにプラグイン固有のデータを永続化します。
設定を公開
設定スキーマを宣言し、設定用の自動生成された管理 UI を取得します。
管理ページを追加
React コンポーネントを使用してカスタム管理ページとダッシュボードウィジェットを作成します。
API ルートを作成
プラグインの管理 UI または外部統合のエンドポイントを公開します。
HTTP リクエストを実行
セキュリティのために宣言されたホスト制限で外部 API を呼び出します。
プラグインアーキテクチャ
すべてのプラグインは definePlugin() で作成されます:
import { definePlugin } from "emdash";
export default definePlugin({
id: "my-plugin",
version: "1.0.0",
// プラグインがアクセスする必要がある API
capabilities: ["read:content", "network:fetch"],
// プラグインが HTTP リクエストを行うことができるホスト
allowedHosts: ["api.example.com"],
// 永続ストレージコレクション
storage: {
entries: {
indexes: ["userId", "createdAt"],
},
},
// イベントハンドラー
hooks: {
"content:afterSave": async (event, ctx) => {
ctx.log.info("Content saved", { id: event.content.id });
},
},
// REST API エンドポイント
routes: {
status: {
handler: async (ctx) => ({ ok: true }),
},
},
// 管理 UI 設定
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
},
pages: [{ path: "/dashboard", label: "Dashboard" }],
widgets: [{ id: "status", size: "half" }],
},
});
プラグインコンテキスト
すべてのフックとルートハンドラーは、アクセスできる PluginContext オブジェクトを受け取ります:
| プロパティ | 説明 | 可用性 |
|---|---|---|
ctx.storage | プラグインのドキュメントコレクション | 常に(宣言されている場合) |
ctx.kv | 設定と状態のキーバリューストア | 常に |
ctx.content | サイトコンテンツの読み取り/書き込み | read:content または write:content を使用 |
ctx.media | メディアファイルの読み取り/書き込み | read:media または write:media を使用 |
ctx.http | 外部リクエスト用の HTTP クライアント | network:fetch を使用 |
ctx.log | 構造化ロガー(debug、info、warn、error) | 常に |
ctx.plugin | プラグインメタデータ(id、version) | 常に |
ctx.site | サイト情報:name、url、locale | 常に |
ctx.url() | パスから絶対 URL を生成 | 常に |
ctx.users | ユーザー情報の読み取り:get()、getByEmail()、list() | read:users を使用 |
ctx.cron | タスクのスケジュール:schedule()、cancel()、list() | 常に |
ctx.email | メール送信:send() | email:send を使用 + プロバイダー設定 |
コンテキストの形状は、すべてのフックとルートで同じです。能力でゲートされたプロパティは、プラグインが必要な能力を宣言した場合にのみ存在します。
能力
能力は、プラグインコンテキストで使用可能な API を決定します:
| 能力 | アクセス権を付与 |
|---|---|
read:content | ctx.content.get()、ctx.content.list() |
write:content | ctx.content.create()、ctx.content.update()、ctx.content.delete() |
read:media | ctx.media.get()、ctx.media.list() |
write:media | ctx.media.getUploadUrl()、ctx.media.upload()、ctx.media.delete() |
network:fetch | ctx.http.fetch()(allowedHosts に制限) |
network:fetch:any | ctx.http.fetch()(制限なし — ユーザー設定 URL 用) |
read:users | ctx.users.get()、ctx.users.getByEmail()、ctx.users.list() |
email:send | ctx.email.send()(プロバイダープラグインが必要) |
email:provide | email:deliver 排他的フックを登録(トランスポートプロバイダー) |
email:intercept | email:beforeSend / email:afterSend フックを登録 |
page:inject | page:metadata / page:fragments フックを登録 |
登録
Astro 設定でプラグインを登録します:
import { defineConfig } from "astro/config";
import { emdash } from "emdash/astro";
import seoPlugin from "@emdash-cms/plugin-seo";
import auditLogPlugin from "@emdash-cms/plugin-audit-log";
export default defineConfig({
integrations: [
emdash({
plugins: [seoPlugin({ generateSitemap: true }), auditLogPlugin({ retentionDays: 90 })],
}),
],
});
プラグインはビルド時に解決されます。同じ優先度のフックの場合、順序が重要です — 配列内の早いプラグインが最初に実行されます。
実行モード
EmDash は 2 つのプラグイン実行モードをサポートしています:
| モード | 説明 | プラットフォーム |
|---|---|---|
| サンドボックス化 | 強制制限付きの分離された V8 ワーカー | Cloudflare のみ |
| ネイティブ | フルアクセス付きのインプロセス | 任意 |
サンドボックスモードでは、能力はランタイムレベルで強制されます — プラグインは宣言したもののみにアクセスできます。ネイティブモードでは、能力はアドバイザリであり、プラグインは完全なプロセスアクセス権を持ちます。
次のステップ
プラグインを作成
ストレージ、フック、管理 UI を使用して最初のプラグインを構築します。
利用可能なフック
コンテンツ、メディア、プラグインライフサイクル用のすべてのフックを参照します。
プラグインストレージ
ストレージについて学び、プラグインデータをクエリする方法を確認します。
管理 UI
管理ページを追加し、ダッシュボードウィジェットを作成します。
ネイティブ vs. サンドボックス
実行モードを比較し、プラグインに適したものを選択します。