El hook page:fragments permite que un plugin contribuya HTML crudo, scripts u hojas de estilo a páginas públicas. Es la herramienta adecuada para etiquetas de análisis, widgets de terceros, CSS personalizado y cualquier otra cosa que necesite entregar JavaScript o marcado directamente en el navegador del visitante.
Está restringido a plugins nativos porque su salida se ejecuta como código de primera parte en el navegador, fuera de cualquier límite de sandbox. Si solo necesitas contribuir metadatos estructurados — etiquetas meta, OpenGraph, JSON-LD, rels <link> en la lista blanca — usa page:metadata en su lugar, que está disponible tanto para plugins en sandbox como nativos. Consulta Hooks: page:metadata.
Capacidad
page:fragments requiere la capacidad hooks.page-fragments:register:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
La capacidad también debe aparecer en el descriptor.
Dónde se renderizan los fragmentos
Las plantillas optan por recibir fragmentos incluyendo los componentes relevantes desde emdash/ui:
<EmDashHead />— renderiza fragmentos conplacement: "head"más todas las contribuciones depage:metadata.<EmDashBodyStart />— renderiza fragmentos conplacement: "body:start".<EmDashBodyEnd />— renderiza fragmentos conplacement: "body:end".
Las plantillas que omiten uno de estos componentes ignoran silenciosamente los fragmentos dirigidos a esa ubicación — tu plugin no se rompe, los fragmentos simplemente no aparecen. Documenta tus requisitos de ubicación en el README del plugin.
Tipos de contribuciones
Tres tipos de contribuciones:
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 es "head" | "body:start" | "body:end".
Ejemplos
Script externo
Inyectar un administrador de etiquetas de terceros:
"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 en línea
Ejecutar un pequeño fragmento de JavaScript en la parte superior 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
Agregar un respaldo noscript al 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últiples fragmentos
Devolver un array para contribuir múltiples fragmentos desde un ú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
El hook page:fragments recibe la misma 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 };
}
}
Usa event.page.kind y event.page.pageType para decidir si contribuir en una página dada — por ejemplo, omitir análisis en vistas previas de administrador o inyectar JSON-LD solo en publicaciones de blog.
Cuándo usar page:metadata en su lugar
Si lo que realmente necesitas es:
- Una meta descripción, directiva robots o tarjeta de Twitter →
page:metadataconkind: "meta". - Una propiedad OpenGraph →
page:metadataconkind: "property". - Un
<link>canonical o alternate →page:metadataconkind: "link". - Un grafo JSON-LD →
page:metadataconkind: "jsonld".
page:metadata funciona en plugins en sandbox, obtiene validación y deduplicación de forma gratuita, y evita la carga de confianza de entregar HTML crudo a los visitantes. Recurre a page:fragments solo cuando realmente necesites entregar JavaScript o HTML.