Construire son propre page builder, c'est de la folie. C'est aussi la meilleure décision qu'on ait prise. Il en existe pourtant des dizaines, dans tous les langages — alors pourquoi réinventer la roue ? Parce que la roue qu'on voulait n'existait pas. Voici comment il marche, et ce que ce choix nous apporte vraiment.
Le concept : une page est une donnée
Tout part d'une idée simple : une page n'est pas un fichier qu'on code à la main, c'est une donnée qu'on manipule. On sépare radicalement le contenu (quoi afficher, dans quel ordre) du rendu (comment le transformer en HTML).
Cette donnée, c'est du JSON : un arbre de blocs. L'éditeur visuel ne fait qu'éditer cet arbre — glisser un bloc, changer une propriété, réordonner. Rien de plus. Et comme c'est de la donnée, elle est portable, versionnable (elle vit dans Git comme le reste) et importable d'un site à l'autre. Une section qu'on aime, on la copie-colle.
L'arborescence : sections → colonnes → blocs
L'arbre a trois étages, toujours les mêmes. Une section (la bande pleine largeur, avec son fond, son padding, sa grille) contient des colonnes (la mise en page sur 12 colonnes), qui contiennent des blocs (le contenu : titre, texte, image, slider, accordéon, posts…).
[
{
"type": "section",
"container": "max-w-6xl",
"columns": [
{
"gridColumn": "col-span-6",
"blocks": [
{ "type": "heading", "level": 2, "content": "Bonjour" },
{ "type": "text", "content": "<p>Un paragraphe.</p>" }
]
}
]
}
]C'est tout. Cette régularité est volontaire : trois niveaux, jamais plus. On peut imbriquer un bloc group pour les cas avancés, mais le modèle mental reste constant — section → colonne → bloc. Un développeur qui ouvre le JSON comprend la structure de la page en dix secondes, sans documentation.
De JSON à HTML : la génération de Blade
À la sauvegarde, le builder ne se contente pas de stocker le JSON : il génère un fichier Blade sur disque. La page servie au visiteur est du HTML quasi statique, sans coût d'interprétation du JSON à la volée. On paie le coût de transformation une fois, à l'enregistrement — pas à chaque visite. Rapide par construction.
Chaque type de bloc a son générateur — HeadingGenerator, ImageGenerator, SliderGenerator… — dont le seul travail est de transformer un nœud JSON en markup propre. Ajouter un type de bloc, c'est ajouter un générateur ; le reste de la chaîne ne bouge pas. Le JSON ci-dessus produit, par exemple :
<section id="section-a1b2" class="py-12">
<div class="container max-w-6xl">
<div class="col-span-6">
<h2 class="font-display text-3xl">Bonjour</h2>
<p>Un paragraphe.</p>
</div>
</div>
</section>Conséquence pratique à connaître : si on modifie un générateur, il faut redéployer ET re-sauver la page dans le builder pour régénérer le Blade. Le HTML sur disque ne se met pas à jour tout seul. C'est le prix de la vitesse, et on l'assume.
Le point délicat : le scoping CSS
Le morceau le plus subtil, c'est le CSS personnalisé par section. Si on laissait les règles telles quelles, une classe .ma-classe écrite dans une section déborderait sur toutes les autres. On préfixe donc automatiquement chaque sélecteur avec l'id de la section.
/* Ce que tu écris dans le panneau de la section */
.ma-classe { color: #FF5310; }
/* Ce qui est généré, préfixé par l'id de la section */
#section-xyz .ma-classe { color: #FF5310; }
/* Les @keyframes restent globales ; le & est remplacé par l'id du bloc */
@keyframes pulse { from { opacity: .5 } to { opacity: 1 } }Quelques finesses : les @keyframes sont préservées (elles doivent rester globales), et le & à la manière de SCSS est géré — remplacé par l'id du bloc, pour écrire des règles auto-référencées. Ce sont des détails invisibles, mais ce sont eux qui font qu'une feuille de style ne se marche jamais dessus.
Pourquoi le faire soi-même ?
Reste la vraie question : pourquoi tout ça, alors qu'il existe Gutenberg, Elementor, Webflow, Builder.io, GrapesJS, Puck… dans tous les langages ? Ces outils sont excellents, et pour la plupart des projets, ce sont eux qu'il faut choisir. Mais ils imposent tous le même marché : tu adoptes leur modèle, leur markup, leur écosystème — et tu t'y plies.
Or chez nous, le builder n'est pas un accessoire : c'est le cœur du produit. Il propulse tous les sites clients et l'agence elle-même. À cette échelle, trois choses comptent, et aucun outil tiers ne nous les donnait ensemble : la maîtrise totale du markup généré (donc des performances et de l'accessibilité), l'intégration native avec le reste de la stack (CodeIgniter, la médiathèque, l'authentification, le multilingue, le sitemap, le cache Redis), et la liberté d'évolution — un besoin client devient un nouveau bloc, pas un contournement.
| Critère | Builder tiers | Builder maison |
|---|---|---|
| Markup généré | imposé, souvent verbeux | maîtrisé ligne à ligne |
| Performances | variables | optimisées par construction |
| Intégration à la stack | via plugins / API | native |
| Évolution du produit | leur roadmap | la nôtre |
| Coût initial & maintenance | faible | élevé |
| À choisir si… | site unique, time-to-market | le builder = cœur de produit |
Et il y a le verrou : un builder tiers, c'est un abonnement, une dépendance, une roadmap qu'on ne contrôle pas. Le jour où il augmente ses prix, change son modèle de licence (les revirements de licence récents un peu partout ne donnent pas envie) ou ferme boutique, on subit. Le nôtre, on en répond.
Quand il ne faut PAS le faire
Soyons honnêtes : ce n'est pas un conseil universel. Écrire son builder coûte cher — au départ, et pour toujours, car il faut le maintenir à vie. Pour un site unique, un blog, un projet one-shot, c'est absurde : prends Gutenberg, Webflow ou un GrapesJS / Puck open source, et avance.
Le calcul ne penche en faveur du « maison » que lorsque le builder devient un actif stratégique : tu le réutilises sur des dizaines de projets, tu en fais un produit, tu as besoin d'un contrôle que rien d'autre n'offre. C'est notre cas. Pour la plupart des gens, ce n'est pas le leur — et c'est très bien ainsi.
La leçon : pouvoir dire oui
Un builder maison nous donne ce qu'aucune solution fermée ne donnera jamais : la maîtrise du markup, des performances, et de l'évolution du produit. Quand un client a un besoin précis, on ajoute un bloc. On ne contourne pas une limite imposée par un éditeur tiers.
C'est ça, l'indépendance technologique : pouvoir dire oui.