コンテンツにスキップ

ページプラグイン

Cloudflareは、あなたがPagesプロジェクトで使用できる公式のページプラグインをいくつか提供しています:


ページプラグインを作成する

ページプラグインは、組み込みのルーティングと機能を含むPages Functionsの配布可能なものです。開発者は、選択した場所でPagesプロジェクトの一部としてプラグインを含めることができ、いくつかの設定オプションを渡すことができます。Functionsの完全な機能がプラグインに利用可能であり、ミドルウェア、パラメータ化されたルート、静的アセットが含まれます。

例えば、ページプラグインは以下のことができます:

  • HTMLページをインターセプトし、サードパーティのスクリプトを注入する。
  • サードパーティサービスのAPIをプロキシする。
  • 認証ヘッダーを検証する。
  • 完全な管理ウェブアプリ体験を提供する。
  • KVまたはDurable Objectsにデータを保存する。
  • CMSからのデータを使用してウェブページをサーバーサイドレンダリング(SSR)する。
  • エラーを報告し、パフォーマンスを追跡する。

ページプラグインは、本質的に、開発者が既存のPagesプロジェクトをFunctionsに深く統合するために使用できるライブラリです。

ページプラグインを使用する

開発者は、アプリケーションのルートにページプラグインをマウントすることでプロジェクトを強化できます。プラグインは、通常どこにマウントすべきかの指示を提供します(例えば、管理インターフェースはfunctions/admin/[[path]].tsにマウントされるかもしれませんし、エラーロガーはfunctions/_middleware.tsにマウントされるかもしれません)。さらに、各プラグインは一部の設定を受け取ることがあります(例えば、APIトークンを使用して)。


静的フォームの例

この例では、ページプラグインを作成し、それをプロジェクトに含めます。

最初のプラグインは以下のことを行うべきです:

  • HTMLフォームをインターセプトする。
  • フォームの送信をKVに保存する。
  • 開発者のカスタムレスポンスで送信に応答する。

1. 新しいページプラグインを作成する

以下の内容で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がプラグインのエントリポイントになります。これは、npm run buildコマンドでWranglerによって生成されたファイルです。dist/ディレクトリを.gitignoreに追加してください。

次に、functionsディレクトリを作成し、プラグインのコーディングを開始します。functionsフォルダは、開発者によって特定のルートにマウントされるため、ファイルの構造をどのようにしたいかを考慮してください。一般的には:

  • 開発者が選択した単一のルートでプラグインを実行したい場合(例えば、/foo)、functions/index.tsファイルを作成します。
  • プラグインをマウントし、特定のパスを超えるすべてのリクエストに応答させたい場合(例えば、/admin/login/admin/dashboard)、functions/[[path]].tsファイルを作成します。
  • プラグインがリクエストをインターセプトし、他のFunctionsやプロジェクトの静的アセットにフォールバックする場合、functions/_middleware.tsファイルを作成します。

必要に応じて、さまざまなファイルを使用することができます。プラグインの構造は、現在のPagesプロジェクトのFunctionsとまったく同じですが、ハンドラーは新しいプロパティpluginArgsを受け取ります。このプロパティは、開発者がプラグインをマウントする際に渡す初期化パラメータです。これを使用して、APIトークン、KV/Durable Objectの名前空間、またはプラグインが機能するために必要なその他の情報を受け取ることができます。

静的フォームの例に戻ると、リクエストをインターセプトし、HTMLフォームの動作をオーバーライドしたい場合は、functions/_middleware.tsを作成する必要があります。開発者は、単一のルートまたはプロジェクト全体にプラグインをマウントできます。

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) => {
// プロジェクトから元のレスポンスを最初に取得します
const response = await context.next()
// 次に、HTMLRewriterを使用して、`data-static-form-name`属性を持つ`form`要素を変換し、現在のページにPOSTするように指示します
return new HTMLRewriter().on('form[data-static-form-name]', new FormHandler()).transform(response)
}
export const onRequestPost = async (context) => {
// フォームを解析します
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'))
// 開発者によってプラグインに渡された引数を取得します
const { kv, respondWith } = context.pluginArgs
// フォームデータをKVに`form-name:YYYY-MM-DDTHH:MM:SSZ`のキーで保存します
const key = `${name}:${new Date().toISOString()}`
context.waitUntil(kv.put(name, JSON.stringify(entries)))
// 開発者が望むものを応答します
const response = await respondWith({ formData })
return response
}

2. ページプラグインの型を定義する

良い開発者体験を提供するために、プラグインにTypeScriptの型を追加することを検討してください。これにより、開発者はIDEのオートコンプリート機能を使用でき、期待されるすべてのパラメータを含めることが保証されます。

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

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

3. ページプラグインをテストする

私たちはまだページプラグインの著者のための素晴らしいテスト体験を作成する作業を進めています。すべての要素が揃うまでお待ちください。その間に、例のプロジェクトを作成し、手動でプラグインを含めてテストすることができます。

