El Manifiesto Sin Build: Publicar sin un Bundler
Lo siguiente no es un argumento sobre por qué debería abandonar sus herramientas de build. Es una medición de lo que ocurre cuando lo hace.
blakecrosley.com ejecuta FastAPI + Jinja2 + HTMX + Alpine.js + CSS puro. Sin webpack. Sin Vite. Sin Rollup. Sin compilador de TypeScript. Sin Babel. Sin PostCSS. Sin Tailwind. Sin package.json. Sin node_modules/. El sitio sirve 33 artículos de blog con 14 componentes interactivos de JavaScript, 20 guías, traducciones en nueve idiomas, y obtiene 100/100/100/100 en Lighthouse.
Resumen
La comunidad de HTMX tiene mucha promoción. Lo que le falta es evidencia. Los números aquí provienen de un sitio en producción con contenido sustancial, funciones interactivas e internacionalización, todo sin una sola herramienta de build. Los compromisos son honestos, y la conclusión es específica: para sitios orientados al contenido con un desarrollador individual o un equipo pequeño, las herramientas de build resuelven problemas que no tiene mientras crean problemas que sí tiene. Para equipos grandes con bibliotecas de componentes compartidas y paquetes de sistemas de diseño, las herramientas de build justifican su complejidad. La línea divisoria es más clara de lo que sugiere el debate.
El 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)
Sin transpilación. Sin tree shaking. Sin hot module replacement. Sin source maps. El JavaScript que escribe es el JavaScript que se despliega.
Los Números
Estas son las métricas reales, no estimaciones:
| Métrica | blakecrosley.com | Proyecto típico con Next.js (estimación del autor)1 |
|---|---|---|
| Dependencias | 18 paquetes de Python | Más de 300 paquetes de npm |
| Archivos de configuración de build | 0 | 5-8 (next.config, tsconfig, postcss, tailwind, eslint, babel, etc.) |
Tamaño de node_modules/ |
No existe | 150-400 MB |
| Tiempo de instalación | pip install -r requirements.txt: 8 segundos |
npm install: 30-90 segundos |
| Paso de build | Ninguno | next build: 15-60 segundos |
| Pipeline de despliegue | git push → en producción en ~40 segundos |
git push → instalar → build → desplegar: 2-5 minutos |
| Archivos CSS | 14 archivos, 10.300 líneas (CSS puro) | Generados desde Tailwind/Sass, el resultado varía |
| Archivos JS | 33 archivos, 10.061 líneas (legibles por humanos) | Empaquetados, minificados, divididos en chunks: ilegibles en producción |
| Rendimiento en Lighthouse | 100 | Varía (frecuentemente 70-90 sin trabajo de optimización) |
Los 18 paquetes de Python incluyen FastAPI, Jinja2, Pydantic, SQLAlchemy y otros 14. Ninguno es una herramienta de build. Ninguno es un compilador. Ninguno es un bundler.2
Lo Que Se Sacrifica
La honestidad exige enumerar los costos reales. Y son reales.
Sin TypeScript. Cada archivo .js en este proyecto es JavaScript vanilla. Las pruebas y el análisis de Claude Code detectan errores de tipo, no un compilador. El enfoque funciona para un desarrollador individual. No funcionaría para un equipo de 10 personas compartiendo interfaces de componentes entre módulos.
Sin Hot Module Replacement. Cuando cambio un archivo CSS, actualizo el navegador manualmente. El hx-boost de HTMX hace que la navegación sea lo suficientemente rápida como para que las actualizaciones completas sean tolerables. En un proyecto donde estoy iterando sobre detalles visuales cada 30 segundos, HMR ahorraría tiempo significativo.
Sin Tree Shaking. Cada byte de JavaScript que escribo llega al navegador. No puedo importar una sola función de una biblioteca de utilidades sin enviar el archivo completo. La restricción impone disciplina: archivos pequeños y enfocados en lugar de módulos de utilidades grandes. Los 14 componentes interactivos promedian entre 300 y 700 líneas cada uno porque deben ser autocontenidos.3
Sin bibliotecas de componentes de npm. Sin Radix, sin shadcn/ui, sin Headless UI. Cada elemento interactivo (la simulación de boids, el visualizador de código Hamming, el simulador de consenso) está construido a mano. El enfoque solo es viable porque los componentes interactivos sirven propósitos pedagógicos específicos, no patrones de UI genéricos.
Sin tokens de sistema de diseño desde npm. Mi sistema de diseño vive enteramente en CSS custom properties. No puedo importarlo como un paquete en otro proyecto. Para un sistema de un solo sitio, la restricción es aceptable. Para una organización con múltiples productos, no lo es.
Los cinco compromisos son aceptables para un sitio orientado al contenido con un solo desarrollador. Serían inaceptables para un producto SaaS con un equipo de ingeniería de 15 personas.
Lo Que Se Gana
Cero fallos de build. El pipeline de despliegue es git push. Ningún npm install puede fallar por un conflicto de dependencias entre pares. Ningún next build puede fallar por un error de TypeScript en un archivo que no toqué. Ningún PR de Dependabot actualiza una dependencia transitiva y rompe el build.4
Depurar con View Source. El JavaScript que se ejecuta en el navegador es el JavaScript que escribí. Sin necesidad de source maps. Sin mapeo desde la salida compilada al código fuente original. Cuando aparece un error en producción, leo el archivo desplegado directamente.
Inicio local instantáneo. uvicorn app.main:app --reload arranca en menos de 2 segundos. Sin npm run dev que instale, compile y empaquete antes de mostrar una página.
Cero ruido de Dependabot. Sin package-lock.json significa sin PRs semanales actualizando semver, ansi-regex o glob-parent: paquetes que nunca importé directamente pero que viven tres niveles de profundidad en mi árbol de dependencias.
A prueba del futuro. El sitio funcionará en 10 años. El HTML es HTML. El CSS es CSS. El JavaScript es JavaScript. No hay migración de Webpack 4 → 5, no hay deprecación de Create React App, no hay migración al App Router de Next.js. La plataforma es el estándar.5
HTMX como Arquitectura
El debate sobre HTMX se centra en la sintaxis: hx-get, hx-swap, hx-target. Ese es el enfoque equivocado. La perspectiva arquitectónica es que el HTML renderizado en el servidor es la API.
En una SPA tradicional:
Browser → fetch('/api/users') → JSON → React renders HTML → DOM update
Con HTMX:
Browser → GET /users (hx-get) → Server renders HTML fragment → DOM swap
El servidor devuelve la representación final. Sin gestión de estado del lado del cliente, sin serialización/deserialización, sin hidratación. La plantilla Jinja2 es el componente. El endpoint de FastAPI es la API. Una capa, no tres.6
El patrón se alinea directamente con el principio de ingeniería compuesta: cada pieza de infraestructura hace exactamente una cosa, y las piezas se componen sin interferencia. Una plantilla renderiza HTML. Una ruta lo devuelve. HTMX lo intercambia en el DOM. Ningún paso de build coordina estas piezas porque no se necesita coordinación.
CSS Puro Es Suficiente
Mi sistema de diseño usa 10 tokens de color, 13 pasos de escala tipográfica y ocho valores de espaciado, todos como CSS custom properties:
: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;
}
Sin paso de compilación Sass. Sin configuración de Tailwind generando utilidades. Sin plugins de PostCSS transformando sintaxis personalizada. El navegador lee estos valores directamente.7
La estética de belleza y brutalismo de este sitio (blanco sobre negro absoluto con cuatro niveles de opacidad) emerge de la restricción. Cuando no se puede recurrir a una paleta de colores, la tipografía lleva la jerarquía. Cuando no se puede recurrir a sombras de componentes, el espacio en blanco crea estructura. La restricción es el diseño.8
El Camino del CLS
El recorrido hacia Lighthouse expuso un costo genuino de no tener build: la extracción de CSS crítico requirió un script personalizado en Python. En un proyecto de Next.js, el framework maneja esto automáticamente.
El error específico: una media query móvil sobrescribía una CSS custom property (--gutter: 48px → --gutter: 24px). El CSS crítico incluía el valor de escritorio pero no la sobrescritura móvil. En dispositivos móviles, el hero se renderizaba con 48px de padding, luego cambiaba a 24px cuando se cargaba la hoja de estilos completa, produciendo un CLS de 0,493.
La solución fueron 12 líneas de Python. La investigación tomó tres horas. Una herramienta de build habría manejado esto automáticamente.
La contabilidad honesta: las herramientas de build automatizan cosas que se pueden hacer manualmente, pero la versión manual cuesta tiempo de depuración cuando falla. La pregunta es si el costo de la automatización (complejidad, dependencias, fallos de build, rotación por migraciones) excede el costo manual (sesiones de depuración ocasionales).
Para este sitio, el costo manual ha sido menor. Tres años, un error de CLS, tres horas de depuración. La alternativa (mantener un pipeline de build) habría consumido más tiempo acumulado en actualizaciones de dependencias, cambios disruptivos y mantenimiento de configuración.
Cuándo No Usar Esto
El enfoque sin build es incorrecto para:
Equipos grandes. El valor de TypeScript escala con el tamaño del equipo.9 Cuando 10 desarrolladores comparten interfaces de componentes, la verificación de tipos en tiempo de compilación previene errores de integración que las pruebas en tiempo de ejecución detectan demasiado tarde. Un desarrollador individual tiene todo el sistema en su cabeza. Un equipo no puede.
Paquetes de sistemas de diseño. Si múltiples productos consumen su sistema de diseño, necesita ser un paquete de npm con versionado adecuado, tree shaking y un pipeline de build. Las CSS custom properties en una sola hoja de estilos no se componen entre repositorios.
Estado complejo del lado del cliente. Si su aplicación tiene estado rico del lado del cliente (interfaces de arrastrar y soltar, colaboración en tiempo real, datos offline-first), un framework como React o Svelte justifica su complejidad. HTMX reemplaza el estado del cliente con viajes de ida y vuelta al servidor, lo cual funciona hasta que la latencia importa.
Bibliotecas del ecosistema npm. Si necesita primitivos de Radix, Framer Motion o TanStack Query, necesita un pipeline de build. Los tres asumen un bundler. Usarlos sin uno va de doloroso a imposible.
La línea divisoria es más simple de lo que sugiere el debate: si su aplicación es principalmente contenido renderizado por un servidor, las herramientas de build son sobrecarga. Si su aplicación es principalmente estado gestionado por un cliente, las herramientas de build son infraestructura.
Conclusiones Clave
Para desarrolladores individuales y equipos pequeños:
-
La prueba es el sitio, no el argumento. blakecrosley.com sirve 33 artículos, 14 componentes interactivos, 20 guías y nueve idiomas con cero herramientas de build y puntuaciones perfectas en Lighthouse. Los números son verificables.
-
El costo honesto de no tener build es depuración ocasional. El error de CLS tomó tres horas en resolverse. Una herramienta de build lo habría manejado automáticamente. A lo largo de tres años, el tiempo acumulado de depuración ha sido muy inferior al tiempo acumulado de mantenimiento que habría requerido un pipeline de build.
-
Las restricciones producen diseño. Sin colores obligó a la tipografía a llevar la jerarquía. Sin herramientas de build obligó a un JavaScript simple y autocontenido. Las mejores restricciones son las que se eligen antes de necesitarlas.
Para líderes técnicos evaluando opciones de stack:
-
Las herramientas de build resuelven problemas a escala de equipo. TypeScript, tree shaking y las bibliotecas de componentes justifican su complejidad cuando múltiples desarrolladores comparten interfaces. Un desarrollador individual construyendo sitios orientados al contenido no tiene estos problemas.
-
La contribución real de HTMX es arquitectónica. El HTML renderizado en el servidor como API elimina la gestión de estado del cliente, la serialización y la hidratación. La sintaxis es secundaria frente a la perspectiva.
El artículo conecta las secciones de Diseño e Ingeniería del blog. Las decisiones de diseño aparecen en Belleza y Brutalismo, Sistemas de Diseño para Startups y Escalas Tipográficas. Las mediciones de ingeniería están en Puntuación Perfecta en Lighthouse e Ingeniería Compuesta. El artículo sobre vibe coding explora dónde aplica esta filosofía al desarrollo asistido por IA.
-
La columna “Proyecto típico con Next.js” refleja la experiencia del autor en más de 5 proyectos de Next.js (2021-2024) y las normas reportadas por la comunidad. Los números específicos (más de 300 paquetes, 150-400 MB de node_modules) son consistentes con cifras comúnmente reportadas en la comunidad de Node.js. Los proyectos individuales varían significativamente. Los números son estimaciones del autor, no benchmarks verificados independientemente. ↩
-
Lista completa de dependencias a febrero de 2026: fastapi, uvicorn, starlette, pydantic, pydantic-settings, jinja2, markdown, pygments, beautifulsoup4, lxml, nh3, resend, python-dotenv, python-multipart, slowapi, httpx, sqlalchemy, analytics-941. Cero son herramientas de build. Cero son compiladores. Cero son bundlers. ↩
-
El tamaño promedio de los componentes (300-700 líneas) se midió a partir de los 14 archivos JS interactivos en
/static/js/a febrero de 2026. Los tamaños van desde 240 líneas (signal-calculator.js) hasta 690 líneas (boids-simulation.js). ↩ -
Basado en la experiencia del autor manteniendo proyectos de Next.js, el ecosistema de JavaScript genera entre 15 y 25 PRs de Dependabot por mes para un proyecto activo, la mayoría actualizando dependencias transitivas que el desarrollador nunca importó directamente. La cifra es una estimación de observación directa, no un benchmark verificado independientemente. ↩
-
La plataforma web (HTML, CSS, JavaScript) ha mantenido compatibilidad hacia atrás durante 30 años. Una página de 1996 todavía se renderiza en Chrome 2026. Tim Berners-Lee articuló esto como un principio de diseño: “un navegador debería ser compatible hacia atrás, en el sentido de que debería poder leer una versión anterior del lenguaje.” Véase w3.org/DesignIssues/Principles. ↩
-
Carson Gross, creador de HTMX, enmarca esto como “hipermedia como motor del estado de la aplicación” (HATEOAS). Véase los ensayos de htmx.org y el libro Hypermedia Systems (2023) de Gross, Stepinski y Cotter: hypermedia.systems. ↩
-
Las CSS Custom Properties (variables CSS) son compatibles con más del 97% de los navegadores a nivel global. Fuente: caniuse.com/css-variables. No se necesita ningún paso de compilación para usarlas. ↩
-
El principio de “la restricción como herramienta de diseño” tiene una larga historia. Charles Eames: “El diseño depende en gran medida de las restricciones.” El movimiento Dogme 95 en el cine demostró que eliminar herramientas (sin iluminación artificial, sin posproducción) producía una narrativa más honesta, no menos. Véase en.wikipedia.org/wiki/Dogme_95. ↩
-
La Encuesta de Desarrolladores de Stack Overflow de 2024 encontró que TypeScript es el 4.º lenguaje más popular y el superconjunto de JavaScript más popular, con una adopción que escala proporcionalmente con el tamaño del equipo. Véase survey.stackoverflow.co/2024/. ↩