← Tous les articles

Le manifeste sans build : livrer sans bundler

Ce qui suit n’est pas un plaidoyer pour abandonner vos outils de build. C’est une mesure de ce qui se passe quand vous le faites.

blakecrosley.com fonctionne avec FastAPI + Jinja2 + HTMX + Alpine.js + CSS pur. Pas de webpack. Pas de Vite. Pas de Rollup. Pas de compilateur TypeScript. Pas de Babel. Pas de PostCSS. Pas de Tailwind. Pas de package.json. Pas de node_modules/. Le site sert 33 articles de blog avec 14 composants JavaScript interactifs, 20 guides, neuf traductions linguistiques, et obtient 100/100/100/100 sur Lighthouse.

En bref

La communauté HTMX ne manque pas de plaidoyers. Ce qui lui manque, ce sont des preuves. Les chiffres présentés ici proviennent d’un site de production avec un contenu substantiel, des fonctionnalités interactives et une internationalisation, le tout sans le moindre outil de build. Les compromis sont honnêtes, et la conclusion est ciblée : pour les sites axés sur le contenu avec un développeur solo ou une petite équipe, les outils de build résolvent des problèmes que vous n’avez pas tout en créant des problèmes que vous avez. Pour les grandes équipes avec des bibliothèques de composants partagées et des paquets de design system, les outils de build méritent leur complexité. La frontière est plus nette que le discours ne le laisse entendre.


La stack

Backend:    FastAPI + Jinja2 (server-rendered HTML)
Frontend:   HTMX + Alpine.js + Bootstrap 5 (CDN)
Styles:     Plain CSS with custom properties
JavaScript: Vanilla JS, IIFE-scoped per component
Deployment: Railway (git push → live)
CDN:        Cloudflare (caching, Workers, D1)

Pas de transpilation. Pas de tree shaking. Pas de hot module replacement. Pas de source maps. Le JavaScript que vous écrivez est le JavaScript qui est livré.


Les chiffres

Voici les métriques réelles, pas des estimations :

Métrique blakecrosley.com Projet Next.js typique (estimation de l’auteur)1
Dépendances 18 paquets Python 300+ paquets npm
Fichiers de configuration de build 0 5-8 (next.config, tsconfig, postcss, tailwind, eslint, babel, etc.)
Taille de node_modules/ N’existe pas 150-400 Mo
Temps d’installation pip install -r requirements.txt : 8 secondes npm install : 30-90 secondes
Étape de build Aucune next build : 15-60 secondes
Pipeline de déploiement git push → en ligne en ~40 secondes git push → install → build → deploy : 2-5 minutes
Fichiers CSS 14 fichiers, 10 300 lignes (CSS pur) Généré depuis Tailwind/Sass, résultat variable
Fichiers JS 33 fichiers, 10 061 lignes (lisibles par un humain) Bundlé, minifié, découpé : illisible en production
Performance Lighthouse 100 Variable (souvent 70-90 sans travail d’optimisation)

Les 18 paquets Python incluent FastAPI, Jinja2, Pydantic, SQLAlchemy et 14 autres. Aucun n’est un outil de build. Aucun n’est un compilateur. Aucun n’est un bundler.2


Ce à quoi vous renoncez

L’honnêteté exige de lister les coûts réels. Ils sont réels.

Pas de TypeScript. Chaque fichier .js de ce projet est du JavaScript pur. Les tests et l’analyse de Claude Code détectent les erreurs de type, pas un compilateur. L’approche fonctionne pour un développeur solo. Elle ne fonctionnerait pas pour une équipe de 10 personnes partageant des interfaces de composants entre modules.

Pas de Hot Module Replacement. Quand je modifie un fichier CSS, je rafraîchis le navigateur manuellement. Le hx-boost de HTMX rend la navigation suffisamment rapide pour que les rafraîchissements complets soient tolérables. Sur un projet où j’itère sur des détails visuels toutes les 30 secondes, le HMR ferait gagner un temps significatif.

