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에 배치 요구 사항을 문서화하십시오.
기여 유형
훅은 세 가지 기여 유형 중 하나를 반환할 수 있습니다:
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. - 정규 또는 대체
<link>→kind: "link"가 있는page:metadata. - JSON-LD 그래프 →
kind: "jsonld"가 있는page:metadata.
page:metadata는 샌드박스 플러그인에서 작동하고 무료로 유효성 검사 및 중복 제거를 받으며 방문자에게 원시 HTML을 전달하는 신뢰 부담을 피합니다. JavaScript 또는 HTML을 전달해야 할 때만 page:fragments에 의존하십시오.