JavaScript-Runtime: Deno – das bessere Node.js?

2018 ist die Laufzeitumgebung für JavaScript und TypeScript angetreten, die Schwächen von Node.js auszubügeln. Was zeichnet Deno aus?

In Pocket speichern vorlesen Druckansicht 54 Kommentare lesen

(Bild: Shutterstock.com/Gordana Simic)

Lesezeit: 18 Min.
Von
  • Sebastian Springer
Inhaltsverzeichnis

“10 Things I Regret About Node.js”: Mit diesem Titel kündigte Ryan Dahl sein neues Projekt Deno im Juni 2018 auf der JSConf EU an. Dabei war dieser Vortrag gleich aus mehreren Gründen bemerkenswert. Zum einen ist Ryan Dahl der Erfinder von Node.js und stellte der Plattform ein schlechtes Zeugnis aus. Außerdem hatte er neun Jahre zuvor auf der gleichen Veranstaltung die Node.js-Plattform zum ersten Mal einer breiten Öffentlichkeit vorgestellt.

In seinem Vortrag erläuterte Dahl die seiner Meinung nach schwerwiegendsten Schwächen von Node.js und lieferte mit Deno die Antwort darauf. Seine größten Kritikpunkte an Node.js waren das unnötig komplizierte Buildsystem GYP, die mangelnde Sicherheit der Plattform, die vorübergehende Abkehr von Promises sowie der Umgang mit Paketen.

Die grundsätzliche Idee hinter Node.js und Deno ist die gleiche. Beide stellen eine Plattform zur Verfügung, mit der sich JavaScript-Applikationen abseits des Browsers entwickeln lassen. Beide sind eventgetrieben und verfolgen einen Single-Threaded-Ansatz. Zudem setzen beide mit der V8-Engine auf die bewährte JavaScript-Engine aus dem Chrome-Browser. Es gibt aber auch deutliche Unterschiede. Ryan Dahl hat sich dazu entschieden, Deno im Kern mit Rust umzusetzen. Die Plattform nutzt das rusty_v8-Projekt zur Verbindung von Rust mit der C++-API der V8-Engine. Neben diesen beiden Kernkomponenten nutzt Deno die Tokio-Runtime, die ebenfalls in Rust geschrieben ist, um asynchrone Operationen zu planen und auszuführen. Abbildung 1 zeigt den generellen Aufbau der Deno-Plattform.

Aufbau der Deno-Plattform (Abb.1)

Deno weist einen für eine Rust-Applikation typischen Aufbau auf. Die einzelnen Bestandteile der Plattform sind in Crates unterteilt, das Rust-Äquivalent einer Bibliothek. Dabei bildet die CLI-Crate den Einstieg in die Welt von Deno. Die Kommandozeilenschnittstelle stellt deno zur Verfügung. Deno arbeitet auf dem Command Line Interface (CLI) mit sogenannten Sub-Befehlen. Ein Beispiel hierfür ist run-Sub, der eine Quellcode-Datei einliest und sie ausführt. Daneben gibt es weitere hilfreiche Sub-Befehle wie test zur Ausführung der Unittests einer Applikation, fmt zum Formatieren des Codes oder lint zur statischen Überprüfung des Sourcecodes. Diese und weitere sind in der CLI-Crate implementiert.

Um funktionieren zu können, greift das CLI auf den Kern der Deno-Plattform zu, das Core-Crate. Der Core wiederum nutzt die V8-Bindings von rusty_v8, um die JavaScript-Engine anzusprechen. Auf dieser Ebene führt Deno JavaScript-Quellcode aus. Dennoch beherrscht Deno TypeScript ebenso nativ wie JavaScript. Allerdings ist an dieser Stelle ein Zwischenschritt erforderlich, da die V8-Engine nur JavaScript-Code ausführen kann. Führt Deno eine TypeScript-Applikation aus, übersetzt die Plattform zunächst mithilfe des eingebauten TypeScript-Compilers den Quellcode, speichert ihn in einem lokalen Cache zwischen und führt ihn aus. Das Zwischenspeichern auf der Festplatte des Systems stellt sicher, dass die Übersetzung nur einmalig stattfindet.

Deno funktioniert auf den wichtigsten Systemen wie Linux, macOS und Windows und lässt sich entweder über die Kommandozeile oder einen Installer integrieren. Die Plattform selbst ist dabei mit einer Gesamtgröße von etwa 85 MByte für ihren Funktionsumfang verhältnismäßig leichtgewichtig. Nach der Installation ist Deno systemweit auf der Kommandozeile über deno verfügbar. Deno bietet mit seinem Read Eval Print Loop (REPL) einen interaktiven Modus, den deno ohne weitere Optionen aktiviert. Die interaktive Deno-Shell akzeptiert JavaScript- und TypeScript-Syntax, führt den Quellcode aus, gibt das Ergebnis aus und wartet auf eine erneute Eingabe. Eine Besonderheit des Ausführungsmodus ist, dass er zwar TypeScript-Syntax erlaubt, jedoch keinerlei Überprüfung durchführt. So ist es möglich, eine Variable als String zu deklarieren, ihr jedoch eine Zahl zuzuweisen.

Die zweite, deutlich häufiger verwendete Variante besteht aus run in Kombination mit einem Dateinamen. Deno nutzt diese Datei als Einstieg in eine Applikation. Eine Deno-Applikation besteht in der Regel nicht nur aus einer Datei, sondern aus einer Vielzahl von Dateien, die über das Modulsystem miteinander verbunden sind. Deno nutzt hier sowohl in TypeScript als auch in JavaScript das ECMAScript-Modulsystem mit den Schlüsselworten import und export. Die Unterscheidung zwischen JavaScript und TypeScript nimmt Deno anhand des Dateinamens vor. Der Standard ist JavaScript. Bei der Endung .ts (für TypeScript) übersetzt Deno den Quellcode in JavaScript und führt ihn anschließend aus. Eine Applikation kann sowohl TypeScript als auch JavaScript nutzen, solange der Quellcode in separaten Dateien liegt. Eine solche Strategie ist jedoch nicht zu empfehlen und sollte nur vorübergehend bei Migrationen von JavaScript auf TypeScript zum Einsatz kommen.