Cómo la usan los frameworks: SSR y edge de forma uniforme
El lado del consumidor de la Environment API: cómo Astro, SolidStart, TanStack Start y el plugin de Cloudflare dejan de reimplementar runners ad hoc y modelan cada runtime de despliegue como un entorno. El caso de workerd, donde el dev corre en el runtime real y por fin coincide con producción.
Una API de plataforma se mide por lo que deja de existir río abajo. Antes de la Environment API, cada meta-framework cargaba con su propio runner de servidor, su propio puente de HMR y su propia forma de fingir el edge. Con ella, todos convergen en un mismo primitivo: un entorno por runtime de despliegue, contribuido por un adaptador. Este nivel mira cómo Astro, SolidStart, TanStack Start y el plugin de Cloudflare usan la API, y por qué el caso de workerd es el que mejor muestra la ganancia: por primera vez, el dev del edge corre en el edge.
- Ver el patrón común: un adaptador aporta un entorno por runtime de despliegue.
- Entender cómo el plugin de Cloudflare corre tu Worker en
workerddurante el desarrollo. - Situar a Astro, SolidStart y TanStack Start sobre el mismo primitivo de entornos.
- Reconocer por qué los RSC son el caso que exige varios entornos a la vez.
El patrón común: un entorno por adaptador
Todos los meta-frameworks resuelven la misma ecuación: tomar tu código y hacerlo correr en un runtime de despliegue —Node, Cloudflare, Vercel, Deno—. Antes, cada uno lo hacía a su manera, reimplementando por dentro un trozo del pipeline de Vite: un runner tipo vite-node, un empaquetado manual del servidor, un juego de polyfills. La Environment API les ofrece un lugar canónico donde encajar ese trabajo: el adaptador aporta un environment.
Un adaptador de despliegue, en el mundo nuevo, es esencialmente una fábrica de entornos. Declara un entorno con las condiciones de resolución de su runtime, provee un createEnvironment que sabe instanciar ese runtime en dev y coloca un ModuleRunner dentro de él conectado por un transport. A partir de ahí, Vite hace el resto: transforma una vez por entorno, el runtime ejecuta, y el HMR fluye por el canal del entorno. El framework deja de mantener su runner.
// Esbozo de un adaptador: aporta un entorno via config, no un runner propio
function adaptadorEdge(): Plugin {
return {
name: 'adaptador-edge',
config() {
return {
environments: {
edge: {
consumer: 'server',
resolve: { conditions: ['worker', 'browser', 'import'] },
dev: {
// instancia el runtime real y coloca dentro un ModuleRunner
createEnvironment(name, config) {
return crearDevEnvironmentEnElRuntime(name, config)
},
},
},
},
}
},
}
}
Lee ese esbozo como la esencia de un adaptador moderno: no trae un runner ni un bundler propios, solo declara un entorno y provee la factoría que sabe instanciar su runtime. Todo lo demás —transformar, resolver, cachear, propagar el HMR— lo pone Vite. El adaptador aporta conocimiento del destino; la plataforma aporta la maquinaria.
Ese es el giro que abarata tanto la adopción de la API para un framework: la superficie que debe implementar se reduce a lo irreducible. Antes, soportar un runtime nuevo era escribir medio Vite; ahora es escribir una factoría y unas condiciones. La barrera de entrada para modelar un destino cae de un proyecto a una función.
La señal de que la abstracción está bien trazada es que el adaptador dejó de ser un rival de la herramienta para volverse una extensión suya. Antes, cada framework construía por fuera un aparato que solapaba con Vite y a menudo peleaba con él; ahora encaja por dentro, en el hueco que la API reserva para el conocimiento del runtime. Cuando extender una plataforma se parece más a rellenar un contrato que a reescribir sus tripas, la plataforma ha ganado.
flowchart LR ad[Adaptador de despliegue] --> ef[createEnvironment] ef --> env[Environment del runtime] env --> mr[ModuleRunner dentro del runtime] env --> cond[condiciones y transforms del destino] style ad fill:#cba6f7,color:#11111b style env fill:#89b4fa,color:#11111b style mr fill:#a6e3a1,color:#11111b
Conviene subrayar el reparto de responsabilidades que esto instaura. Vite se queda con lo genérico —transformar, resolver, cachear, propagar el HMR— y el adaptador se queda solo con lo específico de su runtime: cómo se arranca, qué globales inyecta, dónde vive su ModuleRunner. Esa línea limpia entre lo común y lo particular es la razón de que la misma API sirva por igual a un adaptador de Node trivial y a uno de workerd que orquesta Miniflare.
Cloudflare y workerd: dev igual que producción
El caso más nítido es el plugin oficial de Cloudflare para Vite. Su objetivo es que tu Worker corra, en desarrollo, dentro del mismo runtime que en producción: workerd, a través de Miniflare. Para lograrlo declara un entorno cuyo ModuleRunner vive dentro del Worker; cuando llega una petición, Vite transforma el módulo con las condiciones de workerd y el runner lo ejecuta en el runtime real, no en un simulacro de Node.
La consecuencia es enorme y concreta: los globales, la resolución de módulos y las restricciones que ves en dev son los de workerd. Si usas un binding de KV, R2 o D1, está disponible en desarrollo con su semántica auténtica. El bug de “funcionaba en local y reventó al desplegar” —el síntoma que definía la era de los dos grafos— desaparece porque local y despliegue son el mismo runtime.
// vite.config.ts con el plugin de Cloudflare
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'
export default defineConfig({
plugins: [cloudflare()],
// el plugin declara un entorno workerd y ejecuta tu Worker
// dentro de Miniflare, con HMR, en el runtime real del edge
})
Conviene no leer “dev en el runtime real” como una comodidad estética. En el edge, la brecha entre un simulacro de Node y workerd no es cosmética: son APIs distintas, límites distintos y fallos que solo aparecen en producción, justo donde más caro es descubrirlos. Que el plugin de Cloudflare ejecute tu Worker en workerd desde el primer vite dev traslada esos fallos al momento más barato de arreglarlos, tu propia máquina. La Environment API no inventó workerd; lo que hizo fue dar el hueco donde ese runtime encaja como un entorno de primera clase, con transform, grafo y HMR propios.
Astro, SolidStart y el caso de los RSC
El mismo primitivo sirve a frameworks de propósito distinto. Astro mueve su integración con Vite hacia los entornos para que sus adaptadores —Node, Cloudflare, Vercel— se expresen como environments y sus islas de servidor y el soporte de componentes de servidor descansen sobre varios grafos. SolidStart y TanStack Start convergen en lo mismo: en lugar de una capa propia que orquesta runtimes —el papel que antes jugaban proyectos como Vinxi o Nitro—, se apoyan en los entornos de Vite para modelar cliente y servidor de forma uniforme.
La lista sigue: React Router, tras absorber Remix, apunta al mismo primitivo para su renderizado de servidor; y proyectos como el SDK de Redwood para Cloudflare nacen ya asumiendo los entornos como base para servir RSC sobre workerd. Lo revelador no es qué framework concreto lo adopta antes, sino que todos convergen a la misma pieza en lugar de multiplicar soluciones incompatibles. Cuando competidores que no se coordinan eligen el mismo cimiento, suele ser porque el cimiento captura una verdad del dominio que ninguno puede permitirse ignorar.
Astro
Adaptadores como entornos. Las islas de servidor y el render por destino dejan de necesitar una capa propia de ejecución.
Cloudflare
El plugin corre tu Worker en workerd vía Miniflare en dev. Bindings reales y HMR en el runtime de producción.
SolidStart y TanStack
Cliente y servidor modelados como entornos de Vite, sin reimplementar el runner ni el puente de HMR.
RSC
Tres entornos vivos a la vez: servidor de componentes, SSR y cliente, cada uno con su grafo y su resolución.
Los React Server Components son el banco de pruebas más exigente, y por eso el más revelador. Una app con RSC necesita tres grafos coexistiendo: el entorno de servidor que ejecuta los componentes de servidor, el de SSR que convierte su salida en HTML y el de cliente que hidrata en el navegador. Cada uno resuelve los paquetes con condiciones distintas —la directiva de cliente marca la frontera— y cada uno tiene su transform. Modelar eso con dos grafos cableados era imposible sin parches; con la Environment API es, literalmente, declarar tres entornos. Que el patrón más complejo del frontend actual se exprese como una lista de entornos es la mejor prueba de que la abstracción está bien puesta.
El dividendo compartido: plugins portables
Hay un beneficio que solo se ve cuando miras el ecosistema entero en lugar de un framework aislado. Como todos hablan el mismo primitivo —entornos con nombre, this.environment en los hooks, applyToEnvironment para acotar—, un plugin escrito contra la Environment API funciona igual bajo Astro, bajo SolidStart o bajo el plugin de Cloudflare. Antes, un plugin que quisiera comportarse distinto en servidor tenía que adivinar el contexto con heurísticas frágiles; ahora lo pregunta a la API, y la respuesta es la misma sea cual sea el framework que la envuelve.
// El mismo plugin, valido en cualquier framework que use la Environment API
function soloEnEdge(): Plugin {
return {
name: 'solo-en-edge',
applyToEnvironment(env) {
return env.name === 'workerd' // no depende del framework, solo del entorno
},
transform(code) {
return this.environment.name === 'workerd' ? adaptarAlEdge(code) : null
},
}
}
Esta portabilidad es la que empieza a desfragmentar el ecosistema. La comunidad de plugins deja de bifurcarse por framework y se reorganiza alrededor de los entornos, que es la frontera que de verdad importa. Un autor de plugins mantiene una sola implementación; un usuario la instala sin preguntarse si “es compatible con mi meta-framework”, porque la pregunta correcta pasó a ser otra: “¿qué entornos toca?”.
Hay un patrón que se repite en la historia de las buenas abstracciones de infraestructura: su éxito no se mide por lo que añaden, sino por lo que dejan de hacer necesario río abajo. Antes de la Environment API, cada meta-framework de la galaxia Vite mantenía, con esfuerzo considerable, su propia versión de la misma máquina: un runner para ejecutar código de servidor en dev, un mecanismo para fingir o alcanzar el edge, un puente para que el HMR cruzara del servidor al runtime, un empaquetado a medida para producción. Eran miles de líneas duplicadas entre proyectos que competían resolviendo, cada uno peor y en soledad, un problema que era de la herramienta. Al reificar el entorno y separar la transformación de la ejecución, Vite absorbió ese problema hacia la plataforma y les dejó a los frameworks un hueco limpio donde encajar solo lo que de verdad es suyo: qué runtimes soportan y cómo se instancian. Un adaptador de Cloudflare deja de ser un mini-Vite y pasa a ser una fábrica de un entorno workerd. Astro deja de orquestar runtimes y pasa a declararlos. El resultado no es solo menos código, sino convergencia: como todos hablan el mismo primitivo, un plugin escrito para un entorno funciona en cualquier framework que use la API, y el ecosistema deja de fragmentarse en islas incompatibles. Cuando veas que una API nueva hace desaparecer categorías enteras de código repetido en sus consumidores —no que les da más funciones, sino que les quita responsabilidades— estás ante una verdadera plataforma, y no ante una librería más. Esa es la huella que la Environment API está dejando en 2026.
- Instala el plugin de Cloudflare en un proyecto de juguete y confirma que
vite devejecuta tu Worker enworkerd, no en Node. - Usa un binding —KV o D1— en desarrollo y verifica que responde con su semántica real.
- Investiga cómo un adaptador que uses declara su entorno y dónde coloca su
ModuleRunner. - Dibuja los tres entornos de una app con RSC y anota qué condición de resolución distingue al de cliente.
- Escribe un plugin con
applyToEnvironmentacotado aworkerdy razona por qué sería reutilizable entre frameworks distintos.