A Community Group for Web-interoperable JavaScript runtimes

Heute gibt Cloudflare die Gründung einer neuen Community Group bekannt – gegründet in Zusammenarbeit mit Vercel, Shopify und einzelnen Mitwirkenden an Node.js und Deno. Die Gruppe arbeitet an der interoperablen Implementierung von standardisierten Web-APIs in JavaScript-basierten Entwicklungsumgebungen ohne Webbrowser.

Das W3C und die Web Hypertext Application Technology Working Group (WHATWG) leisten seit langem Pionierarbeit bei der Entwicklung standardisierter APIs und Features für das Web als Entwicklungsumgebung. APIs wie fetch(), ReadableStream und WritableStream, URL, URLPattern und TextEncoder sind inzwischen allgegenwärtige und wertvolle Elemente der modernen Webentwicklung geworden. Die Satzungen dieser bestehenden Gruppen berücksichtigen jedoch immer ausdrücklich nur die spezifischen Bedürfnisse von Webbrowsern. Das führte zur Entwicklung von Standards, die für eine Umgebung, die nicht genau wie ein Webbrowser aussieht nicht optimiert sind. Ein gutes Beispiel für diesen Effekt ist, dass einige Nicht-Browser-Implementierungen des Streams-Standards um eine Größenordnung langsamer sind als die entsprechenden Node.js-Streams und Deno-Reader-Implementierungen. Das liegt vor allem daran, wie die API im Standard spezifiziert ist.

Serverlose Umgebungen wie Cloudflare Workers oder Laufzeiten wie Node.js und Deno haben eine breite Palette von Anforderungen, Problemen und Bedenken, die für Webbrowser einfach irrelevant sind, und andersherum. Diese Diskrepanz und da diese Unterschiede bei der Entwicklung verschiedenen Spezifikationen nicht klar berücksichtigt wurden, hat dazu geführt, dass die Nicht-Browser-Laufzeiten ihre eigenen maßgeschneiderten, Ad-hoc-Lösungen für Funktionen implementiert haben, die eigentlich allen Umgebungen gemeinsam sind.

Mit diesem neuen Projekt ändert sich das. Es schafft einen Ort, an dem die gemeinsamen Anforderungen aller Webumgebungen, die überall im Stack bereitgestellt werden, diskutiert und vertreten werden können.

Was haben Entwickler davon?

Entwickler möchten, dass ihr Code portabel ist. Einmal geschrieben, möchten sie ihn beim Wechsel zu einer anderen Umgebung (z. B. von Node.js zu Deno) nicht komplett umschreiben müssen, nur damit er exakt das tut, was er ohnehin schon tat.

Unsere Nutzer fragen uns häufig, wie sie ein beliebiges Modul nutzen können, das auf npm veröffentlicht wurde und eine Reihe von Node.js- oder Deno-spezifischen APIs verwendet. Die Antwort besteht in der Regel in einer beliebigen Kombination von Polyfill-Implementierungen. Ähnlich verhält es sich mit dem Deno-Projekt, das ein Polyfill der gesamten Node.js-Kern-API direkt in seine Standardbibliothek integriert hat. Je mehr sich die Standards in diesen Umgebungen gleichen, desto mehr kann sich das Entwickler-Ökosystem darauf verlassen, dass der von ihnen geschriebene Code einfach funktioniert, unabhängig davon, wo er ausgeführt wird.

Cloudflare Workers, Node.js, Deno und Webbrowser sind alle sehr unterschiedlich, aber sie teilen eine ganze Reihe von gemeinsamen Funktionen. Zum Beispiel bieten sie alle APIs für die Generierung von kryptografischen Hashes; sie alle arbeiten in irgendeiner Weise mit Streaming-Daten; sie alle bieten die Möglichkeit, eine HTTP-Anfrage zu senden. Wo es diese Überschneidungen gibt und wo die Anforderungen und Funktionen gleich sind, sollten die Umgebungen alle die gleichen standardisierten Mechanismen implementieren.

Die Web-interoperable Runtimes Community Group

Die neue Web-interoperable Runtimes Community Group (oder „WinterCG“) arbeitet im Rahmen der etablierten Prozesse des W3C.

Wir haben eine Weile nach dem richtigen Namen für diese Gruppe gesucht, denn der Name ist entscheidend für das Verständnis der Ziele, die die Gruppe zu erreichen versucht (und auch dafür, was sie nicht ist). Das Schlüsselelement ist die Formulierung „web-interoperabel“.

Wir verwenden „Web“ in genau demselben Sinne wie die W3C- und WHATWG-Communitys – also: Webbrowser. Der Begriff „web-interoperabel“ bedeutet also, dass Features auf eine Weise implementiert werden, die entweder identisch oder zumindest so konsistent wie möglich mit der Art und Weise ist, wie diese Features in Webbrowsern implementiert sind. So sollte der neue URL()-Konstruktor in Browsern genauso funktionieren wie der neue URL()-Konstruktor in Node.js, in Deno und in Cloudflare Workers funktioniert.

