23 Punkte von GN⁺ 2025-08-04 | 3 Kommentare | Auf WhatsApp teilen
  • Die Node.js-Entwicklungsumgebung hat in den vergangenen Jahren einen grundlegenden Wandel durchlaufen – insbesondere in Bezug auf hohe Kompatibilität mit Webstandards und den Ausbau integrierter Funktionen
  • Durch die Einführung moderner Modulsysteme und asynchroner Muster wie ESM (ES Modules), dem Präfix node: und Top-level await lässt sich Code intuitiver und sicherer schreiben
  • Mit Fetch API, AbortController und Web Streams sinkt die Abhängigkeit von externen Bibliotheken, da viele Funktionen direkt über integrierte APIs bereitgestellt werden
  • Integrierte Entwicklungswerkzeuge wie Test Runner, Watch-Modus und Unterstützung für Umgebungsdateien verbessern Komfort und Produktivität deutlich
  • Mit ausgebauter Sicherheits- und Deployment-Infrastruktur – von Berechtigungskontrolle über Diagnostics Channels bis hin zur Verteilung als einzelne ausführbare Datei – entwickelt sich modernes Node.js zu einer professionellen und vielseitigen Plattform

Wandel und Weiterentwicklung von Node.js

  • Node.js entwickelt sich von seiner ursprünglichen Callback-lastigen, CommonJS-zentrierten Struktur hin zu einer stärker standardisierten Entwicklungsumgebung
  • Dieser Wandel ist nicht nur oberflächlicher Natur, sondern steht für einen Paradigmenwechsel in der Entwicklung von serverseitigem JavaScript insgesamt

1. Modulsystem: Standardisierung von ES Modules

  • CommonJS war lange Zeit der etablierte Ansatz in Node.js, bringt aber Einschränkungen bei statischer Analyse, Tree Shaking und der Übereinstimmung mit Webstandards mit sich
  • ESM (ES Modules) hat sich als neuer Standard in Node.js etabliert
    • Verwendung der Syntax import und export
    • Einführung des Präfixes node:, um integrierte Module explizit zu kennzeichnen
      • Beispiel: import { readFile } from 'node:fs/promises'
      • Die Unterscheidung zwischen eingebauten Modulen und npm-Paketen wird dadurch klarer
  • Durch die Unterstützung von Top-level await kann await auch auf der obersten Modulebene verwendet werden
    • Ein Wrapper mit einer sofort ausgeführten asynchronen Funktion ist nicht mehr nötig
    • Der Code wird geradliniger und leichter verständlich

2. Integrierte Web-APIs: weniger externe Abhängigkeiten

  • Die Fetch API ist in Node.js integriert, sodass HTTP-Anfragen ohne externe Abhängigkeiten wie Axios oder node-fetch möglich sind
  • Fetch unterstützt standardmäßig Timeouts und Abbruchfunktionen (AbortSignal.timeout())
    • Konsistente Fehlerbehandlung ist damit auch ohne separate Timeout-Bibliothek möglich
  • Mit AbortController lassen sich Abbruchmuster für verschiedene asynchrone Aufgaben wie Datei- oder Netzwerkoperationen umsetzen
    • Das bietet einen standardisierten Ansatz für Benutzerunterbrechungen oder Zeitüberschreitungen

3. Integriertes Testen: professionelle Testumgebung

  • Statt externer Frameworks wie Jest oder Mocha genügt für die meisten Anforderungen der integrierte Test Runner von Node.js
    • Mit node:test und node:assert lassen sich Tests intuitiv schreiben
  • Komfortfunktionen wie Watch-Modus für Tests und Coverage-Reporting sind integriert
    • Tests werden bei jeder Codeänderung automatisch erneut ausgeführt
    • Ab Node.js 20 steht experimentelle Coverage-Funktionalität zur Verfügung

