Abschnitt 2 · Lektion 4
Pfade mit path
Ein Pfad ist am Ende nur eine Zeichenkette, und deshalb ist die Versuchung groß, ihn selbst
zusammenzusetzen. ordner + "/" + datei sieht harmlos aus und funktioniert auf dem eigenen Rechner
auch. Das Problem kommt später, an einem Ort, an dem du es nicht mehr mit dieser Zeile in Verbindung
bringst.
Was beim Aneinanderkleben schiefgeht
import path from "node:path";
const ordner = "daten/";
const datei = "/liste.json";
console.log("Selbst gebaut:", ordner + datei);
console.log("Mit join:", path.join(ordner, datei));
console.log("Eine Ebene hoch:", path.join("daten", "..", "bilder", "logo.png")); Im Beispiel endet der Ordner auf einen Schrägstrich und die Datei fängt mit einem an. Zusammengeklebt ergibt das zwei Schrägstriche mitten im Pfad. Unter Linux geht das oft noch gut, in einer Fehlermeldung sieht es dann seltsam aus, und beim Vergleich zweier Pfade sind es plötzlich zwei verschiedene Zeichenketten.
path.join räumt das auf. Es setzt genau einen Trenner zwischen die Teile, wirft doppelte weg und
löst .. gleich mit auf.
Dazu kommt der Punkt, wegen dem es node:path überhaupt gibt: Windows trennt Pfade mit einem
Backslash, Linux und macOS mit einem Schrägstrich. Wenn du den Trenner selbst tippst, entscheidest
du dich für ein Betriebssystem. Wenn du path.join benutzt, entscheidet Node, und zwar dort, wo das
Programm gerade läuft. Der Server ist fast immer ein anderer als dein Arbeitsrechner.
Einen Pfad wieder auseinandernehmen
Der umgekehrte Weg kommt genauso oft vor: Aus einem vollständigen Pfad willst du nur einen Teil.
import path from "node:path";
const pfad = "/vercel/sandbox/lern/daten/liste.json";
console.log("Ordner:", path.dirname(pfad));
console.log("Datei:", path.basename(pfad));
console.log("Name:", path.basename(pfad, ".json"));
console.log("Endung:", path.extname(pfad)); dirname gibt den Ordner, basename die Datei, extname die Endung. basename nimmt optional
noch die Endung als zweites Argument entgegen und schneidet sie ab, was praktisch ist, wenn du aus
liste.json den Namen liste brauchst.
Auch hier gilt: Das ließe sich mit split("/") und slice nachbauen. Aber die eingebaute Fassung
kennt die Sonderfälle, an die du in dem Moment nicht denkst, und sie liest sich in einem halben Jahr
noch von selbst.
Der Unterschied, an dem Programme umfallen
Jetzt der wichtigste Teil dieser Lektion. Es gibt zwei Orte, und sie sehen sich zum Verwechseln ähnlich.
process.cwd() ist das Arbeitsverzeichnis. Also der Ordner, in dem jemand stand, als er den
Befehl abgeschickt hat. Er hat nichts damit zu tun, wo deine Datei liegt.
import.meta.dirname ist der Ordner deiner Datei. In CommonJS heißt derselbe Wert __dirname.
Solange du dein Programm aus seinem eigenen Ordner startest, sind beide gleich, und genau deshalb fällt der Unterschied auf dem eigenen Rechner monatelang nicht auf.
import path from "node:path";
console.log("Arbeitsverzeichnis:", process.cwd());
console.log("Verzeichnis der Datei:", import.meta.dirname);
console.log("Falsch:", path.join(process.cwd(), "daten", "liste.json"));
console.log("Richtig:", path.join(import.meta.dirname, "daten", "liste.json")); Hier liegt die Datei in app/, gestartet wurde aber eine Ebene darüber mit node app/index.mjs. Und
schon zeigen die beiden Zeilen auf verschiedene Orte. Die Variante mit process.cwd() sucht die
Daten neben dem Startort, findet dort nichts und meldet ENOENT, obwohl die Datei existiert.
Genau so entsteht der Klassiker: Auf deinem Rechner läuft alles, auf dem Server nicht. Dort startet nämlich ein Dienst dein Programm, und der steht in irgendeinem Verzeichnis, das mit deinem Projekt nichts zu tun hat.
Die Faustregel
Gehört die Datei zu deinem Programm, geh von import.meta.dirname aus. Vorlagen,
Konfigurationsdateien, mitgelieferte Daten liegen neben dem Code und wandern mit ihm mit.
Gibt der Benutzer den Pfad an, ist process.cwd() richtig. Wer ein Kommandozeilenwerkzeug mit
werkzeug bericht.txt aufruft, meint die Datei in seinem aktuellen Ordner, nicht eine neben dem
Werkzeug. Abschnitt 4 baut genau so ein Werkzeug.
Für den Rest gibt es noch path.resolve. Es macht aus allem, was du hineingibst, einen absoluten
Pfad, und zwar ausgehend vom Arbeitsverzeichnis. Praktisch, wenn du Benutzereingaben absichern
willst, und Abschnitt 15 kommt darauf zurück.
Zum Mitnehmen
process.cwd() ist der Ort, an dem der Befehl abgesetzt wurde. import.meta.dirname ist der Ort, an dem deine Datei liegt. Das sind zwei verschiedene Dinge.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.