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 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 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 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:metadata con kind: "meta".
  • Una proprietà OpenGraph → page:metadata con kind: "property".
  • Un <link> canonical o alternate → page:metadata con kind: "link".
  • Un grafo JSON-LD → page:metadata con kind: "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.