page:fragments 훅을 사용하면 플러그인이 공개 페이지에 원시 HTML, 스크립트 또는 스타일시트를 제공할 수 있습니다. 이는 분석 태그, 서드파티 위젯, 커스텀 CSS 및 JavaScript 또는 마크업을 방문자의 브라우저에 직접 전달해야 하는 모든 것을 위한 올바른 도구입니다.
출력이 브라우저에서 퍼스트파티 코드로 실행되고 샌드박스 경계 밖에 있기 때문에 네이티브 플러그인으로 제한됩니다. 구조화된 메타데이터(meta 태그, OpenGraph, JSON-LD, 허용 목록의 <link> rels)만 제공하면 되는 경우 샌드박스 및 네이티브 플러그인 모두에서 사용할 수 있는 page:metadata를 대신 사용하세요. Hooks: page:metadata를 참조하세요.
기능
page:fragments에는 hooks.page-fragments:register 기능이 필요합니다:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
이 기능은 디스크립터에도 나타나야 합니다.
프래그먼트 렌더링 위치
템플릿은 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"입니다.
예제
외부 스크립트
서드파티 태그 관리자 삽입:
"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>`,
};
},
여러 프래그먼트
단일 훅에서 배열을 반환하여 여러 프래그먼트 제공:
"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를 사용합니다. - canonical 또는 alternate
<link>→kind: "link"와 함께page:metadata를 사용합니다. - JSON-LD 그래프 →
kind: "jsonld"와 함께page:metadata를 사용합니다.
page:metadata는 샌드박스 플러그인에서 작동하며 검증 및 중복 제거를 무료로 제공하고 방문자에게 원시 HTML을 전달하는 신뢰 부담을 피할 수 있습니다. JavaScript 또는 HTML을 실제로 전달해야 하는 경우에만 page:fragments를 사용하세요.