4. Weiterentwickelte asynchrone Muster

  • async/await ist weit verbreitet, doch modernes Node.js legt zusätzlich Wert auf parallele Ausführung und ausgefeilte Muster für die Fehlerbehandlung
    • Mit Promise.all() lassen sich Aufgaben parallel ausführen; Fehler können in einem einzelnen try/catch inklusive Kontextinformationen verarbeitet werden
  • Durch den Einsatz von AsyncIterator werden sequentielle Ereignisverarbeitung und Flow Control einfacher

5. Erweiterte Stream-Funktionen und Kompatibilität mit Webstandards

  • Die Stream-API ist inzwischen mit dem Webstandard (Streams API) kompatibel
    • Mit Readable.fromWeb und Readable.toWeb lassen sich Streams zwischen Node.js und Browser konvertieren
  • Mit der Funktion pipeline (Promise-basiert) können intuitive und sichere Stream-Pipelines aufgebaut werden

6. Worker Threads: parallele Verarbeitung CPU-intensiver Aufgaben

  • Mit Worker Threads lässt sich die Begrenzung des einzelnen JS-Threads überwinden und Multi-Core-Hardware nutzen
  • Komplexe Berechnungen oder die Verarbeitung großer Datenmengen sind möglich, ohne den Main Loop zu blockieren

7. Revolution der Developer Experience

  • Mit dem Flag --watch werden Codeänderungen erkannt und Prozesse automatisch neu gestartet – ganz ohne nodemon
  • Mit dem Flag --env-file wird dotenv überflüssig; Umgebungsvariablen sind sofort nutzbar
  • Die Konfiguration der Entwicklungsumgebung wird einfacher und schneller

8. Integrierte Sicherheit und Performance-Monitoring

  • Mit dem experimentellen Permission Model lassen sich Anwendungsberechtigungen für Datei- oder Netzwerkzugriffe einschränken
    • Das erleichtert die Umsetzung des Prinzips der geringsten Rechte und die Einhaltung von Sicherheitsvorgaben
  • Mit perf_hooks sind integrierte Performance-Messungen sowie automatische Analyse und Protokollierung langsamer Operationen möglich

9. Modernisierung von Deployment und Packaging

  • Mit Unterstützung für SEA (Single Executable Application) lassen sich Node.js und die Anwendung als einzelne Binärdatei verteilen
    • Deployment und Installation werden auch in Umgebungen ohne vorhandenes Node.js deutlich einfacher

10. Moderne Fehlerbehandlung und Diagnostik

  • Strukturierte Fehlerklassen enthalten umfangreichen Kontext und Diagnoseinformationen und ermöglichen die konsistente Weitergabe von Fehlerobjekten
  • Mit diagnostics_channel lassen sich benutzerdefinierte, ereignisbasierte Diagnosedaten übertragen und Monitoring automatisieren

11. Fortschritte bei Modulauflösung und Paketverwaltung

  • Mit Import Maps lassen sich interne Pfade in separaten Namespaces verwalten
    • Das erleichtert die Trennung interner Module und spätere Refactorings
  • Mit dynamischem import können Code und Code-Splitting zur Laufzeit abhängig von Umgebung oder Konfiguration geladen werden

Kernaussagen und Ausblick

  • Für Node.js sind Konformität mit Webstandards, maximale Nutzung integrierter Werkzeuge und die Übernahme moderner asynchroner Muster entscheidend
  • Mit Worker Threads und anderen Hochleistungsmechanismen für Parallelisierung sowie Diagnose- und Sicherheitsfunktionen entwickelt sich Node.js zu einer Plattform für professionelle Anforderungen
  • Neue Funktionen wie die Verteilung als einzelne ausführbare Datei und Modul-Namespaces erhöhen die Betriebseffizienz deutlich
  • Diese Muster lassen sich schrittweise einführen und bleiben dabei mit bestehendem Code kompatibel
  • Auch nach 2025 wird sich Node.js stetig weiterentwickeln; die hier vorgestellten modernen Muster dürften die Grundlage für zukunftsorientierte Anwendungen bilden

