Les plugins EmDash utilisent l’un des deux formats : sandboxed ou native. Choisissez le format avant d’écrire le plugin car la forme d’écriture, le chemin d’installation et la frontière de confiance diffèrent.
Choisissez un plugin sandboxed sauf si le plugin a besoin d’une intégration uniquement native. Les plugins sandboxed peuvent être publiés dans le registre et installés depuis l’UI d’administration. Un plugin natif est un paquet npm qu’un opérateur de site installe dans le projet et ajoute à astro.config.mjs avant de redéployer.
En un coup d’œil
| Sandboxed | Native | |
|---|---|---|
| Authoring shape | emdash-plugin.jsonc + src/plugin.ts | definePlugin() descriptor |
| Install method | One-click from the admin registry | npm install + edit astro.config |
| Runs in | An isolated runtime provided by a sandbox runner | Same process as your Astro site |
Capability-gated ctx APIs | Enforced by the sandbox bridge | Gated by PluginContext, but not a security boundary |
| Resource limits | Runner limits for CPU, subrequests, and wall time; platform memory ceiling | No per-plugin limits |
| Network access | ctx.http, restricted to declared access | ctx.http follows declarations; native code can also call fetch() |
Direct fetch() / process.env | Blocked by the runner | Possible (plugin code shares the runtime) |
| Distribution | Signed release in the plugin registry | npm package |
| Admin UI | Block Kit (JSON-described) routes | React components, or Block Kit |
| Settings UI | Block Kit page + ctx.settings | admin.settingsSchema (auto-form) or Block Kit |
| Portable Text rendering components | Not available | componentsEntry provides Astro components |
| Page metadata contributions | page:metadata hook — meta/property tags, allowlisted <link> rels, JSON-LD | page:metadata hook (same surface) |
| Page fragment injection | Not available — meta/JSON-LD only via page:metadata | page:fragments hook — inline scripts, external scripts, raw HTML |
| Constructor options | None — read settings from KV at runtime | options on the descriptor |
Coûts d’un plugin natif
Les plugins natifs ont un modèle d’installation et de confiance différent :
- Installation au niveau du projet. Chaque site doit installer votre paquet npm, modifier
astro.config.mjset redéployer. - Pas d’isolation. Un bug dans votre plugin peut faire planter le processus hôte ou consommer son budget CPU. Un rejet non géré dans un hook peut emporter la requête environnante.
- Charge de confiance sur l’utilisateur. Les plugins natifs ont le même accès que le site hôte. Les déclarations de capability seules ne peuvent pas montrer tout ce que leur code peut faire.
Si votre plugin peut faire son travail dans le sandbox, il devrait le faire.
Quand passer au natif
Choisissez natif pour les fonctionnalités qui nécessitent une intégration au moment du build avec le site hôte :
-
Pages ou widgets d’administration React personnalisés. Les plugins sandboxed décrivent leur UI d’administration avec Block Kit — un schéma JSON que l’admin rend pour le compte du plugin. Si vous avez besoin de React complet (hooks personnalisés, composants tiers, état complexe), vous avez besoin du natif.
-
Types de blocs Portable Text personnalisés. Leur configuration d’édition et leurs composants de rendu Astro sont chargés depuis le paquet npm installé. Seuls les plugins natifs peuvent fournir cette surface au moment du build.
-
Injecter du HTML brut, des scripts ou des feuilles de style dans les pages publiques. Le hook
page:fragmentsenvoie du code de première partie aux navigateurs des visiteurs — hors de toute frontière de sandbox. Il est réservé aux plugins natifs. Les plugins sandboxed peuvent toujours contribuer aux pages publiques via le hookpage:metadata, qui couvre de nombreux cas d’usage réels :- balises
meta(name+content) — descriptions SEO, directives robots, Twitter cards - balises
property— OpenGraph et autre meta basé sur property - balises
linkavec une allowlist de rel verrouillée pour la sécurité (canonical,alternate,author,license,nlweb,site.standard.document) —stylesheet,prefetchet rels similaires de chargement de ressources sont volontairement exclus - graphes JSON-LD
Si votre besoin d’« injection de page » est des données structurées ou des métadonnées SEO, restez sandboxed et utilisez
page:metadata. Si vous devez réellement envoyer du JavaScript ou du HTML dans le navigateur du visiteur, c’est le cas pour passer au natif. - balises
Si aucune de ces fonctionnalités ne s’applique, utilisez le format sandboxed.
Runners de sandbox et prise en charge des plateformes
Le sandbox lui-même est enfichable. EmDash expose une option de configuration sandboxRunner et le runner décide comment le code du plugin est isolé — il n’y a rien de spécifique à Cloudflare dans le format du plugin lui-même.
Deux runners sont livrés avec EmDash : sandbox() de @emdash-cms/cloudflare, qui exécute chaque plugin comme Dynamic Worker via le Worker Loader de Cloudflare, et @emdash-cms/sandbox-workerd/sandbox, qui exécute les plugins dans un processus enfant workerd sous Node.js. Plugin Sandbox couvre la configuration de chaque runner, les limites de ressources qu’il applique et les différences entre les deux.
Si aucun runner n’est configuré, les plugins listés sous sandboxed: [] ne sont pas chargés. Si le runner configuré est indisponible sur la plateforme actuelle, ils ne sont pas chargés non plus, et EmDash journalise un avertissement au démarrage.
Si vous voulez qu’un plugin sandboxed s’exécute sur une plateforme sans runner de sandbox, déplacez-le de sandboxed: [] vers le tableau plugins: [] — il s’exécutera in-process. Les déclarations de capability sont toujours honorées (la même factory PluginContext contrôle ctx.content, ctx.http et consorts), mais il n’y a pas de frontière d’isolation, pas de limites de ressources, et un plugin bogué ou malveillant peut appeler fetch() directement, lire des variables d’environnement ou bloquer la boucle d’événements. Sans runner de sandbox actif, traitez chaque plugin comme un plugin natif à des fins de confiance.