El hook page:fragments aporta scripts o HTML en bruto al head o al body de una página pública renderizada. Úsalo para código del navegador que los metadatos estructurados no pueden expresar, como un cargador de analítica con un respaldo <noscript>.
La salida de los fragmentos se ejecuta como código de primera parte de la página. EmDash invoca este hook solo para plugins de confianza en proceso; los plugins en sandbox nunca aportan fragmentos. Si la página necesita meta tags, enlaces canónicos o alternate, o JSON-LD, usa en su lugar el hook page:metadata compatible con sandbox.
Declarar la capacidad y el hook
page:fragments requiere hooks.page-fragments:register en la definición del runtime nativo. El siguiente hook añade un script externo y un respaldo HTML solo cuando existe un ID de analítica configurado:
return definePlugin({
id: "plugin-analytics",
version: "0.1.0",
capabilities: ["hooks.page-fragments:register"],
hooks: {
"page:fragments": async (event, ctx) => {
const analyticsId = await ctx.settings.get<string>("analyticsId");
if (!analyticsId || event.page.path.startsWith("/_emdash/")) return null;
const encodedId = encodeURIComponent(analyticsId);
return [
{
kind: "external-script",
placement: "head",
src: `https://analytics.example.com/client.js?id=${encodedId}`,
async: true,
key: "analytics-client",
},
{
kind: "html",
placement: "body:end",
html: "<noscript>Analytics requires JavaScript.</noscript>",
key: "analytics-fallback",
},
];
},
},
});
Las aportaciones de HTML en bruto se insertan tal cual. Mantén el fragmento estático cuando sea posible; de lo contrario, escapa todo valor que pueda proceder de ajustes, contenido, datos de la solicitud o un servicio externo.
Para plugins nativos, declara la capacidad en definePlugin(). El descriptor no necesita una segunda copia porque createPlugin() suministra la lista de capacidades del runtime.
Si falta la capacidad, EmDash registra una advertencia y no registra el hook. Los errores del hook se registran y no impiden que la página se renderice.
Añadir los puntos de inserción del diseño
El tema anfitrión elige qué placements admite. Debe pasar el mismo PublicPageContext a los componentes EmDash correspondientes:
-
Construye el contexto de la página una vez en el diseño.
--- import { createPublicPageContext } from "emdash/page"; import { EmDashBodyEnd, EmDashBodyStart, EmDashHead, } from "emdash/ui"; interface Props { title: string; description?: string; content?: { collection: string; id: string; slug?: string | null }; } const { title, description, content } = Astro.props; const page = createPublicPageContext({ Astro, kind: content ? "content" : "custom", pageType: content ? "article" : "website", title, description, content, }); --- -
Renderiza cada placement admitido en la parte correspondiente del documento.
<html lang="en"> <head> <title>{title}</title> <EmDashHead page={page} /> </head> <body> <EmDashBodyStart page={page} /> <slot /> <EmDashBodyEnd page={page} /> </body> </html>
EmDashHead renderiza fragmentos head así como metadatos de EmDash y de plugins. EmDashBodyStart renderiza fragmentos body:start justo después del <body> de apertura, y EmDashBodyEnd renderiza fragmentos body:end después del contenido de la página. Un tema que omite un componente no renderiza fragmentos para ese placement. Documenta cualquier punto de inserción requerido en el README del plugin.
Referencia de aportaciones
Un hook puede devolver una aportación, una matriz o null. Las formas de aportación admitidas son:
kind | Campos obligatorios | Campos opcionales | Comportamiento de salida |
|---|---|---|---|
external-script | placement, src | async, defer, attributes, key | Renderiza un elemento <script src="…">. |
inline-script | placement, code | attributes, key | Renderiza code dentro de un elemento <script>. |
html | placement, html | key | Inserta html sin sanitizarlo. |
placement acepta head, body:start o body:end.
EmDash escapa en HTML los nombres y valores de atributos y elimina los atributos cuyos nombres empiezan por on. En los scripts en línea, escapa </ para que un valor no pueda cerrar el elemento script. Estas comprobaciones del renderizador no hacen seguro el HTML o JavaScript no fiables; el plugin debe seguir codificando los datos interpolados para el lenguaje y el contexto donde se insertan.
El siguiente hook coloca de forma segura un valor JSON en un script en línea:
"page:fragments": async (event) => {
if (event.page.kind !== "content" || !event.page.content) return null;
return {
kind: "inline-script",
placement: "body:start",
code: `window.currentContent = ${JSON.stringify({
collection: event.page.content.collection,
id: event.page.content.id,
})};`,
key: "current-content",
};
},
Dentro de un placement, las aportaciones con la misma key conservan el primer valor. Los scripts externos sin clave también se deduplican por src. Usa una clave estable cuando dos hooks puedan describir el mismo fragmento lógico.
Referencia del contexto de página
El hook recibe { page }. El objeto page proviene del diseño anfitrión, con valores opcionales del panel SEO superpuestos para una entrada de contenido cargada durante la solicitud.
| Campo | Tipo y significado |
|---|---|
url | URL absoluta de la página. |
path | Nombre de ruta de la URL. |
locale | Locale activo, o null. |
kind | content para una entrada EmDash o custom para otra página. |
pageType | Tipo definido por el tema, habitualmente article o website. |
title, pageTitle | Título completo del documento y título opcional solo de página. |
description, canonical, image | Valores de metadatos de la página, cada uno nullable. |
content | Referencia opcional { collection, id, slug } de la entrada renderizada. |
seo | Anulaciones opcionales de título, descripción, imagen y robots de Open Graph. |
articleMeta | Tiempo de publicación, tiempo de modificación y autor opcionales. |
siteName, siteUrl | Identidad pública opcional del sitio y origen. |
breadcrumbs | Elementos opcionales root-first { name, url }. Una matriz vacía significa explícitamente que no hay breadcrumbs. |
Usa kind, pageType, path, locale o content para limitar dónde aparece un fragmento. No vuelvas a obtener una entrada cuando el contexto de la página ya lleva la identidad necesaria para la decisión.
Preferir metadatos estructurados cuando sea posible
Usa page:metadata para la siguiente salida:
- etiquetas
<meta name="…">y<meta property="…"> - enlaces canonical, alternate, author, license,
nlwebysite.standard.document - grafos JSON-LD
page:metadata valida sus aportaciones estructuradas, las deduplica con los metadatos base de la página y funciona en plugins nativos y en sandbox. Usa page:fragments cuando el navegador deba recibir código ejecutable o marcado que el hook estructurado no pueda representar.