Vue d'ensemble du système de plugins

Sur cette page

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éDescriptionDisponibilité
ctx.storageCollections de documents du pluginToujours (si déclaré)
ctx.kvStockage clé-valeur pour paramètres et étatToujours
ctx.contentLecture/écriture du contenu du siteAvec read:content ou write:content
ctx.mediaLecture/écriture des fichiers médiaAvec read:media ou write:media
ctx.httpClient HTTP pour requêtes externesAvec network:fetch
ctx.logLogger structuré (debug, info, warn, error)Toujours
ctx.pluginMétadonnées du plugin (id, version)Toujours
ctx.siteInfos du site : name, url, localeToujours
ctx.url()Générer des URL absolues depuis des cheminsToujours
ctx.usersLire infos utilisateurs : get(), getByEmail(), list()Avec read:users
ctx.cronPlanifier tâches : schedule(), cancel(), list()Toujours
ctx.emailEnvoyer 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:contentctx.content.get(), ctx.content.list()
write:contentctx.content.create(), ctx.content.update(), ctx.content.delete()
read:mediactx.media.get(), ctx.media.list()
write:mediactx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete()
network:fetchctx.http.fetch() (restreint à allowedHosts)
network:fetch:anyctx.http.fetch() (sans restriction — pour URLs configurées par utilisateur)
read:usersctx.users.get(), ctx.users.getByEmail(), ctx.users.list()
email:sendctx.email.send() (nécessite un plugin fournisseur)
email:provideEnregistrer hook exclusif email:deliver (fournisseur transport)
email:interceptEnregistrer hooks email:beforeSend / email:afterSend
page:injectEnregistrer 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 :

ModeDescriptionPlateforme
SandboxéWorkers V8 isolés avec limites forcéesCloudflare uniquement
NatifEn processus avec accès completTous

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