4. ページプラグインを公開する

プラグインを配布する方法は自由です。一般的なオプションには、npmでの公開、私たちのDeveloper Discordの#what-i-builtや#pages-discussionsチャンネルでの紹介、GitHubでのオープンソース化が含まれます。

生成されたdist/ディレクトリ、型定義index.d.ts、および開発者がプラグインを使用する方法に関する指示を含むREADME.mdを必ず含めてください。


5. ページプラグインをインストールする

アプリケーションにページプラグインを含めたい場合は、最初にそのプラグインをプロジェクトにインストールする必要があります。

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

6. ページプラグインをマウントする

プラグインのREADME.mdには、アプリケーションにプラグインをマウントする方法に関する指示が含まれている可能性があります。あなたは以下を行う必要があります:

  1. functionsディレクトリを作成します(まだない場合)。
  2. このプラグインを実行したい場所を決定し、functionsディレクトリに対応するファイルを作成します。
  3. プラグインをインポートし、このファイルでonRequestメソッドをエクスポートし、必要な引数でプラグインを初期化します。

静的フォームの例では、作成したプラグインはすでにミドルウェアとして作成されていました。これは、単一のルートまたはプロジェクト全体で実行できることを意味します。ウェブサイトの/contactに単一のコンタクトフォームがある場合、functions/contact.tsファイルを作成してそのルートだけをインターセプトできます。また、functions/_middleware.tsファイルを作成して、他のすべてのルートや将来作成する可能性のある他のフォームをインターセプトすることもできます。開発者として、プラグインが実行できる場所を選択できます。

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

import staticFormInterceptorPlugin from "@cloudflare/static-form-interceptor";
export const onRequest = (context) => {
return staticFormInterceptorPlugin({
kv: context.env.FORM_KV,
respondWith: async ({ formData }) => {
// ここでメール/通知サービスを呼び出すことができます
const name = formData.get("name");
return new Response(`ご提出ありがとうございます、${name}さん!`);
},
})(context);
};

7. ページプラグインをテストする

wrangler pages devを使用して、インストールしたプラグインを含むPagesプロジェクトをテストできます。プラグインが期待しているKVバインディングや環境変数を含めることを忘れないでください。

プラグインが/contactルートにマウントされている場合、対応するHTMLファイルは次のようになります:

<!DOCTYPE html>
<html>
<body>
<h1>お問い合わせ</h1>
<!-- 提出名を指定するために`data-static-form-name`属性を含めます -->
<form data-static-form-name="contact">
<label>
<span>名前</span>
<input type="text" autocomplete="name" name="name" />
</label>
<label>
<span>メッセージ</span>
<textarea name="message"></textarea>
</label>
</form>
</body>
</html>

あなたのプラグインは、data-static-form-name="contact"属性を取得し、method="POST"を設定し、<input type="hidden" name="static-form-name" value="contact" />要素を注入し、POST送信をキャプチャする必要があります。

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

新しいプラグインがpackage.jsonに追加され、すべてが期待通りにローカルで動作していることを確認してください。その後、git commitgit pushを行ってCloudflare Pagesのデプロイをトリガーします。

特定のプラグインに問題が発生した場合は、そのプラグインのバグトラッカーに問題を報告してください。

プラグイン全般に問題が発生した場合は、Discordの#pages-discussionsチャンネルでフィードバックをいただけると幸いです!プラグインを使用して何を構築するか楽しみにしており、著者や開発者体験についてのフィードバックを歓迎します。プラグインをさらに強力にするために必要なことがあれば、Discordチャンネルでお知らせください。


プラグインをチェーンする

最後に、一般的にPages Functionsと同様に、異なる機能を組み合わせるためにプラグインをチェーンすることが可能です。ファイルシステム内で上位に定義されたミドルウェアは、他のハンドラーの前に実行され、個々のファイルは次のように配列内で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 = [
// エラーをキャプチャするためにSentryプラグインを初期化します
sentryPlugin({ dsn: "https://sentry.io/welcome/xyz" }),
// この保護されたルートにアクセスできるのは管理者のみであることを確認するためにCloudflare Accessプラグインを初期化します
cloudflareAccessPlugin({
domain: "https://test.cloudflareaccess.com",
aud: "4714c1358e65fe4b408ad6d432a5f878f08194bdb4752441fd56faefa9b2b6f2",
}),
// 現在のユーザーに関する追加情報でSentryプラグインをポピュレートします
(context) => {
const email = context.data.cloudflareAccessJWT.payload?.email || "サービスユーザー";
context.data.sentry.setUser({ email });
return next();
},
// 最後に、エラーがキャプチャされ、すべての受信リクエストが認証されていることを確認しながら、管理ダッシュボードプラグインを提供します
adminDashboardPlugin(),
];