Man muss sich jedoch darüber im Klaren sein, dass Node.js, Deno und Cloudflare Workers explizit keine Webbrowser sind. Das ist zwar offensichtlich, aber dennoch wichtig, denn die Unterschiede zwischen den verschiedenen JavaScript-Umgebungen können die Designentscheidungen für standardisierte APIs stark beeinflussen. Node.js und Deno bieten beispielsweise jeweils vollen Zugriff auf das lokale Dateisystem. Cloudflare Workers verfügt dagegen über kein lokales Dateisystem, und Webbrowser schränken Anwendungen zwangsläufig in der Bearbeitung des lokalen Dateisystems ein. Während Webbrowser von Natur aus ein Konzept des „Ursprungs“ einer Website enthalten und Nutzer über Mechanismen wie CORS vor einer Vielzahl von Sicherheitsbedrohungen schützen, gibt es auf der Serverseite, auf der Node.js, Deno und Cloudflare Workers arbeiten, kein entsprechendes Konzept des „Ursprungs“.

Bislang widmeten sich das W3C und die WHATWG ausschließlich den Bedürfnissen von Webbrowsern. Die neue Web-interoperable Runtimes Community Group befasst sich ausdrücklich mit den Bedürfnissen aller anderen und setzt sich für diese ein.

Die WinterCG hat nicht die Absicht, eine eigene Reihe unabhängiger Standard-APIs zu entwickeln und zu veröffentlichen. Ideen für neue Spezifikationen, die aus der WinterCG hervorgehen, werden zunächst den bestehenden Arbeitsgruppen des W3C und der WHATWG zur Prüfung vorgelegt, um einen möglichst breiten Konsens zu erzielen. Sollte sich jedoch herausstellen, dass Webbrowser keinen besonderen Bedarf oder kein Interesse an einem Feature haben, das die anderen Umgebungen (wie z. B. Cloudflare Workers) benötigen, wird die WinterCG mit einer eigenen Spezifikation voranschreiten können – mit der Einschränkung, dass nichts eingeführt wird, was absichtlich mit den etablierten Webstandards in Konflikt steht oder mit ihnen inkompatibel ist.

Die Beteiligung an der WinterCG steht jedem offen; die Gruppe wird im Rahmen der etablierten W3C-Prozesse und -Richtlinien arbeiten; die gesamte Arbeit wird über die GitHub-Organisation „wintercg“ offen zugänglich sein; und sämtliche Arbeit konzentriert sich darauf, die Interoperabilität zu maximieren.

Woran gearbeitet wird

Die WinterCG hat bereits begonnen, an einer Reihe von wichtigen Aufgaben zu arbeiten.

Das Minimum Common Web API

Aus der Einleitung im aktuellen Entwurf der Spezifikation:

„Die Minimum Common Web Platform API ist eine kuratierte Untergruppe von standardisierten Web-Plattform-APIs, die ein Minimum an gemeinsamen Funktionen für Browser- und Nicht-Browser-JavaScript-basierten Laufzeitumgebungen definieren soll.“

Oder anders ausgedrückt: Es handelt sich um einen minimalen Satz bestehender Web-APIs, die konsistent und korrekt in Node.js, Deno und Cloudflare Workers implementiert werden. Die meisten der APIs, mit einigen Ausnahmen und Nuancen, existieren bereits in diesen Umgebungen, sodass der Großteil der verbleibenden Arbeit darin besteht, sicherzustellen, dass diese Implementierungen mit den jeweiligen Spezifikationen übereinstimmen und über verschiedene Umgebungen hinweg portabel sind.

In der nachstehenden Tabelle sind alle APIs aufgeführt, die derzeit in dieser Untergruppe enthalten sind (zusammen mit einem Hinweis darauf, ob die API derzeit oder voraussichtlich in Kürze von Node.js, Deno und Cloudflare Workers unterstützt wird):

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 ✔️ ✔️ (in Kürze)
TextEncoder ✔️ ✔️ ✔️
TextEncoderStream ✔️ ✔️
TransformStream ✔️ ✔️ ✔️
TransformStreamDefaultController ✔️ ✔️ (in Kürze)
URL ✔️ ✔️ ✔️
URLPattern ? ✔️ ✔️
URLSearchParams ✔️ ✔️ ✔️
WritableStream ✔️ ✔️ ✔️
WritableStreamDefaultController ✔️ ✔️ ✔️
globalThis.self ? ✔️ (in Kürze)
globalThis.atob() ✔️ ✔️ ✔️
globalThis.btoa() ✔️ ✔️ ✔️
globalThis.console ✔️ ✔️ ✔️
globalThis.crypto ✔️ ✔️ ✔️
globalThis.navigator.userAgent ? ✔️ ✔️
globalThis.queueMicrotask() ✔️ ✔️ ✔️
globalThis.setTimeout() / globalthis.clearTimeout() ✔️ ✔️ ✔️
globalThis.setInterval() / globalThis.clearInterval() ✔️ ✔️ ✔️
globalThis.structuredClone() ✔️ ✔️ ✔️

