A Community Group for Web-interoperable JavaScript runtimes

Hoy, Cloudflare, en colaboración con Vercel, Shopify e importantes colaboradores particulares de los sistemas Node.js y Deno, anuncia la creación de un nuevo grupo comunitario dedicado a la implementación interoperable de las API web estandarizadas en entornos de desarrollo no basados en JavaScript ni en navegadores.

El W3C y el Web Hypertext Application Technology Working Group (o WHATWG) han sido durante mucho tiempo pioneros en los esfuerzos por desarrollar las API y las funciones estandarizadas para la web como entorno de desarrollo. Las API como fetch(), ReadableStream y WritableStream, URL, URLPattern, TextEncoder, entre muchas otras, se han convertido en componentes generalizados y valiosos del desarrollo web moderno. Sin embargo, los estatutos de estos grupos siempre se han limitado explícitamente a considerar solo las necesidades específicas de los navegadores web, lo que ha promovido el desarrollo de estándares que no están fácilmente optimizados para cualquier entorno que no se parezca exactamente a un navegador web. Un buen ejemplo de este efecto es que algunas implementaciones no relacionadas con los navegadores del estándar Streams son un orden de magnitud más lentas que las implementaciones equivalentes de las transmisiones de Node.js y el lector de Deno, debido en gran medida a cómo se especifica la API en el estándar.

Los entornos sin servidor, como Cloudflare Workers, o los tiempos de ejecución como Node.js y Deno, tienen una amplia variedad de requisitos, problemas y prioridades que simplemente no son relevantes para los navegadores web, y viceversa. Esta desconexión, y la falta de una clara consideración de estas diferencias mientras se han desarrollado las distintas especificaciones, ha propiciado que los tiempos de ejecución sin navegadores implementen sus propias soluciones ad hoc a medida para funciones que en realidad son comunes a todos los entornos.

Esta nueva iniciativa cambia esta práctica, ya que ofrece un lugar para debatir y promover los requisitos comunes de todos los entornos web, implementados en cualquier lugar de la pila.

¿Qué beneficios ofrece a los desarrolladores?

Los desarrolladores quieren que su código sea portátil. Una vez que lo escriben, si deciden cambiar a un entorno diferente (de Node.js a Deno, por ejemplo) no quieren tener que reescribirlo solo para que siga haciendo exactamente lo mismo que ya hacía.

Una de las preguntas más comunes que recibimos de los usuarios de Cloudflare es cómo pueden utilizar algún módulo arbitrario publicado en npm que haga uso de algún conjunto de API específicas de Node.js o Deno. La respuesta suele conllevar la incorporación de una combinación arbitraria de implementaciones de polyfill. La situación es similar con el proyecto Deno, que ha optado por integrar un polyfill de toda la API del núcleo de Node.js directamente en su biblioteca estándar. Cuanto más implementen estos entornos los mismos estándares comunes, más podrá depender el ecosistema de desarrolladores de que el código que escriben funcione sin más, independientemente de dónde se ejecute.

Cloudflare Workers, Node.js, Deno y los navegadores web son muy diferentes entre sí, pero comparten muchas funciones comunes. Por ejemplo, todos proporcionan API para generar hashes criptográficos, todos tratan de alguna manera con datos de transmisión y todos proporcionan la capacidad de enviar una solicitud HTTP a algún lugar. Cuando existe esta coincidencia, y cuando los requisitos y funciones son los mismos, todos los entornos deberían implementar los mismos mecanismos estandarizados.

Grupo comunitario de tiempos de ejecución interoperables en la web

El nuevo grupo comunitario Web-interoperable Runtimes (o "WinterCG") opera bajo los procesos establecidos del W3C.

La denominación de este grupo es algo que nos llevó un tiempo decidir porque es fundamental para entender los objetivos que el grupo intenta alcanzar (y lo que no). El elemento clave es la frase "web-interoperable".

Utilizamos "web" exactamente en el mismo sentido en que las comunidades del W3C y del WHATWG utilizan el término, en concreto: navegadores web. El término "web-interoperable", por tanto, significa implementar funciones de una manera que sea idéntica o al menos lo más coherente posible con la forma en que esas características se implementan en los navegadores web. Por ejemplo, la forma en que el constructor new URL() funciona en los navegadores es exactamente la forma en que el constructor new URL() debería funcionar en Node.js, Deno y Cloudflare Workers.