Pas de Tree Shaking. Chaque octet de JavaScript que j’écris est envoyé au navigateur. Je ne peux pas importer une seule fonction d’une bibliothèque utilitaire sans livrer le fichier entier. La contrainte impose la discipline : des fichiers petits et ciblés plutôt que de grands modules utilitaires. Les 14 composants interactifs font en moyenne 300 à 700 lignes chacun parce qu’ils doivent être autonomes.3

Pas de bibliothèque de composants npm. Pas de Radix, pas de shadcn/ui, pas de Headless UI. Chaque élément interactif (la simulation de boids, le visualiseur de code de Hamming, le simulateur de consensus) est construit à la main. L’approche n’est viable que parce que les composants interactifs servent des objectifs pédagogiques spécifiques, pas des patterns UI génériques.

Pas de tokens de design system npm. Mon design system vit entièrement dans des propriétés personnalisées CSS. Je ne peux pas l’importer comme un paquet dans un autre projet. Pour un système mono-site, la contrainte est acceptable. Pour une organisation multi-produits, elle ne l’est pas.

Les cinq compromis sont acceptables pour un site axé sur le contenu avec un seul développeur. Ils seraient inacceptables pour un produit SaaS avec une équipe d’ingénierie de 15 personnes.


Ce que vous gagnez

Zéro échec de build. Le pipeline de déploiement est git push. Aucun npm install ne peut échouer à cause d’un conflit de peer dependency. Aucun next build ne peut échouer à cause d’une erreur TypeScript dans un fichier que je n’ai pas touché. Aucune PR Dependabot ne met à jour une dépendance transitive et ne casse le build.4

Déboguer avec « Afficher le code source ». Le JavaScript qui s’exécute dans le navigateur est le JavaScript que j’ai écrit. Pas besoin de source maps. Pas de correspondance entre la sortie compilée et le code source original. Quand un bug apparaît en production, je lis directement le fichier déployé.

Démarrage local instantané. uvicorn app.main:app --reload démarre en moins de 2 secondes. Pas de npm run dev qui installe, compile et bundle avant d’afficher une page.

Zéro bruit Dependabot. Pas de package-lock.json signifie pas de PR hebdomadaires mettant à jour semver, ansi-regex ou glob-parent : des paquets que je n’ai jamais importés directement mais qui vivent trois couches plus bas dans mon arbre de dépendances.

Pérennité. Le site fonctionnera dans 10 ans. Le HTML est du HTML. Le CSS est du CSS. Le JavaScript est du JavaScript. Il n’y a pas de migration Webpack 4 → 5, pas de dépréciation de Create React App, pas de migration vers le Next.js App Router. La plateforme, c’est le standard.5


HTMX comme architecture

Le discours autour de HTMX se concentre sur la syntaxe : hx-get, hx-swap, hx-target. C’est le mauvais angle d’approche. L’insight architectural est que le HTML rendu côté serveur est l’API.

Dans une SPA traditionnelle :

Browser → fetch('/api/users') → JSON → React renders HTML → DOM update

Avec HTMX :

Browser → GET /users (hx-get) → Server renders HTML fragment → DOM swap

Le serveur retourne la représentation finale. Pas de gestion d’état côté client, pas de sérialisation/désérialisation, pas d’hydratation. Le template Jinja2 est le composant. L’endpoint FastAPI est l’API. Une seule couche, pas trois.6

Ce pattern correspond directement au principe d’ingénierie par accumulation : chaque élément d’infrastructure fait exactement une chose, et les éléments se composent sans interférence. Un template rend du HTML. Une route le retourne. HTMX l’insère. Aucune étape de build ne coordonne ces éléments parce qu’aucune coordination n’est nécessaire.


Le CSS pur suffit

Mon design system utilise 10 tokens de couleur, 13 paliers d’échelle typographique et huit valeurs d’espacement, le tout en propriétés personnalisées CSS :

:root {
  --color-bg-dark:        #000000;
  --color-text-primary:   #ffffff;
  --color-text-secondary: rgba(255,255,255,0.65);
  --spacing-sm:           1rem;
  --spacing-md:           1.5rem;
  --font-size-lg:         1.25rem;
}

