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 avecplacement: "head"plus toutes les contributionspage:metadata.<EmDashBodyStart />— rend les fragments avecplacement: "body:start".<EmDashBodyEnd />— rend les fragments avecplacement: "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:metadataaveckind: "meta". - Une propriété OpenGraph →
page:metadataaveckind: "property". - Un
<link>canonical ou alternate →page:metadataaveckind: "link". - Un graphe JSON-LD →
page:metadataaveckind: "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.