Bref. J'ai geeké.
Architecture
Ce blog est simple en apparence. Mais sous le capot, il repose sur une architecture que j’ai voulue à la fois légère, économique et extensible. Voici les choix qui l’ont façonnée.
Un monorepo pnpm (workspaces)
Le projet est organisé en monorepo avec deux packages distincts :
apps/blog: le site Astro, compilé en HTML/CSS/JS statiqueapps/api: un Cloudflare Worker TypeScript qui expose les endpoints dynamiques
Cette séparation n’est pas cosmétique. Elle reflète une réalité technique : le blog n’a pas besoin de serveur. Chaque page est générée à la compilation. Seule la recherche sémantique nécessite un runtime et c’est précisément le rôle du Worker.
Cloudflare Workers Assets
Le modèle de déploiement repose sur les Cloudflare Workers Assets. Un Worker unique fait deux choses :
- Il sert les fichiers statiques générés par Astro (via le binding
ASSETS) - Il route
/api/*vers les handlers TypeScript de l’API
wrangler.jsonc (root)
├── main: apps/api/src/index.ts ← le Worker
└── assets: apps/blog/dist/ ← le site statique
C’est fondamentalement différent de Cloudflare Pages : ici, le Worker contrôle tout. Il n’y a pas de plateforme
intermédiaire, pas de magie cachée. Le fetch handler reçoit chaque requête et décide quoi faire.
Astro 100% statique
apps/blog utilise Astro en mode output: 'static' sans adapter. Zéro runtime côté blog. Le résultat du build est
un dossier dist/ de fichiers HTML, CSS, JS et assets, servi directement par le Worker.
Les images Open Graph (les previews partagées sur les réseaux) sont également générées statiquement à la compilation
via getStaticPaths(), aucun rendu à la volée.
Recherche sémantique
La barre de recherche combine deux approches :
Pagefind gère la recherche textuelle classique. L’index est généré au build et embarqué dans les assets statiques. Zéro requête réseau pour la recherche par mots-clés.
La recherche sémantique entre en jeu pour les requêtes longues (plus de 3 mots). Elle fonctionne en deux temps :
- À la compilation, les titres, descriptions et tags de chaque article sont transformés en vecteurs par
Cloudflare Workers AI (modèle
@cf/baai/bge-small-en-v1.5) et stockés dans Cloudflare Vectorize - À la requête, le terme de recherche est lui aussi vectorisé, puis comparé aux articles via une recherche de similarité cosinus
Le résultat : une recherche qui comprend le sens, pas seulement les mots. Chercher “impact de l’IA sur les développeurs” remonte l’article sur les artisans du web, même sans correspondance de mots-clés exacte.
Cloudflare R2 & archivage des révisions
Le système de révisions repose sur Cloudflare R2, le stockage objet compatible S3 de Cloudflare.
À chaque build, une intégration Astro (revisionArchiver) se déclenche sur le hook astro:build:start. Elle lit les
frontmatters de tous les articles, identifie la révision la plus récente, et archive le contenu MDX correspondant dans
R2 selon la convention :
articles/{slug}/revisions/{YYYY-MM-DD}/{fichier}.mdx
Les révisions antérieures, déjà présentes dans R2 depuis les builds précédents, alimentent getStaticPaths() pendant
la génération : chaque chapitre de chaque révision archivée devient une page HTML statique. Zéro runtime, zéro
reconstruction à la volée.
L’intégration est isolée dans l’hook de build pour éviter de passer par le module runner de Vite, qui ne supporte pas les modules CommonJS comme le SDK AWS au moment de l’évaluation de la config.
CI natif Cloudflare Workers
Le déploiement est entièrement géré par le Cloudflare Workers CI (GitHub → Cloudflare pipeline).
À chaque push sur main :
pnpm --filter blog buildgénère le site statiquewrangler deploydéploie le Worker avec les assets
Pas de GitHub Actions, pas de configuration YAML. Le pipeline est configuré directement dans le dashboard Cloudflare.
Le résultat
Un site qui se charge en quelques dizaines de millisecondes, déployé sur le réseau edge de Cloudflare, avec une recherche sémantique gratuite. L’essentiel du coût est le temps de développement, l’infrastructure, elle, est quasi gratuite à cette échelle.
Tags
Révisions
Articles similaires
Écoconception
Empreinte environnementale estimée · Modèle SWD v4 · 442 g CO₂eq/kWh