Sin embargo, es importante reconocer el hecho de que Node.js, Deno y Cloudflare Workers no son navegadores web explícitamente. Si bien este punto debería ser obvio, es importante señalarlo porque las diferencias entre los distintos entornos de JavaScript pueden afectar en gran medida a las decisiones de diseño de las API estandarizadas. Node.js y Deno, por ejemplo, proporcionan acceso completo al sistema de archivos local. Cloudflare Workers, en cambio, no tiene sistema de archivos local. Además, los navegadores web restringen necesariamente las aplicaciones para que no manipulen el sistema de archivos local. Asimismo, mientras que los navegadores web incluyen de manera inherente un concepto de origen "de un sitio web" e implementan mecanismos como CORS para proteger a los usuarios de una serie de amenazas a la seguridad, no existe un concepto equivalente de "orígenes" en el lado del servidor donde operan Node.js, Deno y Cloudflare Workers.

Hasta ahora, los grupos W3C y el WHATWG se han ocupado estrictamente de las necesidades de los navegadores web. El nuevo grupo comunitario Web-interoperable Runtimes se ocupará y defenderá explícitamente las necesidades de todos.

La intención no es que WinterCG se separe y publique su propio conjunto de API estándares independientes. Las ideas de nuevas especificaciones que surjan de WinterCG se someterán primero a la consideración de los flujos de trabajo existentes en el W3C y el WHATWG con el objetivo de obtener el mayor consenso posible. Sin embargo, si queda claro que los navegadores web no tienen una necesidad o interés particular en una función que los otros entornos (como Cloudflare Workers) necesitan, WinterCG estará capacitado para avanzar con una especificación propia, con la restricción de que no se incorporará nada que entre en conflicto o sea incompatible a propósito con los estándares web establecidos.

Cualquier persona podrá participar en WinterCG. El grupo funcionará según los procesos y políticas establecidos por el W3C, todo el trabajo será accesible públicamente a través de la organización GitHub "wintercg"  y todo lo que haga estará centrado en el objetivo de maximizar la interoperabilidad.

En proceso

WinterCG ya ha empezado a trabajar en una serie de elementos de trabajo importantes.

API web mínima común

Extracto de la introducción de la actual propuesta de la especificación:

"La API mínima común de la plataforma web es un subconjunto seleccionado de API estandarizadas de la plataforma web que pretende definir un conjunto mínimo de capacidades comunes a los entornos de ejecución basados en JavaScript en navegadores y sin navegadores".

O dicho de otro modo. Se trata de un conjunto mínimo de API web existentes que se implementarán de forma coherente y correcta en Node.js, Deno y Cloudflare Workers. La mayoría de las API, con algunas excepciones y matices, ya existen en estos entornos, por lo que la mayor parte del trabajo que queda es garantizar que esas implementaciones se ajusten a sus especificaciones relativas y puedan cambiar entre entornos.

La siguiente tabla enumera todas las API incluidas actualmente en este subconjunto (así como una indicación de si la API es compatible con Node.js, Deno y Cloudflare Workers, o si lo será próximamente):

Node.js Deno Cloudflare Workers
AbortController ✔️ ✔️ ✔️
AbortSignal ✔️ ✔️ ✔️
ByteLengthQueueingStrategy ✔️ ✔️ ✔️
CompressionStream ✔️ ✔️ ✔️
CountQueueingStrategy ✔️ ✔️ ✔️
Crypto ✔️ ✔️ ✔️
CryptoKey ✔️ ✔️ ✔️
DecompressionStream ✔️ ✔️ ✔️
DOMException ✔️ ✔️ ✔️
Event ✔️ ✔️ ✔️
EventTarget ✔️ ✔️ ✔️
ReadableByteStreamController ✔️ ✔️ ✔️
ReadableStream ✔️ ✔️ ✔️
ReadableStreamBYOBReader ✔️ ✔️ ✔️
ReadableStreamBYOBRequest ✔️ ✔️ ✔️
ReadableStreamDefaultController ✔️ ✔️ ✔️
ReadableStreamDefaultReader ✔️ ✔️ ✔️
SubtleCrypto ✔️ ✔️ ✔️
TextDecoder ✔️ ✔️ ✔️
TextDecoderStream ✔️ ✔️ (próximamente)
TextEncoder ✔️ ✔️ ✔️
TextEncoderStream ✔️ ✔️
TransformStream ✔️ ✔️ ✔️
TransformStreamDefaultController ✔️ ✔️ (próximamente)
URL ✔️ ✔️ ✔️
URLPattern ? ✔️ ✔️
URLSearchParams ✔️ ✔️ ✔️
WritableStream ✔️ ✔️ ✔️
WritableStreamDefaultController ✔️ ✔️ ✔️
globalThis.self ? ✔️ (próximamente)
globalThis.atob() ✔️ ✔️ ✔️
globalThis.btoa() ✔️ ✔️ ✔️
globalThis.console ✔️ ✔️ ✔️
globalThis.crypto ✔️ ✔️ ✔️
globalThis.navigator.userAgent ? ✔️ ✔️
globalThis.queueMicrotask() ✔️ ✔️ ✔️
globalThis.setTimeout() / globalthis.clearTimeout() ✔️ ✔️ ✔️
globalThis.setInterval() / globalThis.clearInterval() ✔️ ✔️ ✔️
globalThis.structuredClone() ✔️ ✔️ ✔️

