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 análise, widgets de terceiros, CSS personalizado e qualquer outra coisa que precise entregar JavaScript ou marcação diretamente no navegador do visitante.
É restrito a plugins nativos porque sua saída é executada como código de primeira parte no navegador, fora de qualquer limite de sandbox. Se você só precisa contribuir com metadados estruturados — tags meta, OpenGraph, JSON-LD, rels <link> na lista de permissões — use page:metadata em vez disso, que está disponível tanto para plugins em sandbox quanto nativos. Veja Hooks: page:metadata.
Capacidade
page:fragments requer a capacidade hooks.page-fragments:register:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
A capacidade também deve aparecer no descritor.
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 posicionamento — seu plugin não quebra, os fragmentos simplesmente não aparecem. Documente seus requisitos de posicionamento no README do plugin.
Tipos de contribuições
Três tipos de contribuições:
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
Injetar um gerenciador de tags de terceiros:
"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
Executar um pequeno pedaço de JavaScript no topo de <body>:
"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
Adicionar um fallback noscript no final de <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
Retornar um array para contribuir com múltiplos fragmentos de um único hook:
"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, pulando análise em visualizações de administrador ou injetando JSON-LD apenas em posts de blog.
Quando usar page:metadata em vez disso
Se o que você realmente precisa é:
- Uma meta descrição, diretiva robots ou cartão do Twitter →
page:metadatacomkind: "meta". - Uma propriedade OpenGraph →
page:metadatacomkind: "property". - Um
<link>canonical ou alternate →page:metadatacomkind: "link". - Um grafo JSON-LD →
page:metadatacomkind: "jsonld".
page:metadata funciona em plugins em sandbox, 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 você realmente precisar entregar JavaScript ou HTML.