Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

Pages Plugins

最終更新 Markdown で表示Agent セットアップ

Cloudflare は、Pages プロジェクトで使える公式 Pages Plugins をいくつか提供しています。


Pages Plugin を作成する

Pages Plugin は、組み込みのルーティングと機能を含む、配布可能な Pages Functions です。開発者は Pages プロジェクトの好きな場所に Plugin を含め、設定オプションを渡せます。ミドルウェア、パラメーター付きルート、静的アセットなど、Functions の機能をすべて Plugin で使えます。

たとえば、Pages Plugin では次のようなことができます。

  • HTML ページを傍受し、サードパーティのスクリプトを挿入する。
  • サードパーティサービスの API をプロキシする。
  • 認可ヘッダーを検証する。
  • 管理者向けの Web アプリ体験を一式提供する。
  • KV または Durable Objects にデータを保存する。
  • CMS のデータを使って Web ページをサーバーサイドレンダリング(SSR)する。
  • エラーを報告し、パフォーマンスを追跡する。

Pages Plugin は、既存の Pages プロジェクトを Functions と深く統合して拡張するためのライブラリです。

Pages Plugin を使う

開発者は、アプリケーションのルートに Pages Plugin をマウントしてプロジェクトを強化できます。Plugin は、通常どこにマウントすべきかの手順を提供します(例: 管理画面は functions/admin/[[path]].ts、エラーロガーは functions/_middleware.ts)。加えて、Plugin ごとに設定を受け取ることがあります(例: API トークン)。


静的フォームの例

この例では、Pages Plugin を作成し、プロジェクトに含めます。

最初の Plugin の役割は次のとおりです。

  • HTML フォームを傍受する。
  • フォーム送信を KV に保存する。
  • 開発者が指定したレスポンスで送信に応答する。

1. 新しい Pages Plugin を作成する

次の内容で package.json を作成します。

{
	"name": "@cloudflare/static-form-interceptor",
	"main": "dist/index.js",
	"types": "index.d.ts",
	"files": ["dist", "index.d.ts", "tsconfig.json"],
	"scripts": {
		"build": "npx wrangler pages functions build --plugin --outdir=dist",
		"prepare": "npm run build"
	}
}

この例では、dist/index.js が Plugin のエントリポイントになります。これは Wrangler が npm run build コマンドで生成するファイルです。dist/ ディレクトリを .gitignore に追加します。

次に、functions ディレクトリを作成し、Plugin の実装を始めます。functions フォルダーは、開発者によってあるルートにマウントされます。ファイル構成をどうするか検討してください。一般的には次のとおりです。

  • Plugin を、開発者が選んだ単一ルート(例: /foo)で動かしたい場合は、functions/index.ts を作成します。
  • Plugin をマウントし、あるパス以降のすべてのリクエスト(例: /admin/login/admin/dashboard)を処理したい場合は、functions/[[path]].ts を作成します。
  • リクエストを傍受しつつ、ほかの Functions またはプロジェクトの静的アセットにフォールバックしたい場合は、functions/_middleware.ts を作成します。

必要な数だけファイルを使えます。Plugin の構成は、現在の Pages プロジェクトの Functions とまったく同じです。違いは、ハンドラーがパラメーターオブジェクトの新しいプロパティ pluginArgs を受け取ることです。このプロパティは、開発者が Plugin をマウントするときに渡す初期化パラメーターです。API トークン、KV / Durable Object 名前空間など、Plugin の動作に必要なものを受け取れます。

静的フォームの例に戻ります。リクエストを傍受し、HTML フォームの挙動を上書きするには、functions/_middleware.ts を作成します。開発者は、単一ルートまたはプロジェクト全体に Plugin をマウントできます。

class FormHandler {
	element(element) {
		const name = element.getAttribute("data-static-form-name");
		element.setAttribute("method", "POST");
		element.removeAttribute("action");
		element.append(
			`<input type="hidden" name="static-form-name" value="${name}" />`,
			{ html: true },
		);
	}
}

export const onRequestGet = async (context) => {
	// We first get the original response from the project
	const response = await context.next();

	// Then, using HTMLRewriter, we transform `form` elements with a `data-static-form-name` attribute, to tell them to POST to the current page
	return new HTMLRewriter()
		.on("form[data-static-form-name]", new FormHandler())
		.transform(response);
};

export const onRequestPost = async (context) => {
	// Parse the form
	const formData = await context.request.formData();
	const name = formData.get("static-form-name");
	const entries = Object.fromEntries(
		[...formData.entries()].filter(([name]) => name !== "static-form-name"),
	);

	// Get the arguments given to the Plugin by the developer
	const { kv, respondWith } = context.pluginArgs;

	// Store form data in KV under key `form-name:YYYY-MM-DDTHH:MM:SSZ`
	const key = `${name}:${new Date().toISOString()}`;
	context.waitUntil(kv.put(name, JSON.stringify(entries)));

	// Respond with whatever the developer wants
	const response = await respondWith({ formData });
	return response;
};

2. Pages Plugin に型を付ける

開発者体験をよくするために、Plugin に TypeScript の型を付けることを検討してください。IDE のオートコンプリートが使え、想定するパラメーターを漏れなく含められるようになります。

index.d.ts で、pluginArgs を受け取り PagesFunction を返す関数をエクスポートします。静的フォームの例では、2 つのプロパティを受け取ります。kv は KV 名前空間、respondWithformData プロパティ(FormData)を持つオブジェクトを受け取り、ResponsePromise を返す関数です。