Wann immer eine der Umgebungen von der standardisierten Definition der API abweicht (z. B. die Node.js-Implementierung von setTimeout() und setInterval()), werden die Unterschiede in einer eindeutigen Dokumentation beschrieben. Diese Unterschiede sollte es nur aus Gründen der Abwärtskompatibilität mit bereits bestehendem Code geben.

Web Cryptography Streams

Die Web Cryptography API bietet minimale (und sehr begrenzte) APIs gängiger Kryptographieoperationen. Eine der wichtigsten Einschränkungen ist die Tatsache, dass sie – anders als das integrierte Kryptomodul von Node.js – keine Unterstützung für das Streaming von Inputs und Outputs für symmetrische kryptografische Algorithmen bietet. Alle Web Cryptography-Features arbeiten mit Datenpaketen, die im Speicher gehalten werden, und zwar alle auf einmal. Dies schränkt die Performance und Skalierbarkeit von kryptografischen Operationen stark ein. Die Sache wird schnell mühsam, wenn Sie diese APIs in einer Umgebung verwenden, die kein Webbrowser ist, und versuchen, eine gute Performance zu erzielen.

Um dieses Problem anzugehen, arbeitet die WinterCG an einer neuen Spezifikation für Web Crypto Streams. Sie wird dem W3C zur Prüfung vorgelegt und ist Teil eines größeren Projekts, mit dem das W3C derzeit die Web Cryptography Spezifikation aktualisiert. Ziel ist es, Krypto-Streaming-Operationen für das gesamte Web, einschließlich Webbrowsern, in Übereinstimmung mit den bestehenden Standards zu ermöglichen.

Eine Untergruppe von fetch() für Server

Mit der kürzlich veröffentlichten Version 18.0.0 gehört Node.js nun zu den JavaScript-Umgebungen, die eine Implementierung der standardisierten fetch()-API der WHATWG bieten. Die Implementierung von fetch() durch Node.js, Deno und Cloudflare Workers unterscheidet sich jedoch in einigen wichtigen Punkten von der Implementierung in Webbrowsern.

Zum einen gibt es in Serverumgebungen kein Konzept des „Ursprungs“ wie bei einem Webbrowser. Features wie CORS, die vor Cross-Site-Scripting-Sicherheitslücken schützen sollen, sind auf dem Server einfach irrelevant. Während Webbrowser in der Regel jeweils von einem einzelnen Nutzer verwendet werden und über ein Konzept eines globalen Cookie-Speichers verfügen, können Server und serverlose Anwendungen von Millionen von Nutzern gleichzeitig verwendet werden, und ein globaler Cookie-Speicher, der möglicherweise Sitzungs- und Authentifizierungsdaten enthält, wäre sowohl unpraktisch als auch gefährlich.

Aufgrund der akuten Unterschiede in den Umgebungen ist es oft schwierig, über vorgeschlagene Änderungen am Fetch-Standard nachzudenken und einen Konsens darüber zu erzielen. Eine neue API könnte beispielsweise für Fetch-Nutzer auf einem Server äußerst relevant sein, für Fetch-Nutzer in einem Webbrowser dagegen völlig nutzlos. Eine Reihe von Sicherheitsbedenken, die für den Browser relevant sind, haben möglicherweise keinerlei Auswirkungen auf den Server.

Um dieses Problem anzugehen und die konsistente Implementierung von Fetch in Nicht-Webbrowser-Umgebungen zu erleichtern, arbeitet die WinterCG an der Dokumentation einer Untergruppe des Fetch-Standards. Sie befasst sich speziell mit diesen unterschiedlichen Anforderungen und Beschränkungen.

Entscheidend ist, dass diese Untergruppe vollständig mit dem Fetch-Standard kompatibel sein wird. Sie wird gemeinsam mit den Entwicklern von Fetch in Node.js, Deno und Cloudflare Workers erarbeitet. Es soll keine konkurrierende Definition des Fetch-Standards werden, sondern eine Reihe von dokumentierten Richtlinien für die korrekte Implementierung von Fetch in diesen anderen Umgebungen.

Wir fangen gerade erst an

Die Web-interoperable Runtimes Community Group steht erst am Anfang und wir haben uns eine Reihe von ehrgeizigen Zielen gesetzt. Jeder kann mitmachen und alle Arbeiten werden offen über GitHub unter https://github.com/wintercg durchgeführt. Wir bemühen uns aktiv um die Zusammenarbeit mit dem W3C, der WHATWG und der JavaScript-Community insgesamt, um sicherzustellen, dass Web-Features verfügbar sind, konsistent funktionieren und die Anforderungen aller Web-Entwickler erfüllen, die überall auf dem Stack arbeiten.

Weitere Informationen über die WinterCG finden Sie unter https://wintercg.org. Einzelheiten zur Teilnahme finden Sie unter https://github.com/wintercg/admin.