Anzeige
Anzeige
How-To

Besser als Node.js? Was Deno vom großen Bruder unterscheidet

Der Node.js-Erfinder Ryan Dahl hat mit seinem Team eine neue Entwicklungsplattform vorgelegt: Deno soll dabei nicht nur die Schwachstellen des Vorgängers beheben, sondern auch ­effizienter sein. Aber lohnt sich der Umstieg?

Von Krzysztof Piechowicz
9 Min.
Artikel merken
Anzeige
Anzeige

Deno versteht sich als eine „einfache, moderne und sichere Plattform für JavaScript und TypeScript“.

Mit Deno will das Team um den Node.js-Erfinder Ryan Dahl mehr als nur einige Schwachstellen – wie die Architektur – der Open-Source-­JavaScript-Laufzeitumgebung ­korrigieren. Vielmehr ist das Ziel, eine moderne Entwicklungsplattform zu schaffen, die Werkzeuge für den gesamten Softwareentwicklungsprozess enthält: von der Entwicklung über das Testen, die Code-Formatierung und Produktionsversionierung bis hin zur Dokumentation.

Anzeige
Anzeige

Deno versteht sich dabei als eine „einfache, moderne und ­sichere Plattform für JavaScript und TypeScript“. Das klingt vertraut, wenn man auf der offiziellen Website von Node.js liest, es sei eine „JavaScript-Laufzeitumgebung, die auf der JavaScript-­Engine V8 basiert“. In der Tat haben beide Platt­formen ein ­ähnliches Ziel: Sie wollen Entwicklern dabei helfen, mit JavaScript Anwendungen zu erstellen, die außerhalb des ­Webbrowsers – im Backend – laufen. Beide Umgebungen basieren auf ­asynchroner und ereignisgesteuerter Architektur und verwenden die ­V8-JavaScript-Engine von Google, um JavaScript-Code auszuführen. In der Anwendung unterscheiden sich die Plattformen jedoch in vielen Punkten. Zunächst ist Deno kein Fork von Node.js, sondern eine völlig neue Umgebung, die auf der Sprache Rust basiert und mit ihren älteren Konkurrenten in­kompatibel ist.

Ein weiterer Unterschied ergibt sich aus einem Hauptnachteil von Node.js: Es unterstützt ES-Modules – also den ­wichtigsten ECMAScript-Standard, der das Modulsystem für JavaScript beschreibt – nativ nur sehr mangelhaft. Mit den neuesten Node.js-Versionen können Entwickler zwar die Syntax der ES-Modules verwenden. Doch zum Druckschluss war ­diese Funktion noch als „experimentell“ gekennzeichnet. Darüber ­hinaus muss Node.js noch das CommonJS-System unterstützen, auf dem es seit seiner Gründung basiert, weil es schon so viele Node.js-Projekte gibt, die es nutzen. Deno unterstützt dagegen ausschließlich ES-­Modules. Es importiert die Module – wie die Dateien im Browser – zur Moduldatei, indem es die gesamte URL verwendet:

Anzeige
Anzeige

import {serve} from "https://deno.land/std/http/server.ts";

Anzeige
Anzeige

Auf den ersten Blick sieht dieses Format im Vergleich zu Node.js kompliziert aus, denn hier müssen Entwickler nur den ­Modulnamen eingeben:

const {Server} = require("http");

Anzeige
Anzeige

Trotzdem hat Denos Design gleich zwei wesentliche Vorteile ­gegenüber Node.js:

Erstens wissen Entwickler durch die Analyse der URL sofort, welches Modul und welche Datei sie importieren, und wo die Codequelle gespeichert ist. Da Deno immer eine einzelne Datei importiert und dazu ihre Extension erfordert, können Programmierer den Link im Browser öffnen und die Quelle analysieren. Pakete zu importieren, sieht in Node.js also nur einfacher aus. In Wirklichkeit steckt dahinter jedoch ein ziemlich komplizierter Algorithmus. Mit seiner Hilfe muss Node.js entscheiden, welche Datei es laden soll: Handelt es sich um ein Benutzermodul? Gibt es eine npm-Installation? Oder handelt es sich um eine lokale oder globale Installation?

