Abschnitt 4 · Lektion 2
Umgebungsvariablen
Argumente sind für das, was sich bei jedem Aufruf ändert. Für das, was sich pro Ort ändert, gibt es einen zweiten Weg.
Dein Programm soll auf drei Rechnern laufen: auf deinem, auf einem Testsystem und in der Produktion. Überall gilt eine andere Datenbankadresse, ein anderer Port, ein anderer Schlüssel für einen fremden Dienst. Der Code soll trotzdem überall derselbe sein, Zeichen für Zeichen. Sonst hast du drei Fassungen, und eine davon ist immer die falsche.
Das Fach, in das die Umgebung ihre Werte legt
process.env ist ein Objekt mit allem, was die Umgebung deinem Prozess mitgegeben hat. Auf der
Kommandozeile schreibst du die Werte vor den Befehl:
PORT=8080 node start.mjs
const port = Number(process.env.PORT) || 3000;
const umgebung = process.env.NODE_ENV ?? "development";
console.log("Port:", port);
console.log("Typ des Rohwerts:", typeof process.env.PORT);
console.log("Umgebung:", umgebung); Genau so läuft dieses Beispiel auch, mit PORT=8080 davor; im Terminal steht die Befehlszeile
über der Ausgabe. Zwei Dinge stehen darin, und beide sind wichtig.
Erstens: typeof process.env.PORT ist string, nicht number. Dazu gleich mehr.
Zweitens: || 3000 fängt den Fall ab, dass niemand einen Port gesetzt hat. Das ist kein Notbehelf,
sondern gehört dazu. Ein Programm, das ohne gesetzte Umgebung gar nicht erst startet, ist auf dem
eigenen Rechner mühsam.
const port = Number(process.env.PORT) || 3000;
const umgebung = process.env.NODE_ENV ?? "development";
console.log("Port:", port);
console.log("Typ des Rohwerts:", typeof process.env.PORT);
console.log("Umgebung:", umgebung); Es ist dieselbe Datei, unverändert, nur ohne PORT=8080 davor. Eine nicht gesetzte Variable ist
undefined, und dafür springt der Standardwert ein. Beim NODE_ENV darüber siehst du dasselbe
schon im ersten Beispiel: Gesetzt ist dort nur der Port, also steht bei der Umgebung
development.
Im Terminal kannst du beide Fassungen selbst nebeneinanderstellen. Starte die Sandbox und tipp
erst node start.mjs, dann PORT=8080 NODE_ENV=production node start.mjs. Die Werte stehen vor dem
Befehl und gelten nur für ihn, der nächste Aufruf weiß nichts mehr davon.
Warum jeder Wert Text ist
Die Umgebung kennt keine Datentypen. Sie reicht Zeichenketten durch, und was du damit machst, ist
deine Sache. PORT=8080 kommt als "8080" an, nicht als 8080.
Bei Zahlen fällt das schnell auf, weil Number(...) sich anbietet. Bei Wahrheitswerten fällt es
gar nicht auf, und das ist die Falle.
const rohwert = process.env.DEBUG;
console.log("Rohwert:", rohwert);
console.log("Typ:", typeof rohwert);
console.log("Falsch geprueft:", rohwert ? "an" : "aus");
console.log("Richtig geprueft:", rohwert === "true" ? "an" : "aus"); Lies den dritten Fall noch einmal. DEBUG steht auf false, und die Prüfung sagt trotzdem an.
Der Grund ist keine Merkwürdigkeit von Node, sondern eine Regel von JavaScript: In einem if ist
jede Zeichenkette wahr, außer der leeren. "false" ist eine Zeichenkette mit fünf Zeichen, also
wahr.
Die Regel dazu lautet: vergleiche Umgebungswerte immer ausdrücklich. process.env.DEBUG === "true"
sagt genau, was du meinst. if (process.env.DEBUG) sagt nur, ob überhaupt etwas gesetzt ist, und
das ist so gut wie nie die Frage.
Die .env-Datei
Sechs Variablen vor jedem Befehl zu tippen hält niemand durch. Deshalb legt man sie in eine Datei, eine Zeile je Wert, und Node liest sie beim Start ein:
node --env-file=.env start.mjs
Das ist eingebaut, du brauchst kein Paket dafür. Früher war dotenv dafür Standard, und in
bestehenden Projekten wirst du es weiter finden.
Jetzt der Satz, auf den es in diesem Abschnitt am meisten ankommt:
Die .env gehört in die .gitignore. Immer. Ohne Ausnahme.
In dieser Datei stehen Zugangsdaten, und ein Repository ist dafür der falsche Ort. Es ist auch nicht
damit getan, sie später wieder herauszunehmen: Was einmal committet war, steht in der Historie, und
wer den Schlüssel abgreifen will, sucht genau dort. Abschnitt 15 geht darauf ein, wie man damit
umgeht, wenn es doch passiert ist. Lektion 5.4 zeigt, wie so eine .gitignore aussieht.
Was stattdessen ins Repository gehört, ist eine .env.example mit denselben Schlüsseln und leeren
oder erfundenen Werten. Sie ist die Liste dessen, was gesetzt sein muss, und die kann jeder sehen.
Wo der Standardwert hingehört
Ein Standardwert steht an der Stelle, an der die Variable gelesen wird, und zwar genau einmal. Wenn
process.env.PORT an vier Stellen in deinem Code auftaucht, hast du vier Gelegenheiten, den
Standard unterschiedlich zu schreiben.
Der übliche Weg ist eine kleine Datei, die alle Werte einmal einliest, prüft und als fertiges Objekt
weitergibt. Der restliche Code fragt dann dieses Objekt und nie mehr process.env. Lektion 18.4 baut
so eine Datei, und sie hat einen angenehmen Nebeneffekt: Fehlt eine Pflichtvariable, merkt das dein
Programm beim Start und nicht mitten in der Nacht bei der ersten Anfrage.
Zum Mitnehmen
Jeder Wert in process.env ist Text. Auch „8080“, auch „false“. Und der Text „false“ ist in einem if wahr.
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.