Pas d’étape de compilation Sass. Pas de configuration Tailwind générant des utilitaires. Pas de plugins PostCSS transformant une syntaxe personnalisée. Le navigateur lit ces valeurs directement.7

L’esthétique beauté et brutalisme de ce site (blanc sur noir absolu avec quatre niveaux d’opacité) émerge de la contrainte. Quand vous ne pouvez pas recourir à une palette de couleurs, la typographie porte la hiérarchie. Quand vous ne pouvez pas recourir aux ombres de composants, l’espace blanc crée la structure. La contrainte est le design.8


Le parcours du CLS

Le parcours Lighthouse a révélé un coût réel de l’absence de build : l’extraction du CSS critique a nécessité un script Python personnalisé. Dans un projet Next.js, le framework gère cela automatiquement.

Le bug spécifique : une media query mobile écrasait une propriété personnalisée CSS (--gutter: 48px--gutter: 24px). Le CSS critique incluait la valeur desktop mais pas le remplacement mobile. Sur mobile, le héros s’affichait avec un padding de 48px, puis basculait à 24px quand la feuille de style complète se chargeait, produisant un CLS de 0,493.

La correction faisait 12 lignes de Python. L’investigation a pris trois heures. Un outil de build aurait géré cela automatiquement.

Le bilan honnête : les outils de build automatisent des choses que vous pouvez faire manuellement, mais la version manuelle coûte du temps de débogage quand elle casse. La question est de savoir si le coût de l’automatisation (complexité, dépendances, échecs de build, instabilité des migrations) dépasse le coût manuel (sessions de débogage occasionnelles).

Pour ce site, le coût manuel a été inférieur. Trois ans, un bug de CLS, trois heures de débogage. L’alternative (maintenir un pipeline de build) aurait consommé plus de temps cumulé en mises à jour de dépendances, changements cassants et maintenance de configuration.


Quand ne pas utiliser cette approche

L’approche sans build est inadaptée pour :

Les grandes équipes. La valeur de TypeScript augmente avec la taille de l’équipe.9 Quand 10 développeurs partagent des interfaces de composants, la vérification de types à la compilation prévient des bugs d’intégration que les tests à l’exécution détectent trop tard. Un développeur solo garde l’ensemble du système en tête. Une équipe ne le peut pas.

Les paquets de design system. Si plusieurs produits consomment votre design system, il doit être un paquet npm avec un versionnement approprié, du tree shaking et un pipeline de build. Des propriétés personnalisées CSS dans une seule feuille de style ne se composent pas entre dépôts.

Un état client complexe. Si votre application a un état côté client riche (interfaces drag-and-drop, collaboration en temps réel, données offline-first), un framework comme React ou Svelte mérite sa complexité. HTMX remplace l’état client par des allers-retours serveur, ce qui fonctionne jusqu’à ce que la latence devienne critique.

Les bibliothèques de l’écosystème npm. Si vous avez besoin des primitives Radix, de Framer Motion ou de TanStack Query, vous avez besoin d’un pipeline de build. Les trois supposent un bundler. Les utiliser sans va du pénible à l’impossible.

La frontière est plus simple que le discours ne le laisse entendre : si votre application est principalement du contenu rendu par un serveur, les outils de build sont du surpoids. Si votre application est principalement de l’état géré par un client, les outils de build sont de l’infrastructure.


Points clés à retenir

Pour les développeurs solo et les petites équipes :

  • La preuve, c’est le site, pas l’argumentaire. blakecrosley.com sert 33 articles, 14 composants interactifs, 20 guides et neuf langues avec zéro outil de build et des scores Lighthouse parfaits. Les chiffres sont vérifiables.

  • Le coût honnête du sans-build est le débogage occasionnel. Le bug de CLS a pris trois heures à corriger. Un outil de build l’aurait géré automatiquement. Sur trois ans, le temps de débogage cumulé a été bien inférieur au temps de maintenance cumulé qu’un pipeline de build aurait exigé.

  • Les contraintes produisent le design. Pas de couleurs a forcé la typographie à porter la hiérarchie. Pas d’outils de build a forcé un JavaScript simple et autonome. Les meilleures contraintes sont celles que vous choisissez avant d’en avoir besoin.