Zweitens behebt Deno einen Kritikpunkt, dem sich Node.js ­immer wieder stellen muss: die Art, wie es externe Abhängig­keiten des Projektes speichert. Jede in Node.js ­geschriebene Anwendung hat ihre eigenen Node_modules. Das ist ein Verzeichnis mit externen Abhängigkeiten (mit Ausnahme von global ­installierten Modulen), in das Node.js den Inhalt des gesamten Moduls herunter­lädt – also auch die Funktionen, die ein ­Programm gar nicht verwendet. Das macht das Verzeichnis ­natürlich unnötig groß. Deno löst dieses Problem, indem es nur die erforderlichen Dateien importiert und nicht das gesamte ­Modul. Alle Moduldetails – wie Lizenz, Beschreibung oder Tests – finden Entwickler im Repository.

Anzeige
Anzeige

Ein dezentrales Repository

Dass Deno einzelne Moduldateien über die vollständige URL importiert und direkt im Quellcode speichert, hat eine wichtige Konsequenz: Die Module lassen sich auf jedem Server im ­Internet speichern. Ein zentrales Module-Repository wie npm ist nicht ­nötig. Es ist eines der wichtigsten architektonischen ­Ziele von Deno, dass Nutzer für die Modulspeicherung nicht von ­einer privaten Plattform beziehungsweise einem Unternehmen abhängig sind. Es ist aber auch eine der umstrittensten Entscheidungen. Kritiker sagen nämlich, dass Deno auf diese Weise einen viel größeren Nachteil schaffe: Die Gefahr steige, dass Module-Repositories nicht verfügbar sind – vor allem dann, wenn eine Anwendung Module von vielen verschiedenen Servern importiert. Deno löst dieses Problem mit dem Module-Caching-Mechanismus im ­globalen Verzeichnis. Deno lädt also die Abhängigkeiten nur einmal herunter und holt sie dann aus dem Verzeichnis mit Cache. Einzige Ausnahme: Ein Entwickler erzwingt den ­Download, ­indem er diesen Prozess manuell ungültig macht. Solange sich alle notwendigen Module im lokalen Cache befinden, benötigt Deno daher keine Internetverbindung, um das Programm auszuführen. Es gibt auch kein separates Tool zur Installation von Modulen wie npm:

deno run app.ts
Download https://deno.land/std/http/server.ts
Download https://deno.land/std/encoding/utf8.ts
Download https://deno.land/std/io/bufio.ts
Download https://deno.land/std/_util/assert.ts
Download https://deno.land/std/async/mod.ts
Download https://deno.land/std/http/_io.ts
...

Dazu kommt, dass Deno bei verteiltem Hosting von Modulen hilft und die Suche nach einer Bibliothek mit bestimmten Funktionen erleichtert, indem es Module logisch in mehrere Gruppen aufteilt:

Anzeige
Anzeige
  • In der ersten Gruppe befinden sich Bibliotheken mit wenigen Funktionen, die die Plattform zudem selbst enthält, ohne ­Module importieren zu müssen (vor allem Funktionen aus dem Namespace „Deno“).
  • Die zweite Gruppe enthält die Standardbibliothek. Dabei ­handelt es sich um eine Reihe von Modulen, die das Deno-­Entwicklerteam auf Kompatibilität und Qualität geprüft hat. ­Diese Module bieten Funktionen, die die meisten Anwendungen verwenden. Zum Beispiel, um mit Dateien zu arbeiten, eindeutige Identifikatoren zu erzeugen, Logging oder Datums­funktionen zu nutzen und Unit-Tests zu schreiben.
  • In der dritten Gruppe sind die Module von Drittanbietern, also alle anderen Module, die Programmierer entwickelt haben. Dank Deno lassen sie sich der Module-Liste auf der Website Deno.land hinzufügen und so leichter finden.

