Le système de plugins EmDash vous permet d’étendre le CMS sans modifier le code principal. Les plugins peuvent se brancher sur des événements de cycle de vie du contenu, stocker leurs propres données, exposer des paramètres aux administrateurs et ajouter une interface utilisateur personnalisée au panneau d’administration.
Philosophie de conception
Les plugins EmDash se déclinent en deux versions : sandboxés et natifs. Les plugins sandboxés s’exécutent dans des workers V8 isolés et peuvent être installés depuis le marché en un clic. Les plugins natifs s’exécutent en processus et sont configurés dans le code.
Préférez les plugins sandboxés. Ils peuvent être installés, mis à jour et supprimés depuis l’interface admin sans toucher au code ou redéployer. N’utilisez les plugins natifs que lorsque vous avez besoin de fonctionnalités nécessitant une intégration au moment du build (pages admin React, composants de rendu Portable Text ou injection de fragments de page).
Principes clés :
- Sandbox d’abord — Concevez pour le sandbox ; utilisez le mode natif uniquement si nécessaire
- Déclaratif — Les hooks, le stockage et les routes sont déclarés au moment de la définition, pas enregistrés dynamiquement
- Type-safe — Support complet de TypeScript avec des objets de contexte typés
- Basé sur les capacités — Les plugins déclarent ce dont ils ont besoin ; le sandbox l’applique
Ce que les plugins peuvent faire
Se brancher sur les événements
Exécuter du code avant ou après les sauvegardes de contenu, les téléchargements de médias et les événements du cycle de vie des plugins.
Stocker des données
Persister des données spécifiques au plugin dans des collections indexées sans écrire de migrations de base de données.
Exposer des paramètres
Déclarer un schéma de paramètres et obtenir une interface admin auto-générée pour la configuration.
Ajouter des pages admin
Créer des pages admin personnalisées et des widgets de tableau de bord avec des composants React.
Créer des routes API
Exposer des endpoints pour l’interface admin de votre plugin ou des intégrations externes.
Faire des requêtes HTTP
Appeler des API externes avec des restrictions d’hôtes déclarées pour la sécurité.
Architecture des plugins
Chaque plugin est créé avec definePlugin() :
import { definePlugin } from "emdash";
export default definePlugin({
id: "my-plugin",
version: "1.0.0",
// APIs dont le plugin a besoin
capabilities: ["read:content", "network:fetch"],
// Hôtes vers lesquels le plugin peut faire des requêtes HTTP
allowedHosts: ["api.example.com"],
// Collections de stockage persistant
storage: {
entries: {
indexes: ["userId", "createdAt"],
},
},
// Gestionnaires d'événements
hooks: {
"content:afterSave": async (event, ctx) => {
ctx.log.info("Content saved", { id: event.content.id });
},
},
// Endpoints REST API
routes: {
status: {
handler: async (ctx) => ({ ok: true }),
},
},
// Configuration de l'interface admin
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
},
pages: [{ path: "/dashboard", label: "Dashboard" }],
widgets: [{ id: "status", size: "half" }],
},
});
Contexte du plugin
Chaque hook et gestionnaire de route reçoit un objet PluginContext avec accès à :
| Propriété | Description | Disponibilité |
|---|---|---|
ctx.storage | Collections de documents du plugin | Toujours (si déclaré) |
ctx.kv | Stockage clé-valeur pour paramètres et état | Toujours |
ctx.content | Lecture/écriture du contenu du site | Avec read:content ou write:content |
ctx.media | Lecture/écriture des fichiers média | Avec read:media ou write:media |
ctx.http | Client HTTP pour requêtes externes | Avec network:fetch |
ctx.log | Logger structuré (debug, info, warn, error) | Toujours |
ctx.plugin | Métadonnées du plugin (id, version) | Toujours |
ctx.site | Infos du site : name, url, locale | Toujours |
ctx.url() | Générer des URL absolues depuis des chemins | Toujours |
ctx.users | Lire infos utilisateurs : get(), getByEmail(), list() | Avec read:users |
ctx.cron | Planifier tâches : schedule(), cancel(), list() | Toujours |
ctx.email | Envoyer email : send() | Avec email:send + fournisseur configuré |
La forme du contexte est identique pour tous les hooks et routes. Les propriétés protégées par capacité ne sont présentes que lorsque le plugin déclare la capacité requise.
Capacités
Les capacités déterminent quelles API sont disponibles dans le contexte du plugin :
| Capacité | Accorde l’accès à |
|---|---|
read:content | ctx.content.get(), ctx.content.list() |
write:content | ctx.content.create(), ctx.content.update(), ctx.content.delete() |
read:media | ctx.media.get(), ctx.media.list() |
write:media | ctx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete() |
network:fetch | ctx.http.fetch() (restreint à allowedHosts) |
network:fetch:any | ctx.http.fetch() (sans restriction — pour URLs configurées par utilisateur) |
read:users | ctx.users.get(), ctx.users.getByEmail(), ctx.users.list() |
email:send | ctx.email.send() (nécessite un plugin fournisseur) |
email:provide | Enregistrer hook exclusif email:deliver (fournisseur transport) |
email:intercept | Enregistrer hooks email:beforeSend / email:afterSend |
page:inject | Enregistrer hooks page:metadata / page:fragments |
Enregistrement
Enregistrez les plugins dans votre configuration Astro :
import { defineConfig } from "astro/config";
import { emdash } from "emdash/astro";
import seoPlugin from "@emdash-cms/plugin-seo";
import auditLogPlugin from "@emdash-cms/plugin-audit-log";
export default defineConfig({
integrations: [
emdash({
plugins: [seoPlugin({ generateSitemap: true }), auditLogPlugin({ retentionDays: 90 })],
}),
],
});
Les plugins sont résolus au moment du build. L’ordre compte pour les hooks avec la même priorité — les plugins plus tôt dans le tableau s’exécutent en premier.
Modes d’exécution
EmDash prend en charge deux modes d’exécution de plugins :
| Mode | Description | Plateforme |
|---|---|---|
| Sandboxé | Workers V8 isolés avec limites forcées | Cloudflare uniquement |
| Natif | En processus avec accès complet | Tous |
En mode sandboxé, les capacités sont appliquées au niveau du runtime — les plugins ne peuvent accéder qu’à ce qu’ils déclarent. En mode natif, les capacités sont consultatives et les plugins ont un accès complet au processus.
Prochaines étapes
Créer un plugin
Construisez votre premier plugin avec stockage, hooks et interface admin.
Hooks disponibles
Parcourez tous les hooks pour le contenu, les médias et le cycle de vie des plugins.
Stockage de plugin
Découvrez le stockage et comment interroger les données des plugins.
Interface admin
Ajoutez des pages admin et des widgets de tableau de bord.
Natif vs. Sandboxé
Comparez les modes d’exécution et choisissez le bon pour votre plugin.