Pour les responsables d’équipe évaluant des choix de stack :

  • Les outils de build résolvent des problèmes à l’échelle de l’équipe. TypeScript, le tree shaking et les bibliothèques de composants méritent leur complexité quand plusieurs développeurs partagent des interfaces. Un développeur solo construisant des sites axés sur le contenu n’a pas ces problèmes.

  • La vraie contribution de HTMX est architecturale. Le HTML rendu côté serveur comme API élimine la gestion d’état côté client, la sérialisation et l’hydratation. La syntaxe est secondaire par rapport à l’insight.


Cet article fait le lien entre les sections Design et Pratique d’ingénierie du blog. Les décisions de design apparaissent dans Beauté et Brutalisme, Design Systems pour Startups et Échelles typographiques. Les mesures d’ingénierie se trouvent dans Score Lighthouse parfait et Ingénierie par accumulation. L’article sur le vibe coding explore où cette philosophie s’applique au développement assisté par l’IA.



  1. La colonne « Projet Next.js typique » reflète l’expérience de l’auteur sur plus de 5 projets Next.js (2021-2024) et les normes rapportées par la communauté. Les chiffres spécifiques (300+ paquets, 150-400 Mo de node_modules) sont cohérents avec les chiffres couramment rapportés dans la communauté Node.js. Les projets individuels varient considérablement. Les chiffres sont des estimations de l’auteur, pas des benchmarks vérifiés indépendamment. 

  2. Liste complète des dépendances en février 2026 : fastapi, uvicorn, starlette, pydantic, pydantic-settings, jinja2, markdown, pygments, beautifulsoup4, lxml, nh3, resend, python-dotenv, python-multipart, slowapi, httpx, sqlalchemy, analytics-941. Zéro outil de build. Zéro compilateur. Zéro bundler. 

  3. Taille moyenne des composants (300-700 lignes) mesurée à partir des 14 fichiers JS interactifs dans /static/js/ en février 2026. Les tailles vont de 240 lignes (signal-calculator.js) à 690 lignes (boids-simulation.js). 

  4. D’après l’expérience de l’auteur dans la maintenance de projets Next.js, l’écosystème JavaScript génère 15 à 25 PR Dependabot par mois pour un projet actif, la plupart mettant à jour des dépendances transitives que le développeur n’a jamais importées directement. Ce chiffre est une estimation issue de l’observation directe, pas un benchmark vérifié indépendamment. 

  5. La plateforme web (HTML, CSS, JavaScript) a maintenu la rétrocompatibilité pendant 30 ans. Une page de 1996 s’affiche encore dans Chrome 2026. Tim Berners-Lee a articulé cela comme un principe de conception : « un navigateur devrait être rétrocompatible, en ce qu’il devrait être capable de lire une version antérieure du langage. » Voir w3.org/DesignIssues/Principles

  6. Carson Gross, créateur de HTMX, formule cela comme « l’hypermédia comme moteur de l’état de l’application » (HATEOAS). Voir les essais sur htmx.org et le livre Hypermedia Systems (2023) de Gross, Stepinski et Cotter : hypermedia.systems

  7. Les propriétés personnalisées CSS (variables CSS) sont prises en charge par plus de 97 % des navigateurs mondiaux. Source : caniuse.com/css-variables. Aucune étape de compilation n’est nécessaire pour les utiliser. 

  8. Le principe de « la contrainte comme outil de design » a une longue histoire. Charles Eames : « Le design dépend en grande partie des contraintes. » Le mouvement Dogme 95 au cinéma a prouvé que retirer des outils (pas d’éclairage artificiel, pas de post-production) produisait une narration plus honnête, pas moins. Voir en.wikipedia.org/wiki/Dogme_95

  9. L’enquête Stack Overflow Developer Survey 2024 a révélé que TypeScript est le 4e langage le plus populaire et le superset de JavaScript le plus populaire, avec une adoption proportionnelle à la taille de l’équipe. Voir survey.stackoverflow.co/2024/