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

Seite 3: Third-Party-Module in Deno

Inhaltsverzeichnis

Ein Grund für den Erfolg von Node.js war sein Paketmanager npm, der sich zum Quasistandard in der JavaScript-Welt entwickelt hat. Ryan Dahl hatte sich bei Deno bewusst gegen einen Paketmanager entschieden. Zu Beginn der Entwicklung war es nicht möglich, npm-Pakete in einer Deno-Applikation zu installieren. Dahl hatte diese Entscheidung getroffen, um sich im Design der neuen Plattform nicht von bestehenden Lösungen und etablierten Mustern in eine falsche Richtung leiten zu lassen. Das Modulsystem von Deno unterstützt daher das Laden von Modulen entfernter Quellen.

Die populärste Quelle für Deno-Module ist der Hosting-Dienst deno.land/x. Dieser Dienst lädt den Quellcode von GitHub und stellt die Module zur Verfügung. Prinzipiell kann jeder Autor eines GitHub-Projekts das Projekt auf deno.land/x publizieren. Die Module url_parse und querystring sind nur zwei Beispiele von knapp 4000 Modulen des Hosting-Dienstes. Sie umfassen einfache Hilfsbibliotheken wie die beiden im Beispiel eingesetzten, aber auch umfangreichere Bibliotheken und Frameworks wie unter anderem opine, eine Express.js-Portierung für Deno. Listing 4 erweitert den bisherigen Webserver der Standardbibliothek um eine dynamische Komponente.

Listing 4: Verwendung externer Module

import { serve } from 'https://deno.land/std@0.125.0/http/server.ts';
import { urlParse } from 'https://deno.land/x/url_parse@1.1.0/mod.ts';
import * as queryString from 'https://deno.land/x/querystring@v1.0.2/mod.js';
const port = 8080;
serve(
  (request: Request) => {
    let name = 'World';
    const { search } = urlParse(request.url);
    const query = queryString.parse(search);
    if (query && query.name && typeof query.name === 'string') {
      name = query.name;
    }
    return new Response(`Hello ${name}!`, { status: 200 });
  },
  { port }
);
console.log(`Server running on http://localhost:${port}/`);

Die urlParse-Funktion aus dem url_parse-Modul schlüsselt die URL als Objekt aus, die als Zeichenkette in der Anfrage vorliegt. Die queryString-Funktion aus dem querystring-Modul wiederum wandelt den Query-Teil der URL in ein Objekt um. Existiert hier eine Option name, nutzt der Webserver sie für eine Begrüßung. Eine Anfrage auf dem lokalen Host 8080 mit der Option "Jane" als Namen (http://localhost:8080/?name=Jane) führt im Webbrowser zu einer Ausgabe von "Hello Jane!".

Deno behandelt die Module auf deno.land/x ähnlich wie die Standardbibliothek. Enthält die URL des Moduls keine explizite Versionsnummer wie im Beispiel, nutzt Deno die neueste Version. In diesem Fall gibt Deno bei der Ausführung auf der Konsole eine Warnung aus, dass implizit die neueste Version zum Einsatz kommt, und gibt außerdem die verwendete Versionsnummer des Moduls an.

Ryan Dahl hat sich bereits zu Beginn der Deno-Entwicklung klar von npm als Paketmanager distanziert. Aus diesem Grund enthält eine Deno-Applikation in der Regel auch keine package.json-Datei und kein node_modules-Verzeichnis. Es ist dennoch möglich, npm-Pakete in Deno zu verwenden. Diese Pakete sollten keine Abhängigkeit auf den Kern von Node.js haben, da diese Schnittstellen in Deno so nicht existieren. Listing 5 zeigt am Beispiel von lodash wie ein n-Paket auch in Deno verwendet werden kann.

Listing 5: npm-Paketen verwenden

import _ from 'https://esm.sh/lodash';
const result = _.sum([1, 2, 3, 4, 5]);
console.log(result); // 15

Listing 5 nutzt das Content Delivery Network (CDN) esm.sh, ein Repository, das npm-Pakete als ES-Module zur Verfügung stellt. esm.sh nutzt esbuild, um die meist als CommonJS-Module vorliegenden Pakete in ES Module umzuwandeln. Solche Module kann Deno laden und in eine Applikation integrieren. Der Code des Beispiels importiert lodash und nutzt die sum-Funktion, um die Zahlen eins bis fünf zu summieren und das Ergebnis auf der Konsole auszugeben.

Lodash ist ein typisches Beispiel für eine Bibliothek, die keine Probleme verursacht, da sie sowohl im Browser als auch in Node.js ausführbar ist. Seit Version 1.15 bietet Deno jedoch einen Kompatibilitätsmodus für Node.js an, der sich mit der Option —compat aktivieren lässt. In dem Modus stellt Deno die globalen Variablen von Node.js zur Verfügung. Außerdem funktionieren darin die Import-Statements und require-Aufrufe für Node.js-Kernmodule. Die Standardbibliothek stellt mit std/node Polyfills (Code-Bausteine) für die Kernmodule von Node.js zur Verfügung. Derzeit implementiert Deno noch nicht alle Module. Das Deno-Repository bei GitHub bietet eine Liste der Module und den aktuellen Entwicklungsstand. Listing 6 zeigt am Beispiel einer Express-Applikation, wie der Kompatibilitätsmodus aussieht. Damit das Beispiel funktioniert, ist es notwendig, Express mit dem Kommando npm install express lokal zu installieren.

Listing 6: Node.js-Applikationen in Deno ausführen

const express = require('express');
const app = express();
app.get('/', (request, response) => {
  response.send('Hello World!');
});
app.listen(8080, () =>
  console.log('Server is listening to http://localhost:8080')
);

Damit Deno die Applikation korrekt ausführen kann, sind einige Kommandozeilenoptionen erforderlich. --unstable und --compat schalten den Kompatibilitätsmodus ein. Mit --allow-net darf Express eine Netzwerkverbindung öffnen. --allow-read ist für das CommonJS-Modulsystem erforderlich, und --allow-env benötigt Deno für den Zugriff auf die Umgebungskonfiguration. Zusammen ergibt sich daraus die Kommandozeile: deno run --unstable --compat --allow-net --allow-read --allow-env server.js.