このサイトは非公式の日本語訳です。Cloudflare・EmDashプロジェクトが運営するサイトではありません。

このページで分かること

  • パッケージの構成とエクスポート(../admin./astro)、プラグインのIDとバージョンの決まり
  • 公開前にtarballの中身を確かめる手順と、READMEに書く内容
  • npmへの公開とインストール、サイトと並行して開発する方法、ネイティブ型はレジストリに公開できないこと
難易度
上級
読む時間
5分
このページの目次

ネイティブ型プラグインは、ホストのプロジェクトにインストールし、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つのエントリーポイントをすべて公開します。

package.json
{
	"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がない場合は、./adminsrc/admin、管理画面専用のピア依存関係を削除します。Portable Textのレンダラーがない場合は、./astrosrc/astroastro のピア依存関係を削除します。エクスポートするソースのエントリーポイントがインポートする、ホスト側が持つライブラリには、すべてピア依存関係を追加します。こうすると、React、Kumo、Lingui、React Queryの2つ目のインスタンスが管理画面のバンドルに入るのを防げます。

エントリーポイントごとに、読み込む側が異なります。

エクスポート 必要になる場合 読み込む側
. 常に Astroの設定がディスクリプターのファクトリーをインポートします。EmDashは実行時に名前付きの createPlugin() をインポートします。
./admin adminEntry を設定している場合 ホストのブラウザー用ビルドが、Reactのコンポーネントマップをインポートします。
./astro componentsEntry を設定している場合 ホストのAstroのビルドが blockComponents をインポートします。

ディスクリプターとランタイムで指定するモジュール指定子は、これらのエクスポートと一致させる必要があります。

src/index.ts
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環境を含めます。

tsconfig.json
{
	"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 という名前の使い捨てのサイトが、プラグインのディレクトリと同じ階層にあることを前提にしています。

  1. パッケージをビルドし、型チェックします。

    pnpm typecheck
    pnpm build
    
  2. npmのtarballを作成し、npmが表示するファイルの一覧を確認します。

    npm pack
    

    この例のパッケージでは、npmは example-plugin-activity-0.1.0.tgz を作成します。

  3. 出力に dist/index.mjsdist/index.d.mts、エクスポートした ./admin./astro のモジュールからたどれるすべてのソースファイルが含まれていることを確認します。

  4. 作成したtarballを、使い捨てのEmDashサイトにインストールします。

    cd ../my-emdash-site
    pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz
    
  5. パッケージの作成と登録に従い、使い捨てのサイトの 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のレンダラー、信頼されたフラグメント、その他のプロセス内の依存関係を必要としなくなった場合は、レジストリを通じて公開する前にサンドボックス型の形式に変換します。