O hook page:fragments permite que um plugin contribua com HTML bruto, scripts ou folhas de estilo para páginas públicas. É a ferramenta certa para tags de analytics, widgets de terceiros, CSS personalizado e qualquer outra coisa que precise entregar JavaScript ou markup diretamente no navegador do visitante.
É restrito a plugins nativos porque sua saída é executada como código first-party no navegador, fora de qualquer limite de sandbox. Se você só precisa contribuir com metadados estruturados — meta tags, OpenGraph, JSON-LD, <link> rels permitidos — use page:metadata em vez disso, que está disponível tanto para plugins sandboxed quanto nativos. Veja Hooks: page:metadata.
Capability
page:fragments requer a capability hooks.page-fragments:register:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
A capability também deve aparecer no descriptor.
Onde os fragmentos são renderizados
Os templates optam por receber fragmentos incluindo os componentes relevantes de emdash/ui:
<EmDashHead />— renderiza fragmentos complacement: "head"mais todas as contribuições depage:metadata.<EmDashBodyStart />— renderiza fragmentos complacement: "body:start".<EmDashBodyEnd />— renderiza fragmentos complacement: "body:end".
Templates que omitem um desses componentes ignoram silenciosamente fragmentos direcionados a esse placement — seu plugin não quebra, os fragmentos simplesmente não aparecem. Documente seu requisito de placement no README do plugin.
Tipos de contribuição
Um hook pode retornar um dos três tipos de contribuição:
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".
Exemplos
Script externo
O seguinte hook injeta um gerenciador de tags de terceiros em <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,
};
},
Script inline
O seguinte hook executa um pequeno trecho de JavaScript no topo do <body> em páginas de conteúdo:
"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)};`,
};
},
Fragmento HTML
O seguinte hook adiciona um fallback noscript no final do <body>:
"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>`,
};
},
Múltiplos fragmentos
Um hook pode retornar um array para contribuir com múltiplos fragmentos de uma vez. O seguinte hook adiciona tanto um script quanto um fallback 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>`,
},
];
},
Evento de página
O hook page:fragments recebe a mesma forma de evento que 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 };
}
}
Use event.page.kind e event.page.pageType para decidir se deve contribuir em uma determinada página — por exemplo, pular analytics em prévias de admin ou injetar JSON-LD apenas em posts de blog.
Quando usar page:metadata em vez disso
Se o que você realmente precisa é:
- Uma meta description, diretiva robots ou Twitter card →
page:metadatacomkind: "meta". - Uma propriedade OpenGraph →
page:metadatacomkind: "property". - Um
<link>canônico ou alternativo →page:metadatacomkind: "link". - Um grafo JSON-LD →
page:metadatacomkind: "jsonld".
page:metadata funciona em plugins sandboxed, obtém validação e deduplicação de graça, e evita o ônus de confiança de entregar HTML bruto aos visitantes. Recorra a page:fragments apenas quando precisar entregar JavaScript ou HTML.