L’hook page:fragments consente a un plugin di contribuire HTML grezzo, script o fogli di stile alle pagine pubbliche. È lo strumento giusto per tag di analytics, widget di terze parti, CSS personalizzato e qualsiasi altra cosa che debba fornire JavaScript o markup direttamente nel browser del visitatore.
È limitato ai plugin nativi perché il suo output viene eseguito come codice di prima parte nel browser, al di fuori di qualsiasi confine sandbox. Se hai bisogno solo di contribuire metadati strutturati — tag meta, OpenGraph, JSON-LD, rel <link> nella whitelist — usa invece page:metadata, che è disponibile sia per i plugin sandboxed che nativi. Vedi Hooks: page:metadata.
Capacità
page:fragments richiede la capacità hooks.page-fragments:register:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
La capacità deve apparire anche nel descrittore.
Dove vengono renderizzati i frammenti
I template optano per ricevere frammenti includendo i componenti rilevanti da emdash/ui:
<EmDashHead />— renderizza frammenti conplacement: "head"più tutti i contributipage:metadata.<EmDashBodyStart />— renderizza frammenti conplacement: "body:start".<EmDashBodyEnd />— renderizza frammenti conplacement: "body:end".
I template che omettono uno di questi componenti ignorano silenziosamente i frammenti destinati a quel posizionamento — il tuo plugin non si rompe, i frammenti semplicemente non appaiono. Documenta i requisiti di posizionamento nel README del plugin.
Tipi di contributi
Tre tipi di contributi:
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".
Esempi
Script esterno
Iniettare un tag manager di terze parti:
"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
Eseguire un piccolo pezzo di JavaScript in cima a <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)};`,
};
},
Frammento HTML
Aggiungere un fallback noscript alla fine di <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>`,
};
},
Frammenti multipli
Restituire un array per contribuire più frammenti da un singolo 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 di pagina
L’hook page:fragments riceve la stessa forma di evento di 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 e event.page.pageType per decidere se contribuire su una data pagina — ad esempio, saltando l’analytics sulle anteprime admin o iniettando JSON-LD solo sui post del blog.
Quando usare invece page:metadata
Se ciò di cui hai effettivamente bisogno è:
- Una meta descrizione, direttiva robots o scheda Twitter →
page:metadataconkind: "meta". - Una proprietà OpenGraph →
page:metadataconkind: "property". - Un
<link>canonical o alternate →page:metadataconkind: "link". - Un grafo JSON-LD →
page:metadataconkind: "jsonld".
page:metadata funziona nei plugin sandboxed, ottiene validazione e deduplicazione gratuite e evita l’onere di fiducia di fornire HTML grezzo ai visitatori. Usa page:fragments solo quando hai effettivamente bisogno di fornire JavaScript o HTML.