export type PluginArgs = {
	kv: KVNamespace;
	respondWith: (args: { formData: FormData }) => Promise<Response>;
};

export default function (args: PluginArgs): PagesFunction;

3. Pages Plugin をテストする

Pages Plugin 作者向けのテスト体験は、まだ整備中です。揃うまでしばらくお待ちください。当面は、サンプルプロジェクトを作成し、テスト用に Plugin を手動で含めてください。

4. Pages Plugin を公開する

Plugin の配布方法は自由です。よくある選択肢は、npm での公開、Developer Discord の #what-i-built または #pages-discussions チャンネルでの紹介、GitHub でのオープンソース化です。

生成された dist/ ディレクトリ、型定義の index.d.ts、開発者向け手順を書いた README.md を含めてください。


5. Pages Plugin をインストールする

アプリケーションに Pages Plugin を含めるには、まずその Plugin をプロジェクトへインストールします。

プロジェクトでまだ npm を使っていない場合は、npm init を実行して package.json ファイルを作成します。Plugin の README.md には、通常インストールコマンドが載っています(例: npm install --save @cloudflare/static-form-interceptor)。

6. Pages Plugin をマウントする

Plugin の README.md には、アプリケーションへのマウント方法が載っていることが多いです。次を実施します。

  1. まだない場合は、functions ディレクトリを作成します。
  2. この Plugin を動かす場所を決め、functions ディレクトリに対応するファイルを作成します。
  3. このファイルで Plugin をインポートし、必要な引数で初期化したうえで、onRequest メソッドをエクスポートします。

静的フォームの例では、作成した Plugin はミドルウェアです。単一ルートでも、プロジェクト全体でも動かせます。サイトの /contact に問い合わせフォームが 1 つだけある場合は、functions/contact.ts を作成してそのルートだけを傍受できます。functions/_middleware.ts を作成して、ほかのルートと将来追加するフォームも傍受することもできます。この Plugin をどこで動かすかは、開発者が選べます。

Plugin のデフォルトエクスポートは、通常の Pages Functions ハンドラーと同じコンテキストパラメーターを受け取る関数です。

import staticFormInterceptorPlugin from "@cloudflare/static-form-interceptor";

export const onRequest = (context) => {
	return staticFormInterceptorPlugin({
		kv: context.env.FORM_KV,
		respondWith: async ({ formData }) => {
			// Could call email/notification service here
			const name = formData.get("name");
			return new Response(`Thank you for your submission, ${name}!`);
		},
	})(context);
};

7. Pages Plugin をテストする

wrangler pages dev を使うと、インストールした Plugin を含む Pages プロジェクトをテストできます。Plugin が必要とする KV バインディングと環境変数を忘れずに含めてください。

Plugin を /contact ルートにマウントした場合、対応する HTML ファイルは次のようになります。

<!DOCTYPE html>
<html>
	<body>
		<h1>Contact us</h1>
		<!-- Include the `data-static-form-name` attribute to name the submission -->
		<form data-static-form-name="contact">
			<label>
				<span>Name</span>
				<input type="text" autocomplete="name" name="name" />
			</label>
			<label>
				<span>Message</span>
				<textarea name="message"></textarea>
			</label>
		</form>
	</body>
</html>

Plugin は data-static-form-name="contact" 属性を検出し、method="POST" を設定し、<input type="hidden" name="static-form-name" value="contact" /> 要素を挿入し、POST 送信をキャプチャします。

8. Pages プロジェクトをデプロイする

新しい Plugin が package.json に追加され、ローカルで想定どおり動くことを確認します。そのあと git commitgit push を実行し、Cloudflare Pages のデプロイを開始します。

特定の Plugin で問題が起きた場合は、その Plugin のバグトラッカーに issue を登録してください。

Plugin 全般で問題が起きた場合は、Discord の #pages-discussions チャンネルへフィードバックをお願いします。Plugin で作られるもの、および作者体験や開発者体験へのフィードバックを歓迎します。Plugin をさらに強力にするために必要なことがあれば、Discord チャンネルで知らせてください。


Plugin をチェーンする

最後に、Pages Functions 全般と同様、Plugin をチェーンして機能を組み合わせられます。ファイルシステム上でより上位に定義したミドルウェアは、ほかのハンドラーより先に実行されます。個別のファイルでは、次のように配列で Functions をチェーンできます。

import sentryPlugin from "@cloudflare/pages-plugin-sentry";
import cloudflareAccessPlugin from "@cloudflare/pages-plugin-cloudflare-access";
import adminDashboardPlugin from "@cloudflare/a-fictional-admin-plugin";

export const onRequest = [
	// Initialize a Sentry Plugin to capture any errors
	sentryPlugin({ dsn: "https://sentry.io/welcome/xyz" }),

	// Initialize a Cloudflare Access Plugin to ensure only administrators can access this protected route
	cloudflareAccessPlugin({
		domain: "https://test.cloudflareaccess.com",
		aud: "4714c1358e65fe4b408ad6d432a5f878f08194bdb4752441fd56faefa9b2b6f2",
	}),

	// Populate the Sentry plugin with additional information about the current user
	(context) => {
		const email =
			context.data.cloudflareAccessJWT.payload?.email || "service user";

		context.data.sentry.setUser({ email });

		return next();
	},

	// Finally, serve the admin dashboard plugin, knowing that errors will be captured and that every incoming request has been authenticated
	adminDashboardPlugin(),
];

役に立ちましたか?