O hook page:fragments fornece scripts ou HTML bruto ao head ou body de uma página pública renderizada. Use-o para código de navegador que metadados estruturados não conseguem expressar, como um carregador de analytics com um fallback <noscript>.
A saída dos fragmentos é executada como código de primeira parte da página. EmDash chama este hook apenas para plugins confiáveis in-process; plugins sandboxed nunca contribuem com fragmentos. Se a página precisar de meta tags, links canonical ou alternate, ou JSON-LD, use em vez disso o hook page:metadata compatível com sandbox.
Declarar a capability e o hook
page:fragments requer hooks.page-fragments:register na definição do runtime nativo. O hook a seguir adiciona um script externo e um fallback HTML somente quando existe um ID de analytics 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",
},
];
},
},
});
Contribuições de HTML bruto são inseridas verbatim. Mantenha o fragmento estático quando possível; caso contrário, faça escape de qualquer valor que possa vir de configurações, conteúdo, dados da requisição ou um serviço externo.
Para plugins nativos, declare a capability em definePlugin(). O descriptor não precisa de uma segunda cópia porque createPlugin() fornece a lista de capabilities do runtime.
Se a capability estiver ausente, EmDash registra um aviso e não registra o hook. Erros do hook são registrados e não impedem a renderização da página.
Adicionar os pontos de inserção do layout
O tema host escolhe quais placements oferece suporte. Ele deve passar o mesmo PublicPageContext aos componentes EmDash correspondentes:
-
Construa o contexto da página uma vez no layout.
--- 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, }); --- -
Renderize cada placement suportado na parte correspondente do 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 bem como metadados EmDash e de plugins. EmDashBodyStart renderiza fragmentos body:start logo após o <body> de abertura, e EmDashBodyEnd renderiza fragmentos body:end após o conteúdo da página. Um tema que omite um componente não renderiza fragmentos para aquele placement. Documente quaisquer pontos de inserção necessários no README do plugin.
Referência de contribuições
Um hook pode retornar uma contribuição, um array ou null. As formas de contribuição suportadas são:
kind | Campos obrigatórios | Campos opcionais | Comportamento da saída |
|---|---|---|---|
external-script | placement, src | async, defer, attributes, key | Renderiza um elemento <script src="…">. |
inline-script | placement, code | attributes, key | Renderiza code dentro de um elemento <script>. |
html | placement, html | key | Insere html sem sanitizá-lo. |
placement aceita head, body:start ou body:end.
EmDash faz escape HTML dos nomes e valores de atributos e remove atributos cujos nomes começam com on. Para scripts inline, faz escape de </ para que um valor não possa fechar o elemento script. Essas verificações do renderer não tornam HTML ou JavaScript não confiáveis seguros; o plugin ainda deve codificar dados interpolados para a linguagem e o contexto em que são inseridos.
O hook a seguir coloca com segurança um valor JSON em um script inline:
"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 um placement, contribuições com a mesma key mantêm o primeiro valor. Scripts externos sem chave também são deduplicados por src. Use uma chave estável quando dois hooks puderem descrever o mesmo fragmento lógico.
Referência do contexto de página
O hook recebe { page }. O objeto page vem do layout host, com valores opcionais do painel SEO sobrepostos para uma entrada de conteúdo carregada durante a requisição.
| Campo | Tipo e significado |
|---|---|
url | URL absoluto da página. |
path | Pathname da URL. |
locale | Locale ativo, ou null. |
kind | content para uma entrada EmDash ou custom para outra página. |
pageType | Tipo definido pelo tema, geralmente article ou website. |
title, pageTitle | Título completo do documento e título opcional só da página. |
description, canonical, image | Valores de metadados da página, cada um nullable. |
content | Referência opcional { collection, id, slug } da entrada renderizada. |
seo | Substituições opcionais de título, descrição, imagem e robots Open Graph. |
articleMeta | Hora de publicação, hora de modificação e autor opcionais. |
siteName, siteUrl | Identidade pública opcional do site e origin. |
breadcrumbs | Itens opcionais root-first { name, url }. Um array vazio significa explicitamente nenhum breadcrumb. |
Use kind, pageType, path, locale ou content para limitar onde um fragmento aparece. Não busque novamente uma entrada quando o contexto da página já carrega a identidade necessária para a decisão.
Preferir metadados estruturados quando possível
Use page:metadata para a seguinte saída:
- tags
<meta name="…">e<meta property="…"> - links canonical, alternate, author, license,
nlwebesite.standard.document - grafos JSON-LD
page:metadata valida suas contribuições estruturadas, as deduplica com os metadados base da página e funciona em plugins nativos e sandboxed. Use page:fragments quando o navegador precisar receber código executável ou markup que o hook estruturado não consegue representar.