EmDash s’intègre profondément avec Astro pour fournir une expérience CMS complète. Cette page explique les décisions architecturales clés et comment les pièces s’assemblent.
Vue d’ensemble de haut niveau
┌──────────────────────────────────────────────────────────────────┐
│ Votre site Astro │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Intégration EmDash │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │ │
│ │ │ Contenu │ │ Admin │ │ Plugins │ │ │
│ │ │ APIs │ │ Panneau │ │ │ │ │
│ │ └──────────────┘ └──────────────┘ └───────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ Couche de données │ │ │
│ │ │ Base de données (D1/SQLite) + Stockage (R2/S3) │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Framework Astro │ │
│ │ Live Collections · Middleware · Sessions │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
EmDash fonctionne comme une intégration Astro. Il injecte des routes pour le panneau d’administration et les API REST, fournit un chargeur de contenu pour les Live Collections et gère les migrations de base de données et les connexions de stockage.
Schéma database-first
Contrairement aux CMS traditionnels qui définissent le schéma dans le code, EmDash stocke les définitions de schéma dans la base de données elle-même. Deux tables système suivent la structure de votre contenu :
_emdash_collections— Métadonnées de collection (slug, label, fonctionnalités)_emdash_fields— Définitions de champs pour chaque collection
Lorsque vous créez une collection “products” avec des champs title et price via l’interface d’administration, EmDash :
- Insère des enregistrements dans
_emdash_collectionset_emdash_fields - Exécute
ALTER TABLEpour créerec_productsavec les colonnes appropriées
Cette conception permet :
- Modification du schéma à l’exécution — Créer et éditer des types de contenu sans changements de code ni reconstructions
- Configuration conviviale pour les non-développeurs — Les éditeurs de contenu peuvent concevoir leur modèle de données via l’interface
- Vraies colonnes SQL — Indexation appropriée, clés étrangères et optimisation des requêtes
Tables par collection
Chaque collection obtient sa propre table SQLite avec un préfixe ec_ :
-- Créé lors de l'ajout de la collection "posts"
CREATE TABLE ec_posts (
-- Colonnes système (toujours présentes)
id TEXT PRIMARY KEY,
slug TEXT UNIQUE,
status TEXT DEFAULT 'draft', -- draft, published, scheduled
author_id TEXT,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')),
published_at TEXT,
deleted_at TEXT, -- Suppression douce
version INTEGER DEFAULT 1, -- Verrouillage optimiste
-- Colonnes de contenu (de vos définitions de champs)
title TEXT NOT NULL,
content JSON, -- Portable Text
excerpt TEXT
);
Pourquoi des tables par collection au lieu d’une seule table de contenu avec JSON ?
- Les vraies colonnes SQL permettent une indexation et des requêtes appropriées
- Les clés étrangères fonctionnent correctement
- Le schéma s’autodocumente dans la base de données
- Pas de surcharge d’analyse JSON pour l’accès aux champs
- Les outils de base de données peuvent inspecter le schéma directement
Intégration Live Collections
EmDash utilise les Live Collections d’Astro 6 pour servir le contenu à l’exécution. Les changements de contenu sont immédiatement disponibles sans reconstructions statiques.
emdashLoader() implémente l’interface LiveLoader d’Astro :
// src/live.config.ts
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({ loader: emdashLoader() }),
};
Interrogez le contenu en utilisant les fonctions wrapper fournies :
import { getEmDashCollection, getEmDashEntry } from "emdash";
// Obtenir tous les articles publiés
const { entries: posts } = await getEmDashCollection("posts");
// Obtenir les brouillons
const { entries: drafts } = await getEmDashCollection("posts", {
status: "draft",
});
// Obtenir une seule entrée par slug
const { entry: post } = await getEmDashEntry("posts", "my-post-slug");
Injection de routes
L’intégration EmDash utilise l’API injectRoute d’Astro pour ajouter des routes d’administration et d’API :
| Modèle de chemin | Objectif |
|---|---|
/_emdash/admin/[...path] | SPA du panneau d’administration |
/_emdash/api/manifest | Manifeste d’admin (collections, plugins) |
/_emdash/api/content/[collection] | CRUD pour les entrées de contenu |
/_emdash/api/media/* | Opérations de bibliothèque média |
/_emdash/api/schema/* | Gestion du schéma |
/_emdash/api/settings | Paramètres du site |
/_emdash/api/menus/* | Menus de navigation |
/_emdash/api/taxonomies/* | Catégories, tags, taxonomies personnalisées |
Les routes sont injectées depuis le package emdash — rien n’est copié dans votre projet.
Couche de données
EmDash utilise Kysely pour des requêtes SQL type-safe sur toutes les bases de données prises en charge :
SQLite
Développement local avec sqlite({ url: "file:./data.db" })
D1
SQL serverless de Cloudflare avec d1({ binding: "DB" })
libSQL
SQLite distant avec libsql({ url: "...", authToken: "..." })
La configuration de la base de données est passée à l’intégration dans astro.config.mjs :
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { sqlite } from "emdash/db";
import { local } from "emdash/storage";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
Abstraction du stockage
Les fichiers média sont stockés séparément de la base de données. EmDash prend en charge :
- Système de fichiers local — Développement et déploiements simples
- Cloudflare R2 — Stockage d’objets compatible S3 en périphérie
- Compatible S3 — Tout stockage d’objets compatible S3
Les téléchargements utilisent des URL signées pour des téléchargements directs client-vers-stockage, contournant les limites de taille de corps des Workers.
Architecture des plugins
Les plugins étendent EmDash via un système de hooks inspiré de WordPress :
- Hooks de contenu —
content:beforeSave,content:afterSave,content:beforeDelete,content:afterDelete - Hooks média —
media:beforeUpload,media:afterUpload - Stockage isolé — Chaque plugin obtient un accès KV avec espace de noms
- Extensions d’interface d’administration — Widgets de tableau de bord, pages de paramètres, éditeurs de champs personnalisés
Les plugins peuvent fonctionner en deux modes :
- Natif — Accès complet à l’environnement hôte (pour les plugins propriétaires)
- Sandboxé — Exécution dans des isolates V8 avec permissions basées sur les capacités (pour les plugins tiers sur Cloudflare)
// astro.config.mjs
import { seoPlugin } from "@emdash-cms/plugin-seo";
emdash({
plugins: [seoPlugin({ maxTitleLength: 60 })],
});
Flux de requête
Une requête de contenu typique suit ce chemin :
- Astro reçoit la requête — Votre composant de page s’exécute
- Interroger le contenu —
getEmDashCollection()appellegetLiveCollection()d’Astro - Le chargeur s’exécute —
emdashLoaderinterroge la tableec_*appropriée via Kysely - Données retournées — Les entrées sont mappées au format d’entrée d’Astro avec
id,slugetdata - La page se rend — Votre composant reçoit le contenu et rend le HTML
Pour les requêtes d’administration :
- Le middleware authentifie — Valide le jeton de session
- La route API gère la requête — Opérations CRUD via les dépôts
- Les hooks se déclenchent —
beforeCreate,afterUpdate, etc. - Mise à jour de la base de données — Kysely exécute SQL
- Réponse retournée — Réponse JSON au SPA d’administration
Modules virtuels
EmDash génère des modules virtuels au moment de la construction pour configurer le runtime :
| Module | Objectif |
|---|---|
virtual:emdash/config | Configuration de base de données et stockage |
virtual:emdash/dialect | Fabrique de dialecte de base de données |
virtual:emdash/plugin-admins | Imports statiques pour les interfaces d’administration des plugins |
Cette approche garantit que les bundlers peuvent correctement résoudre et tree-shake le code des plugins.
Prochaines étapes
Collections
Apprenez-en plus sur les collections de contenu et types de champs.
Modèle de contenu
Comprenez le modèle de contenu database-first.
Panneau d'administration
Explorez l’architecture du panneau d’administration.