Fragments de page

Sur cette page

Le hook page:fragments permet à un plugin de contribuer du HTML brut, des scripts ou des feuilles de style aux pages publiques. C’est l’outil approprié pour les balises d’analyse, les widgets tiers, le CSS personnalisé et tout ce qui doit livrer du JavaScript ou du balisage directement dans le navigateur du visiteur.

Il est restreint aux plugins natifs car sa sortie s’exécute comme du code first-party dans le navigateur, en dehors de toute limite de sandbox. Si vous devez uniquement contribuer des métadonnées structurées — balises meta, OpenGraph, JSON-LD, <link> rels autorisés — utilisez plutôt page:metadata, qui est disponible pour les plugins sandboxés et natifs. Voir Hooks: page:metadata.

Capability

page:fragments nécessite la capability hooks.page-fragments:register:

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

La capability doit également apparaître sur le descripteur.

Où les fragments sont rendus

Les templates optent pour recevoir des fragments en incluant les composants pertinents de emdash/ui:

  • <EmDashHead /> — rend les fragments avec placement: "head" plus toutes les contributions page:metadata.
  • <EmDashBodyStart /> — rend les fragments avec placement: "body:start".
  • <EmDashBodyEnd /> — rend les fragments avec placement: "body:end".

Les templates qui omettent l’un de ces composants ignorent silencieusement les fragments ciblant ce placement — votre plugin ne casse pas, les fragments n’apparaissent simplement pas. Documentez votre exigence de placement dans le README du plugin.

Types de contribution

Un hook peut retourner l’un des trois types de contribution:

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 est "head" | "body:start" | "body:end".

Exemples

Script externe

Le hook suivant injecte un gestionnaire de balises tiers dans <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 en ligne

Le hook suivant exécute un petit morceau de JavaScript en haut de <body> sur les pages de contenu:

"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)};`,
	};
},

Fragment HTML

Le hook suivant ajoute un fallback noscript à la fin de <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>`,
	};
},

Plusieurs fragments

Un hook peut retourner un tableau pour contribuer plusieurs fragments à la fois. Le hook suivant ajoute à la fois un script et 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>`,
		},
	];
},

Événement de page

Le hook page:fragments reçoit la même forme d’événement que 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 };
	}
}

Utilisez event.page.kind et event.page.pageType pour décider si vous devez contribuer sur une page donnée — par exemple, ignorer les analyses sur les aperçus d’administration ou n’injecter du JSON-LD que sur les articles de blog.

Quand utiliser page:metadata à la place

Si ce dont vous avez réellement besoin est:

  • Une meta description, directive robots ou carte Twitter → page:metadata avec kind: "meta".
  • Une propriété OpenGraph → page:metadata avec kind: "property".
  • Un <link> canonique ou alternatif → page:metadata avec kind: "link".
  • Un graphe JSON-LD → page:metadata avec kind: "jsonld".

page:metadata fonctionne dans les plugins sandboxés, obtient la validation et la déduplication gratuitement, et évite le fardeau de confiance de livrer du HTML brut aux visiteurs. N’utilisez page:fragments que lorsque vous devez livrer du JavaScript ou du HTML.