// standard library
import { v4 } from "https://deno.land/std/uuid/mod.ts";
// third-partymodule
import * asbcrypt from "https://deno.land/x/bcrypt/mod.ts";

Genau wie bei Node.js empfiehlt Deno kleine Module mit einer bestimmten Funktion.

Auch bei der Datensicherheit will Deno ­Schwachpunkte von Node.js beheben. Denn Node.js bietet – im Gegensatz zu ­JavaScript-Code, der im Browser läuft – keinen Schutz. Jedes ­installierte Node.js-Modul kann auf das gesamte lokale Datei­system zugreifen und beispielsweise eine Verbindung zu externen ­Servern herstellen. Von Zeit zu Zeit hört man von bösartigen ­Modulen, die im npm-Repository gefunden wurden und versuchten, Daten zu stehlen oder eine Backdoor zu installieren.

Anzeige
Anzeige

Deno will das durch einen von Webbrowsern bekannten ­Mechanismus verhindern: Es führt den Code in einer ­isolierten Umgebung, der Sandbox, aus und blockiert standardmäßig ­potenziell gefährliche Operationen. Um zum Beispiel eine ­lokale Datei oder Entwicklungsvariable zu lesen oder einen Netzwerkzugang zu erzielen, verwendet es beim Programmstart ein entsprechendes Flag. Dadurch erzeugt Deno einen zusätzlichen ­Sicherheitslayer:

deno run --allow-read=./sensitive-data --allow-net=www.internal-api.com app.ts

Deno soll so kompatibel wie möglich mit Webstandards sein, damit geschriebene Programme funktionieren, also höchstwahrscheinlich auch im Browser – eine Ausnahme stellen ­Funktionen dar, die nur vom Backend möglich sind, wie das Lesen und Schreiben von Dateien. Das globale Hauptobjekt in Deno ist das aus Browsern bekannte window und nicht global wie in Node.js. Weitere nativ unterstützte Funktionen sind unter anderem fetch, onload und addEventListener. Auf diese Weise sind in Deno geschriebene Programme auch ziemlich zukunftssicher, denn die Standards ändern sich nicht allzu oft. Niemand will schließlich die vielen Programme zum Erliegen bringen, die darauf basieren.

Anzeige
Anzeige

const handler = () => console.log(„Program loaded“); window.addEventListener(„load“, handler);

Und schließlich trägt Deno als komplett neu geschriebene Plattform keinen Ballast in Form von Callbacks mit sich, die ­einen ­großen Teil der Node.js-API ausmachen. Deno basiert auf ­Promises und dem async/await-Mechanismus, der auch auf der Haupt-Code-Ebene verfügbar ist.

