Blog

Comment j'organise mon portfolio : Velite, MDX et structure hybride

  • architecture
  • mdx
  • velite
  • adr

Dans l'article sur Next.js 15, j'ai posé le framework. La question suivante était plus terre-à-terre : où mettre quoi — routes, composants, contenu MDX, assets — sans sur-architecturer un portfolio solo.

Voici les choix retenus pour l'organisation du code.

Le contexte

Avec Next.js 15, Tailwind, shadcn/ui et MDX, il me fallait :

  • un blog en français extensible (traductions un jour, pas maintenant) ;
  • une structure lisible dans 6 mois quand j'aurai oublié où j'ai rangé les choses ;
  • un pipeline de contenu typé et validé au build, pas du parsing fragile au runtime.

Structure hybride par domaine

J'ai évité deux extrêmes :

  • une structure plate (tout au même niveau → navigation difficile) ;
  • une architecture feature-based complète (overkill pour la taille actuelle).

Le compromis :

/app          → routes Next.js
/components   → UI par domaine (blog, layout, cv…)
/content      → MDX et assets co-localisés
/lib          → helpers (blog, utils)

Les composants blog vivent dans /components/blog, pas dans un dossier générique /buttons. Si le blog grossit trop, migration vers /features/blog sans tout casser.

Un dossier par article MDX

Chaque article a son propre dossier :

/content/blog/mon-article/
  index.mdx
  cover.jpg
  /images/

Pourquoi : déplacer ou supprimer un article = déplacer un dossier. Pas de correspondance manuelle entre article.mdx et /public/blog/article/images/.

La structure prépare aussi une évolution i18n : un jour, fr.mdx et en.mdx dans le même dossier, sans refonte des URLs d'emblée.

Velite comme pipeline de contenu

Velite compile le MDX au build time, génère des types TypeScript et valide le frontmatter via son schéma déclaratif (s.string(), s.isodate()…). Les pages consomment #site/content — pas de fs.readFile + regex maison.

Ce que ça m'apporte concrètement :

  • Type safety sur title, date, tags, slug, body ;
  • erreurs de métadonnées bloquantes au build (pas en prod) ;
  • assets hashés vers /public/static/ automatiquement.

Le schéma actuel est volontairement minimal. J'ajouterai cover ou draft quand le besoin sera réel.

Ce que j'ai écarté

AlternativePourquoi non
MDX plats (sans dossiers)Assets séparés → erreurs au rename
ContentlayerPlus maintenu depuis 2024
Parsing regex + eval()Fragile et risqué
Compilation MDX runtimeCode custom sans gain vs Velite
next-intl dès le départComplexité i18n non justifiée sans contenu EN
Branche develop séparéeAucune valeur pour un projet solo — previews Vercel suffisent

Les trade-offs acceptés

  • Étape Velite obligatoire avant next build — quelques secondes en dev (mode watch) ;
  • .velite/ gitignored — regénéré à chaque build ;
  • Frontmatter YAML sans autocomplete éditeur — compensé par la validation Velite au build ;
  • Français uniquement pour l'instant — migration i18n possible grâce à la structure dossiers.

Conclusion

L'architecture n'a pas vocation à impressionner sur un diagramme. Elle doit réduire la friction : écrire un article, ajouter une route, retrouver un composant — sans hésiter.

Prochaine brique visuelle : le design system turquoise — palette, typo Inter et tokens CSS.