Frammenti di pagina

In questa pagina

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 necessiti di fornire JavaScript o markup direttamente nel browser del visitatore.

È limitato ai plugin nativi perché il suo output viene eseguito come codice first-party nel browser, al di fuori di qualsiasi confine di sandbox. Se devi solo contribuire metadati strutturati — meta tag, OpenGraph, JSON-LD, <link> rels consentiti — usa invece page:metadata, che è disponibile sia per plugin sandboxed che nativi. Vedi Hooks: page:metadata.

Capability

page:fragments richiede la capability hooks.page-fragments:register:

return definePlugin({
	id: "analytics-gtm",
	version: "1.0.0",
	capabilities: ["hooks.page-fragments:register"],
	// ...
});

La capability deve anche apparire nel descriptor.

Dove vengono renderizzati i frammenti

I template optano per ricevere frammenti includendo i componenti pertinenti da emdash/ui:

  • <EmDashHead /> — renderizza frammenti con placement: "head" più tutti i contributi page:metadata.
  • <EmDashBodyStart /> — renderizza frammenti con placement: "body:start".
  • <EmDashBodyEnd /> — renderizza frammenti con placement: "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 il tuo requisito di posizionamento nel README del plugin.

Tipi di contributo

Un hook può restituire uno dei tre tipi di contributo:

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

Il seguente hook inietta un tag manager di terze parti in <head>:

"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

Il seguente hook esegue un piccolo frammento di JavaScript all’inizio di <body> sulle pagine di contenuto:

"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

Il seguente hook aggiunge 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

Un hook può restituire un array per contribuire più frammenti contemporaneamente. Il seguente hook aggiunge sia uno script che un fallback noscript:

"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, saltare analytics sulle anteprime admin o iniettare JSON-LD solo sui post del blog.

Quando usare invece page:metadata

Se ciò di cui hai effettivamente bisogno è:

  • Una meta description, direttiva robots o Twitter card → page:metadata con kind: "meta".
  • Una proprietà OpenGraph → page:metadata con kind: "property".
  • Un <link> canonico o alternativo → page:metadata con kind: "link".
  • Un grafo JSON-LD → page:metadata con kind: "jsonld".

page:metadata funziona nei plugin sandboxed, ottiene validazione e deduplicazione gratuitamente, ed evita l’onere di fiducia di fornire HTML grezzo ai visitatori. Ricorri a page:fragments solo quando devi fornire JavaScript o HTML.