Siempre que uno de los entornos se aparte de la definición estandarizada de la API (como la implementación en Node.js de setTimeout() y setInterval()), se facilitará una documentación clara que describa las diferencias. Dichas diferencias solo deberían existir para la compatibilidad con el código existente.

Flujos de Web Cryptography

La API Web Cryptography proporciona unas API mínimas (y muy limitadas)  para operaciones criptográficas comunes. Una de sus principales limitaciones es el hecho de que, a diferencia del módulo criptográfico incorporado de Node.js, no tiene ningún soporte para entradas y salidas de transmisión de algoritmos criptográficos simétricos. Todas las funciones de Web Cryptography operan sobre partes de datos guardados en la memoria simultáneamente. Esto limita de forma estricta el rendimiento y la escalabilidad de las operaciones criptográficas. Utilizar estas API en cualquier entorno que no sea un navegador web, e intentar que tengan un buen rendimiento, se transforma en un problema al instante.

Para abordar esa cuestión, WinterCG ha empezado a elaborar una nueva especificación para los flujos de criptografía web que se presentará al W3C para que la considere como parte de una iniciativa más amplia que actualmente está llevando a cabo el W3C para actualizar la especificación de Web Crytography. El objetivo es llevar las operaciones de flujo de criptografía a toda la web, incluidos los navegadores, de forma que se ajuste a los estándares.

Un subconjunto de fetch() para servidores

Con el reciente lanzamiento de la versión 18.0.0, Node.js se ha unido a la colección de entornos JavaScript que proporcionan una implementación de la AP fetch() estandarizada de WHATWG. Sin embargo, hay una serie de diferencias importantes entre la forma en que Node.js, Deno y Cloudflare Workers implementan fetch() y la forma en que se implementa en los navegadores web.

Por un lado, los entornos de servidor no tienen el concepto de "origen" como un navegador web. Funciones como CORS, destinadas a proteger contra las vulnerabilidades de scripting entre sitios, son simplemente irrelevantes en el servidor. Asimismo, mientras que los navegadores web son utilizados generalmente por un solo usuario a la vez y tienen un concepto de almacén de cookies de ámbito global, las aplicaciones de servidor y sin servidor pueden ser utilizadas por millones de usuarios simultáneamente y un almacén de cookies de ámbito global que contenga potencialmente detalles de sesión y autenticación sería poco práctico y peligroso.

Debido a las acentuadas diferencias entre los entornos, a menudo es difícil razonar sobre los cambios propuestos en el estándar de fetch y obtener un consenso al respecto. Alguna nueva API propuesta, por ejemplo, podría ser increíblemente relevante para los usuarios de fetch en un servidor, pero completamente inútil para los usuarios de fetch en un navegador web. De la misma manera, los problemas de seguridad que sean relevantes para el navegador podrían no tener ningún impacto en el servidor.

Para solucionar este problema, y para facilitar que los entornos que no son navegadores web implementen fetch de forma coherente, WinterCG está trabajando en la documentación de un subconjunto del estándar fetch que aborda específicamente esos diferentes requisitos y limitaciones.

Lo más importante es que este subconjunto será totalmente compatible con el estándar fetch y se está desarrollando en conjunto por las mismas personas que han trabajado en fetch en Node.js, Deno y Cloudflare Workers. No se pretende que se convierta en una definición competitiva del estándar fetch, sino en un conjunto de directrices documentadas sobre cómo implementar fetch correctamente en estos otros entornos.

Esto es solo el principio

El grupo comunitario Web-interoperable Runtimes acaba de ponerse en marcha, y tenemos una serie de objetivos ambiciosos. Todo el mundo puede participar, y todo el trabajo se realizará en abierto a través de GitHub en https://github.com/wintercg. Queremos colaborar activamente con los grupos comunitarios W3C, WHATWG y la comunidad de JavaScript en general para garantizar que las funciones web estén disponibles, funcionen de forma coherente y cumplan los requisitos de todos los desarrolladores web que trabajen en cualquier lugar de la pila.

Para más información sobre WinterCG, consulta https://wintercg.org. Para saber cómo participar, consulta https://github.com/wintercg/admin.