const result = await fetch(„https://api.openweathermap.org“);

Anzeige
Anzeige

Fast jedes Unternehmen, das Node.js in der ­Produktionsversion verwendet, entwickelt seine Software mit TypeScript. Deno ­bietet hingegen einen TypeScript-Compiler, der TypeScript-Code automatisch in eine JavaScript-Version kompiliert. Da jeder TypeScript-Code gleichzeitig ein gültiger JavaScript-Code ist, können Programmierer den Code mithilfe von Deno auch schrittweise von JavaScript auf TypeScript umstellen.

class App {
private readonly title: string;
constructor(title: string) {
this.title=title;
}
}
new App("My App");

Jedes professionelle Programmierprojekt verwendet aber auch zusätzliche Werkzeuge, um beispielsweise automatisiert zu ­testen, Code zu formatieren oder eine Produktionsversion oder Dokumentation zu erstellen. Mit Node.js müssen Entwickler alle diese Tools manuell konfigurieren. Das ist oft komplizierter als die eigentliche Programmentwicklung. Die Anzahl und Vielfalt der Bibliotheken und Plugins führt dazu, dass viele Projekte ­ihren eigenen, einzigartigen Entwicklungsstack haben. Die Ein­arbeitung neuer Programmierer erleichtert das natürlich nicht gerade. Deno will diesen Prozess daher radikal vereinfachen und standardisieren. Deshalb hat es die Werkzeuge, die Auf­gaben wie die oben genannten automatisieren, bereits eingebaut. Wie bei anderen Deno-Funktionen auch sind diese ­Werkzeuge aber ­optional.

Deno in der Praxis

Wie Deno in der Praxis aussieht, demonstriert die folgende ein­fache Beispiel-Webanwendung. Sie zeigt das aktuelle Wetter für die jeweilige Stadt über eine externe API und gibt ­Informationen im Json-Format zurück. Eine Konfiguration zu Beginn ist nicht notwendig. Deno importiert Module ja direkt in den Code und bringt alle wichtigen Produktivitätswerkzeuge mit. Ent­wickler müssen hier – anders als bei Nodes.js – also keine Datei ­„package.json“ mit einer Projektbeschreibung erstellen oder die ­erforderlichen Module manuell installieren.

/ / load environment variables
import "https://deno.land/x/dotenv/load.ts";
import app from "./app.ts";

const APP_PORT= Number(Deno.env.get("APP_PORT"));
console.log('Listening on port ${APP_PORT}');

await app.listen({ port: APP_PORT});

Deno empfiehlt Entwicklern, mehrere Konventionen zu ver­wenden, um das Projektmanagement zu erleichtern. Dazu gehört etwa, dass sie eine Datei erstellen, in die sie alle externen Module importieren:

export { Application, Response, Router } from "https://deno.land/x/oak/mod.ts"; export {assertEquals}from"https://deno.land/std/testing/asserts.ts";
export { denock } from "https://deno.land/x/denock/mod.ts";

Daraufhin re-exportieren sie alle Module und importieren die Projektdateien aus dieser Datei und nicht direkt von externen Servern. So ist es beispielsweise viel einfacher, eine ­Modulversion zu aktualisieren, da das nicht bei allen Projektdateien geschehen muss. Zusätzlich bietet eine solche Datei Entwicklern einen Überblick über alle externen Abhängigkeiten der Anwendung.

Es gibt bereits mehrere Deno-Frameworks, mit denen sich Webanwendungen einfach erstellen lassen, beispiels­weise Rest-API. Einige von ihnen basieren auf Pendants aus der Node.js-Welt. Das Framework Oak fußt zum Beispiel auf dem Vorbild Koa:

import { Application, Router } from "./deps.ts";
import { WeatherController } from "./controller.ts";
const router = new Router();
router.get(„/city/:city“, WeatherController.getByCityName);
const app = new Application();
app.use(r out er .r out es());
app.use(router.allowedMethods());

Wie bei Node.js müssen Entwickler nach jeder Änderung der Quelldateien den Prozess neu starten. Zu Hilfe kommt hier das Pendant des aus Node.js bekannten Pakets nodemon, genannt denon: denon run -A src/server.ts:

[denon] v2.2.0
[denon] watching path(s): *.*
[denon] watching extensions: ts,tsx,js,jsx,json
[denon] starting 'deno run -A src/server.ts'
Listening on port 5000

Den von der API benötigten Schlüssel speichert Deno in der Umgebungsvariable und nicht direkt im Code. Um so eine ­Variable lesen und dann eine Abfrage senden zu können, muss ein in Deno geschriebenes Programm entsprechende Berechtigungen ­erhalten:

deno run --allow-net --allow-env --allow-read src/server.ts

Entwickler können das Flag-A verwenden, um sich die Arbeit zu vereinfachen – auch wenn das in der Produktionsumgebung ­natürlich keine gute Praxis ist. Mit Deno können sie auch eine Reihe von akzeptablen Adressen angeben. Hier eine Beispielliste:

deno run --allow-net=0.0.0.0,api.openweathermap.org --allow-env --allow-read src/ server.ts
Wie bereits erwähnt, bringt Deno auch ein Werkzeug zum automatischen Ausführen von Tests mit. Zudem enthält die Standardbibliothek ein Modul mit Assertions. Ein Beispieltest sieht daher folgendermaßen aus:
Deno.test({
name: "Get temperature, pressure and humidity",
async fn() {
const result = await getWeatherForCity("mannheim,de");
assertEquals(result, { temperature: 25, humidity: 40, pressure: 1020 });
},
});

Das Ausführen von Tests ist sehr einfach:

deno test

running 1 tests
test Get temperature, pressure and humidity ... ok (5ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (5ms)

Mock-Objekte können Entwickler für das Senden von externen API-Anfragen mit dem Modul denock ausführen:

denock({
method: "GET",
protocol: "https"“,
host: "api.openweathermap.org",
path: "/data/2.5/weather?q=mannheim,de&appid=undefined&units=metric",
replyStatus: 200,
responseBody: responseBodyStub,
})

Um Projektdateien automatisiert zu prüfen und zu formatieren, können Entwickler folgenden Befehl nutzen – aber Achtung: Der Linter ist noch nicht production-ready;, weshalb das Flag ;--unstable notwendig ist.

denofmt
deno lint --unstable

Dank dem eingebauten Module-Packer können Entwickler die ­gesamte Produktionsversion in einer Datei erstellen. Der Beispielbefehl dafür lautet:

deno bundle src/server.ts > dist/ bundle.js

Die so erzeugte Datei kann das Programm zum Beispiel auf dem Produktionsserver ausführen oder im Browser laden. Deno unterstützt außerdem das Format „JSDoc“ und kann eine Projektdokumentation generieren:

/**
* Get weather for given city
* @param {string} city
* @return {object} current temperature, humidity and pressure
*/
export async function getWeatherForCity(city: string) {…}

Fazit

Die erste stabile Version von Deno ist überraschend reif und sehr komfortabel. Node.js-Entwickler – und hier vor ­allem die TypeScript-Fans – sollten diese neue Alternative ­daher ­ausprobieren. Aufgrund der noch geringen Anzahl von ­Modulen ist es ­jedoch noch etwas zu früh, Deno als Hauptplattform für größere kommerzielle Projekte zu wählen. Langfristig wird Deno Node.js sicherlich nicht ersetzen. Dazu ist Node.js viel zu gut und ­populär und de facto ein Standard in der JavaScript-Welt.

Doch die neue Entwicklungsplattform wird sicher den ­gleichen Weg nehmen, den auch schon Node.js beschritten hat: Dank ihrer Vorteile und ihrer hohen Produktivität werden ­immer mehr Open-Source- und Startup-­Projekte die Plattform einsetzen – bis sie schließlich auch die Mainstream-Firmen ­erreichen wird.

Mehr zu diesem Thema
Fast fertig!

Bitte klicke auf den Link in der Bestätigungsmail, um deine Anmeldung abzuschließen.

Du willst noch weitere Infos zum Newsletter? Jetzt mehr erfahren

Anzeige
Anzeige
Ein Kommentar
Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Zero

Deno behalte ich schon länger im Auge. Die Fokussierung auf native JS-Befehle anstelle CommonJS und die native async/await-Struktur gefallen mir besonders.
Noch fehlen Deno aber zu viele mir wichtige Features: Insbesondere HTTP/2, Cluster und Streams. Streams sollen zwar schon irgendwie möglich sein, aber die Dokumentation ist ziemlich wirr und unübersichtlich, im Vergleich zu der von Node.js.
Außerdem gefällt mir die feste Einbindung von Typescript nicht, sowie die Module im Web.
Langfristig könnte Deno insgesamt dennoch mein persönlicher Favorit zwischen beiden Runtimes werden.

Antworten

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!
Hallo und herzlich willkommen bei t3n!

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team von mehr als 75 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Schon jetzt und im Namen der gesamten t3n-Crew: vielen Dank für deine Unterstützung! 🙌

Deine t3n-Crew

Anleitung zur Deaktivierung
Artikel merken

Bitte melde dich an, um diesen Artikel in deiner persönlichen Merkliste auf t3n zu speichern.

Jetzt registrieren und merken

Du hast schon einen t3n-Account? Hier anmelden

oder
Auf Mastodon teilen

Gib die URL deiner Mastodon-Instanz ein, um den Artikel zu teilen.

Anzeige
Anzeige