ネイティブ型プラグインの配布
このページで分かること
- パッケージの構成とエクスポート(
.、./admin、./astro)、プラグインのIDとバージョンの決まり - 公開前にtarballの中身を確かめる手順と、READMEに書く内容
- npmへの公開とインストール、サイトと並行して開発する方法、ネイティブ型はレジストリに公開できないこと
このページの目次
ネイティブ型プラグインは、ホストのプロジェクトにインストールし、astro.config.mjs で登録するnpmパッケージです。パッケージには、ディスクリプターと createPlugin() のための、ビルド済みのサーバー用エントリーが必要です。ReactやAstroのコンポーネントも同梱する場合は、それらを別のソースのエントリーポイントとしてエクスポートします。こうすると、ホストがそれぞれを正しい環境向けにコンパイルできます。
パッケージの構成
次の構成では、サーバーのランタイムと、ブラウザー用・Astro用のソースを分けています。
plugin-activity/
├── src/
│ ├── index.ts
│ ├── admin/
│ │ ├── index.tsx
│ │ └── ActivityPage.tsx
│ └── astro/
│ ├── index.ts
│ └── ActivityBlock.astro
├── dist/
│ ├── index.mjs
│ └── index.d.mts
├── package.json
├── tsconfig.json
└── README.md
dist/ は生成されるディレクトリです。src/admin/ と src/astro/ は、公開するtarballに含めたままにします。ホストのViteとAstroのビルドが、これらのエントリーポイントを処理する必要があるためです。
パッケージのエクスポート
次の package.json は、サーバー用のエントリーをビルドし、3つのエントリーポイントをすべて公開します。
{
"name": "@example/plugin-activity",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.mjs",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
},
"./admin": "./src/admin/index.tsx",
"./astro": "./src/astro/index.ts"
},
"files": ["dist", "src/admin", "src/astro"],
"scripts": {
"build": "tsdown src/index.ts --format esm --dts --clean",
"dev": "tsdown src/index.ts --format esm --dts --watch",
"typecheck": "tsc --noEmit",
"prepublishOnly": "pnpm typecheck && pnpm build"
},
"peerDependencies": {
"@cloudflare/kumo": "*",
"@emdash-cms/admin": "*",
"@lingui/core": "*",
"@lingui/react": "*",
"@tanstack/react-query": "*",
"astro": ">=6.0.0-beta.0",
"emdash": "*",
"react": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"tsdown": "^0.20.0",
"typescript": "^5.9.0"
},
"keywords": ["emdash", "emdash-plugin"],
"license": "MIT"
}
プラグインに信頼されたReactのUIがない場合は、./admin、src/admin、管理画面専用のピア依存関係を削除します。Portable Textのレンダラーがない場合は、./astro、src/astro、astro のピア依存関係を削除します。エクスポートするソースのエントリーポイントがインポートする、ホスト側が持つライブラリには、すべてピア依存関係を追加します。こうすると、React、Kumo、Lingui、React Queryの2つ目のインスタンスが管理画面のバンドルに入るのを防げます。
エントリーポイントごとに、読み込む側が異なります。
| エクスポート | 必要になる場合 | 読み込む側 |
|---|---|---|
. |
常に | Astroの設定がディスクリプターのファクトリーをインポートします。EmDashは実行時に名前付きの createPlugin() をインポートします。 |
./admin |
adminEntry を設定している場合 |
ホストのブラウザー用ビルドが、Reactのコンポーネントマップをインポートします。 |
./astro |
componentsEntry を設定している場合 |
ホストのAstroのビルドが blockComponents をインポートします。 |
ディスクリプターとランタイムで指定するモジュール指定子は、これらのエクスポートと一致させる必要があります。
export function activityPlugin(): PluginDescriptor {
return {
id: "plugin-activity",
version: "0.1.0",
format: "native",
entrypoint: "@example/plugin-activity",
adminEntry: "@example/plugin-activity/admin",
componentsEntry: "@example/plugin-activity/astro",
};
}
export function createPlugin() {
return definePlugin({
id: "plugin-activity",
version: "0.1.0",
admin: {
entry: "@example/plugin-activity/admin",
},
});
}
npmパッケージのバージョン、ディスクリプターのバージョン、definePlugin() のバージョンは同じ値に保ちます。サイトの管理者に表示されるバージョンはプラグインの定義から取得され、package.json から自動的に取得されるわけではありません。
プラグインのIDとバージョン
definePlugin() は、英小文字・数字・ハイフンからなるスコープなしのIDか、@scope/name の形式のスコープ付きIDを受け付けます。サイトのプラグインには、スコープなしのケバブケースのIDを使います。IDは /_emdash/api/plugins/<plugin-id>/<route> のパスの1つのセグメントにもなるためです。
次の値は、受け付けられる形式と、プラグインIDとnpmパッケージ名を分ける推奨の方法を示しています。
id: "plugin-activity"; // Recommended: valid in plugin route URLs
id: "@example/plugin-activity"; // Accepted by definePlugin(), but not one URL segment
entrypoint: "@example/plugin-activity"; // The npm package may stay scoped
バージョンは、セマンティックバージョニングの major.minor.patch の並びで始まる必要があります。ディスクリプターとランタイムの両方で、完全なセマンティックバージョンを使います。
version: "1.0.0"; // Valid
version: "1.2.3-beta.1"; // Valid prerelease
version: "1.0"; // Invalid: missing patch version
TypeScriptの設定
ネイティブ型の雛形は、適切な tsconfig.json を作成します。雛形を作ったあとでプラグインにReactとAstroのソースを追加した場合は、両方のJSX環境を含めます。
{
"compilerOptions": {
"target": "ES2022",
"module": "preserve",
"moduleResolution": "bundler",
"strict": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react-jsx",
"types": ["astro/client"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
パッケージにする前に、ソースのエントリーポイントに対して pnpm typecheck を実行します。build スクリプトがコンパイルするのは src/index.ts だけです。エクスポートした管理画面用とAstro用のソースは、ホストがパッケージを読み込むときにコンパイルします。
パッケージの中身の確認
公開する前に、実際のtarballの中身をテストします。次のコマンドは、my-emdash-site という名前の使い捨てのサイトが、プラグインのディレクトリと同じ階層にあることを前提にしています。
-
パッケージをビルドし、型チェックします。
pnpm typecheck pnpm build -
npmのtarballを作成し、npmが表示するファイルの一覧を確認します。
npm packこの例のパッケージでは、npmは
example-plugin-activity-0.1.0.tgzを作成します。 -
出力に
dist/index.mjs、dist/index.d.mts、エクスポートした./adminと./astroのモジュールからたどれるすべてのソースファイルが含まれていることを確認します。 -
作成したtarballを、使い捨てのEmDashサイトにインストールします。
cd ../my-emdash-site pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz -
パッケージの作成と登録に従い、使い捨てのサイトの
astro.config.mjsでディスクリプターのファクトリーをインポートして登録します。そのあと、ホストのサイトをビルドします。pnpm buildプラグインの管理画面をすべて開き、プラグインが追加するPortable Textのブロックをすべて描画します。ビルドの前に登録しておくと、Astroがtarballの
./adminと./astroのエクスポートを解決します。サーバー側だけのパッケージのテストでは、ブラウザー用のソースファイルや.astroのソースファイルの欠落を見つけられません。
やさしい解説
WordPressのプラグインはzipファイルにまとめて配布しますが、EmDashのネイティブ型プラグインはnpmパッケージとして配布します。npm pack で作るtarballは、npmに公開されるファイルをまとめたものです。この節の手順では、公開する前にそのtarballを使い捨てのサイトに実際にインストールし、ビルドして動作を確かめます。管理画面用とAstro用のソースはサイト側でコンパイルされるため、ファイルが1つ欠けていてもサイトをビルドするまで気づけません。
READMEの内容
サイトの運用者が、ソースを読まなくてもパッケージをインストールして評価できるだけの情報を書きます。次の内容を含めます。
- 1文の説明と、対応するEmDashのバージョン
- インストールのコマンドと、
astro.config.mjsでの登録の完全な例 - ネイティブ型の信頼境界と、そのプラグインがネイティブ型で動く必要がある理由
- 宣言しているすべての権限(Capability)と許可するホスト、それぞれを使う機能
- 設定項目とその初期値
- 必要なレイアウトのコンポーネント(例:bodyの末尾に出力するフラグメントのための
EmDashBodyEnd) - 運用者の対応が必要な変更についてのアップグレード手順
権限の宣言を、分離のための境界として説明しないでください。権限の宣言は ctx のAPIを使えるかどうかを制御しますが、ネイティブ型のコードは、ホストのプロセスで使えるインポート、環境変数、直接のネットワーク通信を引き続き使えます。
npmへの公開
tarballのテストに通ったら公開します。
npm publish --access public
スコープ付きパッケージを初めて公開するときは --access public が必要です。以降のリリースではセマンティックバージョニングを使います。コンストラクターのオプション、保存するデータ、ホスト側に必要な変更、パッケージのエクスポート、プラグインの信頼に関する要件の変更は、互換性に関わる判断として扱います。アップグレードで新しい権限や許可するホストが必要になる場合は、ネイティブ型のインストールには権限の同意を求める画面がないとしても、リリースノートで明記します。
npmからのインストール
運用者は、公開されたパッケージをEmDashのサイトにインストールします。
pnpm add @example/plugin-activity
そのあと、パッケージの作成と登録に示したとおり、astro.config.mjs でディスクリプターのファクトリーをインポートして登録します。依存関係をインストールしただけでは、プラグインは有効になりません。Astroの設定を変更してサイトをデプロイすると、インストールが完了します。
ホストのサイトと並行した開発
プラグインをウォッチモードでビルドします。
pnpm dev
ホストのサイトから、ローカルのディレクトリをインストールします。
pnpm add ../plugin-activity
astro.config.mjs でプラグインのディスクリプターのファクトリーを登録し、ホストの開発サーバーを起動します。ディスクリプターのメタデータやパッケージのエクスポートを変更したら、サーバーを再起動します。使っている環境で、パッケージマネージャーのファイル依存関係がリンクではなくファイルのコピーになる場合は、再ビルドのあとにインストールし直します。ワークスペースの依存関係や pnpm link を使うと、開発中もローカルのパッケージがつながったままになります。
レジストリとの境界
ネイティブ型のパッケージは、EmDashのレジストリに公開できません。レジストリのプラグインは、サンドボックス型のパッケージ形式、署名付きのリリースのワークフロー、インストール時の同意の流れを使います。プラグインがReactの管理画面のコード、Astroのレンダラー、信頼されたフラグメント、その他のプロセス内の依存関係を必要としなくなった場合は、レジストリを通じて公開する前にサンドボックス型の形式に変換します。