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 fournir directement du JavaScript ou du balisage dans le navigateur du visiteur.

Il est réservé aux plugins natifs car sa sortie s’exécute en tant que code de première partie dans le navigateur, en dehors de toute limite de sandbox. Si vous avez seulement besoin de contribuer des métadonnées structurées — balises meta, OpenGraph, JSON-LD, rels <link> sur liste blanche — utilisez plutôt page:metadata, qui est disponible pour les plugins sandboxés et natifs. Voir Hooks: page:metadata.

Capacité

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

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

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

Où les fragments sont rendus

Les modèles choisissent de recevoir des fragments en incluant les composants pertinents depuis 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 modèles qui omettent l’un de ces composants ignorent silencieusement les fragments ciblant cet emplacement — votre plugin ne casse pas, les fragments n’apparaissent simplement pas. Documentez vos exigences de placement dans le README du plugin.

Types de contributions

Trois types de contributions :

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

Injecter un gestionnaire de balises tiers :

"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

Exécuter un petit morceau de JavaScript en haut de <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)};`,
	};
},

Fragment HTML

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

Fragments multiples

Retourner un tableau pour contribuer plusieurs fragments depuis un seul 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>`,
		},
	];
},

É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 de contribuer ou non sur une page donnée — par exemple, ignorer l’analyse sur les aperçus d’administration ou injecter JSON-LD uniquement sur les articles de blog.

Quand utiliser page:metadata à la place

Si ce dont vous avez réellement besoin est :

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

page:metadata fonctionne dans les plugins sandboxés, bénéficie de validation et de déduplication gratuites, et évite le fardeau de confiance lié à la fourniture de HTML brut aux visiteurs. N’utilisez page:fragments que lorsque vous devez réellement fournir du JavaScript ou du HTML.