Objectifs du projet
Présenter une offre freelance (Symfony, API, data, outils métier), publier des articles techniques indexables, et offrir un contact fiable sans maintenir un serveur d’applications PHP ou Node pour un simple formulaire. Contraintes : temps de chargement correct, mise en page maîtrisée, conformité RGPD (politique, consentement, pas de trackers non essentiels par défaut).
Pourquoi Astro plutôt qu’un « gros » framework SPA ?
Les applications monopage (React/Vue seuls) envoient souvent un bundle volumineux avant que le contenu ne soit lisible. Pour une vitrine et un blog majoritairement lecture, l’intérêt est faible : on veut du HTML servi tout de suite, du CSS cohérent, et du JS uniquement là où c’est utile (formulaire, bandeau cookies, petites interactions).
Astro part de cette idée : par défaut, zéro JavaScript côté navigateur pour les composants ; les composants peuvent rester en HTML pur. Si besoin d’interactivité, on opte pour des îlots (islands) avec une framework UI au choix, ou du script inline ciblé — comme sur la page contact.
-
SSG :
astro buildproduit des fichiers statiques ; pas de runtime Node obligatoire en production. -
Routing par fichiers :
src/pages/→ URLs prévisibles (/blog/,/contact/, etc.). -
Composants réutilisables (
.astro) : en-tête, pied, cartes, mise en page article — même syntaxe pour tout le site. -
SEO : balises
<title>, meta description, canonical et données structurées (JSON-LD) injectées par layout.
Ce que contient concrètement le dépôt
-
src/pages/: les routes (accueil, services, à propos, contact, pages légales,blog/index.astropour la liste,blog/[slug].astropour générer une page par article). src/layouts/: gabarit global et gabarit article (titre, temps de lecture, JSON-LD blog).src/components/: navigation, pied de page, illustrations blog, bandeau cookies, etc.-
src/content/blog/*.md+src/content.config.ts: collectionblog(loaderglob, schéma Zod sur le frontmatter : titre, description, dates, temps de lecture, tags, cléillustrationpour le schéma SVG). -
src/content/BLOG-AUTHORS.md: rappel pour ajouter un nouvel article (fichier.md, champs obligatoires, build qui valide le schéma). -
public/: assets servis tels quels (favicon, images,contact-zapier.php— voir plus bas).
Blog : content collections et validation au build
Les articles ne sont plus des fichiers .astro dupliqués : chaque billet est un Markdown
dans src/content/blog/ (nom du fichier = slug d’URL). Au build, Astro charge la collection via
getCollection('blog') ; la page [slug].astro appelle render() pour produire le
HTML du corps. Si le frontmatter oublie un champ ou utilise une valeur d’illustration inconnue,
Zod fait échouer le build — utile quand le nombre d’articles augmente.
-
Liste :
blog/index.astrotrie les entrées parpubDatedécroissante. - SEO : titre et description viennent du frontmatter ; le layout article conserve canonical, Open Graph et JSON-LD.
-
Corps : Markdown et HTML autorisés (tableaux,
<aside class="tldr">, FAQ en<details>, blocs de code, etc.).
Les dépendances npm restent limitées (Astro, polices, sharp pour le pipeline d’assets). Pas de base de
données : le contenu du blog est versionné dans le dépôt comme le reste du site, avec une revue possible via PR sur
les fichiers .md.
Formulaire de contact : le problème CORS
Zapier expose une URL Catch Hook en HTTPS. En pratique, le navigateur ne peut en général
pas poster directement du JSON depuis votre domaine vers hooks.zapier.com : le
navigateur applique la politique CORS ; le domaine Zapier ne renvoie pas les en-têtes qui autoriseraient un POST
depuis n’importe quel site (et ce serait d’ailleurs risqué pour eux).
La solution retenue : le formulaire appelle une URL du même site (same-origin), qui
rejoue la requête côté serveur ou outil de dev.
-
En développement (
npm run dev) : un proxy Vite dansastro.config.mjsmappe/api/zapier-contactvershooks.zapier.comavec rewrite vers le chemin du Catch Hook. Le navigateur ne voit que localhost. -
En production (WAMP / Apache + PHP) : un fichier
public/contact-zapier.phpreçoit le POST JSON, valide les champs minimaux, et relaie aveccurlvers l’URL Zapier. Aucun Node requis sur le serveur : le site déployé est statique + ce seul endpoint PHP.
Côté page contact.astro, l’URL de soumission est choisie selon l’environnement :
import.meta.env.DEV → proxy ; sinon → /contact-zapier.php. Le corps envoyé est du JSON
avec notamment name, company, email, message,
submitted_at (ISO 8601).
Zapier : orchestrer sans coder un « back-office »
Zapier sert de couche d’intégration : lorsqu’un message arrive sur le Catch Hook, un Zap enchaîne les étapes — par exemple validation des champs, formatage, puis envoi via l’API Mailjet.
- Avantages : pas de serveur à patcher pour un SMTP custom ; possibilité d’ajouter plus tard une notion Slack, une ligne Google Sheets, ou un filtre anti-spam sans redéployer le site.
- Point d’attention : le flux dépend d’un service tiers ; surveiller les quotas et la bonne exécution des Zaps (logs Zapier). Pour une volumétrie très forte, on repenserait une file ou un endpoint dédié.
Mailjet : emails transactionnels et templates
Mailjet prend le relais pour la délivrabilité (SPF/DKIM/DMARC sur le domaine d’envoi), le suivi des bounces et un éditeur de templates transactionnels. Les champs saisis sur le site sont mappés dans Zapier vers les variables du template Mailjet.
Dans ce dépôt, le dossier email-templates/ contient une source MJML et le HTML généré,
avec une documentation des variables Mailjet (syntaxe du type {{var:name}}, {{var:email}},
etc. — voir README-mailjet-zapier.md dans ce dossier) pour rester aligné avec ce que Zapier envoie.
Workflow typique : modifier le MJML, recompiler en HTML (npx mjml …), mettre à jour le template côté
Mailjet si besoin.
Sécurité et vie privée (rappel)
- Le proxy PHP vérifie la méthode POST, parse le JSON et rejette les champs obligatoires manquants — pas d’exécution de code arbitraire à partir du corps brut.
- En production, HTTPS est indispensable pour protéger les données en transit ; le fichier PHP ne remplace pas une politique de mots de passe pour l’admin Mailjet/Zapier.
- Le site inclut une politique de confidentialité et un consentement explicite sur le formulaire ; les données ne servent qu’à répondre à la demande de contact, en cohérence avec l’usage décrit.
Ce qu’on pourrait ajouter plus tard
Les content collections Astro (Markdown + schéma Zod) sont déjà en place pour ce blog — ce qui suit concerne d’autres évolutions possibles, pas une migration à prévoir.
- MDX ou composants dans le corps des articles si le Markdown seul ne suffit plus ; images optimisées via le pipeline Astro si la galerie photo grossit.
- Protection anti-bot (hCaptcha / Turnstile) si le hook recevait trop de spam — souvent branché avant ou dans le Zap.
-
Hébergement sur CDN + CI qui lance
astro buildà chaque push, pour ne jamais oublier de régénérer le statique.
FAQ
Pourquoi ne pas utiliser un simple mailto: ?
Ouverture du client mail, pas de trace côté serveur, expérience inégale sur mobile, et pas de template Mailjet ni de chaîne Zapier. Le formulaire structuré donne des messages plus exploitables.
Astro impose-t-il TypeScript ou React ?
Non : les fichiers .astro suffisent pour ce site ; TS est optionnel ; React/Vue/Svelte ne sont
ajoutés que si vous choisissez des îlots interactifs.
Le proxy PHP est-il obligatoire si je suis sur Netlify / Vercel ?
Non : on peut remplacer le script par une serverless function ou un endpoint fournisseur qui rejoue le POST vers Zapier. L’idée reste la même : éviter le POST cross-origin direct depuis le navigateur.