3 Kommentare

 
sanori 2025-08-07

Als ich anfing, ein Projekt mit Deno zu erstellen, dachte ich: „Wow, so etwas geht auch?“ – und anscheinend verändert sich node.js auf ähnliche Weise.

 
dnltmdwhd 2025-08-05

Oh, jetzt braucht man kein axios mehr, das geht direkt mit fetch.

 
GN⁺ 2025-08-04
Hacker-News-Kommentare
  • Die größte Veränderung ist nicht ESM, sondern dass fetch und AbortController in Node integriert sind; dadurch konnte ich axios oder node-fetch entfernen, auch die Größe von Lambda-Bundles wurde kleiner und die Cold-Start-Latenz um etwa 100 ms reduziert. Wer aus Gewohnheit immer npm i axios ausführt, sollte mit den Node-Releases 2025 damit aufhören.
    • Für den gesamten Stack bevorzuge ich ts-rest, das sowohl API-Aufrufe als auch Validierung abdeckt. Unter den auf zod/JSON Schema basierenden Bibliotheken ist es am leichtgewichtigsten und bietet zugleich robuste Type Safety. Man kann auch den gewünschten HTTP-Client einstecken (unter Bun und der Node-Engine wähle ich fastify). Zwar gibt es Overhead, aber es ist die Wahl absolut wert, weil sich Type Safety in die Compile-Phase verlagern lässt. Mich würde interessieren, ob jemand bessere Alternativen oder andere Gedanken dazu hat; ich habe so viel gesucht, wie ich finden konnte, und nur ts-rest konnte zugleich Leichtgewichtigkeit und Type Safety bieten.
    • Die fetch-Syntax und die zusätzliche Arbeit mit Ausnahmebehandlung wie await response.json gefallen mir nicht besonders. Mit axios ist es viel intuitiver. Auch im Beispielcode kann man mit axios einfach response.data verarbeiten, während man bei fetch den Status selbst prüfen und dann JSON parsen muss, was umständlicher ist.
    • Als Autor einer Bibliothek war die Einführung von ESM deutlich schwieriger und schmerzhafter, aber es war ein ebenso lohnendes Upgrade. fetch selbst ist großartig, aber dank ESM konnte ich wirklich sehr viel gewinnen.
    • node fetch ist viel einfacher und schlichter als axios, deshalb gefällt es mir besser. Ich wusste gar nicht, dass manche Leute immer noch axios verwenden.
    • Ich freue mich sehr auf Undici als integrierte Request-Bibliothek, siehe offizielle Undici-Website.
  • Man kann es jetzt auch so ausführen, dass Zugriffsrechte auf Dateisystem oder Netzwerk eingeschränkt werden
    # 파일 시스템 접근 제한 예시
    node --experimental-permission \
      --allow-fs-read=./data --allow-fs-write=./logs app.js
    
    # 네트워크 제한 예시
    node --experimental-permission \
      --allow-net=api.example.com app.js
    
    Scheint von Deno inspiriert zu sein, wirklich eine hervorragende Funktion, Deno-Dokumentation zur Permission-Funktion
  • Auch ohne Installation von chalk oder picocolors ist nun direktes Text-Styling möglich
    const { styleText } = require('node:util');
    
    Siehe offizielle styleText-Dokumentation
  • Ich habe mehrere Dinge kennengelernt, die sich sofort einsetzen lassen
    1. In Node ist jetzt ein eingebautes Testsystem enthalten, sodass man nicht unbedingt jest verwenden muss
    2. Node hat jetzt auch eine integrierte Watch-Funktion, sodass nodemon ebenfalls nicht mehr nötig ist
    • Ich bevorzuge immer noch jest, weil man jest-extended verwenden kann.
    • Ich halte das eingebaute Testsystem von Node für qualitativ schwach. Wenn man es ein paar Wochen wirklich benutzt, versteht man warum, und selbst wenn man Issues meldet, interessiert das das Node-Team kaum.
  • Laut Matteo Collina verwendet Node fetch intern undici-fetch. Weil WHATWG Web Streams erzeugt werden müssen, ist es grundsätzlich langsamer als die request-Methode von undici,
    das erwähnte YouTube-Video,
    Blog zur Funktionsweise von Undici
    • Für Interessierte: Benchmarks gibt es hier. Ich habe kürzlich auf einem MacBook Pro mit M3 Max sowohl lokal als auch im Netzwerk getestet; lokal war undici am besten, im Netzwerk lieferte jedoch Axios schnellere Ergebnisse. Den genauen Grund kenne ich nicht, aber meine Erfahrungen mit undici in den letzten anderthalb Jahren waren ausgezeichnet. In Produktion kann man es absolut stabil einsetzen, aber wenn man maximale Performance herausholen will, muss man je nach Situation gut abwägen.
  • Dank des nativen TypeScript-Transpilers von Node sinkt für TS-Nutzer die Komplexität deutlich.
    • Genau genommen werden nur Typen entfernt, es ist also kein echtes Transpiling; Dinge wie TS-enum funktionieren nicht richtig.
    • Für den produktiven Einsatz reicht es noch nicht. enum ist mir egal, aber lokale Datei-Imports ohne Erweiterung funktionieren nicht, und Class Properties lassen sich auch nicht im Konstruktor definieren.
    • Das Flag --experimental-strip-types ist inzwischen ebenfalls nicht mehr nötig.
  • Solche neuen Funktionen entdeckt man oft eher zufällig. Es ist ähnlich wie im Browser, wo man nur diffus denkt: „Das ist eben neu.“ Früher, als ich nur C# gemacht habe, war ich richtig begeistert, wenn ich über neue Sprachfeatures gelesen habe. Heute ist es, weil ich mehrere Sprachen parallel nutze, nicht leicht, auch nur einer einzelnen Sprache konsequent zu folgen. Meist ist es zufälliges Lernen über Blogs oder das Umfeld.
    • Ich interessiere mich sehr für Neuigkeiten rund um Node (V8) und lese deshalb alle zwei bis drei Monate die Release Notes, um solche Funktionen mitzunehmen. Manchmal lese ich auch ECMA proposals; ich hoffe sehr, dass der Pipeline-Operator aufgenommen wird.
  • Ich hatte mich eine Zeit lang vom Node-Ökosystem entfernt und finde es jetzt, wo ich wieder darauf schaue, wirklich spannend, wie viele neue Funktionen dazugekommen sind. Ich denke, das liegt auch daran, dass Deno und Bun den Markt aufgemischt haben und das Node-Team dadurch noch einmal deutlich mehr Gas gegeben hat.
  • Node entwickelt sich im Wettbewerb mit Bun.js, Deno und anderen zunehmend zu einem ernstzunehmenden Akteur. Dieser gegenseitige Wettbewerb ist positiv für die Weiterentwicklung von JS-Runtimes.
    • Die Veränderungen sind langsam, aber sicher und erfreulich. Trotzdem vermisse ich noch immer Buns $-Shell-Funktion; es ist wirklich praktisch, JS wie ein Skript zu verwenden, und ich möchte nicht zwei Runtimes zusammen auf einen Server packen.
  • Ähnlich wie im Browser lassen sich neue Funktionen in Node meiner Ansicht nach in zwei Kategorien einteilen
    1. völlig neue Technologien
    2. eine darübergelegte „Politur“-Schicht auf bereits vorhandenen Funktionen
      Es ist auch interessant zu sehen, welcher Seite die Leute mehr Gewicht geben.
    • Was für den einen nur eine „Politur-Schicht“ ist, kann für jemand anderen wiederum Ergonomie bedeuten.