page:fragments フックは、プラグインが生のHTML、スクリプト、またはスタイルシートを公開ページに提供できるようにします。これは、アナリティクスタグ、サードパーティウィジェット、カスタムCSS、およびJavaScriptやマークアップを訪問者のブラウザに直接配信する必要があるその他のものに適したツールです。
その出力はブラウザでファーストパーティコードとして実行され、サンドボックスの境界外で動作するため、ネイティブプラグインに制限されています。構造化されたメタデータ — メタタグ、OpenGraph、JSON-LD、許可された <link> rels — のみを提供する必要がある場合は、代わりに page:metadata を使用してください。これはサンドボックスプラグインとネイティブプラグインの両方で利用可能です。Hooks: page:metadata を参照してください。
Capability
page:fragments には hooks.page-fragments:register capability が必要です:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
この capability はディスクリプタにも記載する必要があります。
フラグメントがレンダリングされる場所
テンプレートは、emdash/ui から関連するコンポーネントを含めることでフラグメントを受け取ることを選択します:
<EmDashHead />—placement: "head"を持つフラグメントと、すべてのpage:metadataの寄与をレンダリングします。<EmDashBodyStart />—placement: "body:start"を持つフラグメントをレンダリングします。<EmDashBodyEnd />—placement: "body:end"を持つフラグメントをレンダリングします。
これらのコンポーネントのいずれかを省略したテンプレートは、その配置を対象とするフラグメントを静かに無視します — プラグインは壊れず、フラグメントが表示されないだけです。プラグインのREADMEに配置要件を文書化してください。
コントリビューションの種類
フックは3つのコントリビューションタイプのいずれかを返すことができます:
type PageFragmentContribution =
| {
kind: "external-script";
placement: PagePlacement;
src: string;
async?: boolean;
defer?: boolean;
attributes?: Record<string, string>;
key?: string;
}
| {
kind: "inline-script";
placement: PagePlacement;
code: string;
attributes?: Record<string, string>;
key?: string;
}
| {
kind: "html";
placement: PagePlacement;
html: string;
key?: string;
};
PagePlacement は "head" | "body:start" | "body:end" です。
例
外部スクリプト
次のフックは、サードパーティタグマネージャーを <head> に注入します:
"page:fragments": async (event, ctx) => {
const containerId = await ctx.kv.get<string>("settings:gtmContainerId");
if (!containerId) return null;
return {
kind: "external-script",
placement: "head",
src: `https://www.googletagmanager.com/gtm.js?id=${containerId}`,
async: true,
};
},
インラインスクリプト
次のフックは、コンテンツページの <body> の先頭で小さなJavaScriptコードを実行します:
"page:fragments": async (event, ctx) => {
if (event.page.kind !== "content") return null;
return {
kind: "inline-script",
placement: "body:start",
code: `window.contentId = ${JSON.stringify(event.page.content?.id)};`,
};
},
HTMLフラグメント
次のフックは、<body> の終わりにnoscriptフォールバックを追加します:
"page:fragments": async (event, ctx) => {
const containerId = await ctx.kv.get<string>("settings:gtmContainerId");
if (!containerId) return null;
return {
kind: "html",
placement: "body:end",
html: `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${containerId}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>`,
};
},
複数のフラグメント
フックは配列を返して、一度に複数のフラグメントを提供できます。次のフックは、スクリプトとnoscriptフォールバックの両方を追加します:
"page:fragments": async (event, ctx) => {
const id = await ctx.kv.get<string>("settings:gtmContainerId");
if (!id) return null;
return [
{
kind: "external-script",
placement: "head",
src: `https://www.googletagmanager.com/gtm.js?id=${id}`,
async: true,
},
{
kind: "html",
placement: "body:end",
html: `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${id}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>`,
},
];
},
ページイベント
page:fragments フックは、page:metadata と同じイベント形式を受け取ります:
{
page: {
url: string;
path: string;
locale: string | null;
kind: "content" | "custom";
pageType: string;
title: string | null;
pageTitle?: string | null;
description: string | null;
canonical: string | null;
image: string | null;
content?: { collection: string; id: string; slug: string | null };
}
}
event.page.kind と event.page.pageType を使用して、特定のページで寄与するかどうかを決定します — たとえば、管理者プレビューでアナリティクスをスキップしたり、ブログ投稿にのみJSON-LDを注入したりします。
いつ代わりに page:metadata を使用するか
実際に必要なのが次のものである場合:
- メタディスクリプション、robots指示、またはTwitterカード →
kind: "meta"を持つpage:metadata。 - OpenGraphプロパティ →
kind: "property"を持つpage:metadata。 - 正規またはalternateの
<link>→kind: "link"を持つpage:metadata。 - JSON-LDグラフ →
kind: "jsonld"を持つpage:metadata。
page:metadata はサンドボックスプラグインで動作し、無料で検証と重複排除を取得し、訪問者に生のHTMLを配信する信頼負担を回避します。JavaScriptまたはHTMLを配信する必要がある場合にのみ page:fragments に頼ってください。