Arbeiten mit Umgebungsvariablen in Node.js

February 10, 2022
Autor:in:
Prüfer:in:

Mit minimalem Programmieraufwand können Sie eine Node.js-Anwendung direkt vom Terminal aus starten und mittels Programmable SMS von Twilio Textnachrichten senden und empfangen.

Grundlagen von Umgebungsvariablen in Node.js

Node.js ist eines der meistdiskutierten Frameworks in der Webentwickler-Community seit Rails. Obwohl noch jung, hat es sich bereits als schnelle, hochskalierbare und effiziente Umgebung bewährt. Das liegt vor allem an der zugrundeliegenden Struktur eines ereignisgesteuerten, nicht blockierenden E/A-Modells.

In Kombination mit Twilio können Sie damit in nur wenigen Schritten Telefonie-Apps programmieren. Wenn Sie aber beispielsweise eine SMS senden möchten, müssen Sie Node.js und das Node.js-Modul von Twilio installieren.

Eine weitere hervorragende Eigenschaft der Node.js-Sprache (und seiner Module) ist, dass sie mit Umgebungsvariablen kompatibel ist, die auch viele Cloud-Anbieter (wie Heroku, Azure, AWS, Now.sh etc.) nutzen. Dadurch eröffnen sich vielfältige Möglichkeiten, um einzelne Bereiche Ihrer Node.js-Anwendung zu konfigurieren. Während Hosts also eine PORT-Variable setzen, die vorgibt, an welchem Port der Server lauschen soll, können Module je nach Wert der Variable NODE_ENV ein anderes Verhalten zeigen (z. B. Protokollierung).

In diesem Blogbeitrag zeigen wir einige Tricks und Tools für die Arbeit mit Umgebungsvariablen in Node.js.

Zuallererst benötigen Sie eine Node.js-Umgebung. Dann erfahren Sie die grundlegenden Schritte zum Einrichten von Node.js für Twilio auf einem Mac-Computer. Dazu wird npm auf einem Mac installiert und die Umgebung für ein Twilio-Projekt vorbereitet.

So prüfen Sie, ob Node.js bereits installiert ist

Um zu prüfen, ob Node.js bereits auf Ihrem Computer installiert ist, öffnen Sie ein Terminal und führen Sie folgenden Befehl aus:

node -v

Ist Node.js noch nicht installiert, gehen Sie die folgenden Schritte zur Installation durch: 

  1. Gehen Sie zur Download-Seite von Node.js.
  2. Klicken Sie auf die Option „Macintosh Installer“, um Node.js für macOS herunterzuladen.
  3. Führen Sie das heruntergeladene .pkg-Installationsprogramm für Node.js aus.
  4. Akzeptieren Sie im Verlauf der Installation die Lizenzvereinbarung, wählen Sie einen Speicherort und authentifizieren Sie sich.

Nach Abschluss der Installation können Sie sich noch vergewissern, dass Node.js „node -v“ auf Ihrem Terminal ausführt. Sie sollten die oben gezeigte aktuelle Versionsnummer erhalten. 

Wenn die Version nicht angezeigt wird, müssen Sie Ihr Terminal eventuell neu starten.

Um sicherzustellen, dass die Installation korrekt ist, führen Sie „npm -v“ aus. Daraufhin sollte die Version ausgegeben werden.

Als nächstes folgt die Installation des Twilio-Moduls auf Ihrem Mac, damit die Node.js-Skripte im aktuellen Verzeichnis es verwenden können.

Explizites Laden von Variablen aus .env-Dateien 

Die Umgebungsvariablen sind sofort in Node.js verfügbar. Wenn der Node.js-Prozess startet, erhalten Sie automatisch Zugriff auf alle vorhandenen Umgebungsvariablen, indem ein env-Objekt innerhalb des globalen process-Objekts erstellt wird. 

Wenn Sie einen Blick auf das Objekt werfen wollen, führen Sie den Node.js REPL mit „node“ in der Befehlszeile aus und geben Folgendes ein:

console.log(process.env);

Dieser Code sollte alle Umgebungsvariablen ausgeben, die diesem Node.js-Prozess zur Verfügung stehen. Sie können auf eine bestimmte Variable genauso zugreifen wie auf jede andere Eigenschaft eines Objekts:

console.log('The value of PORT is:', process.env.PORT);

Ihnen ist sicherlich aufgefallen, dass der Wert für PORT auf Ihrem Computer nicht festgelegt ist. Cloud-Hosts wie Heroku oder Azure verwenden die PORT-Variable jedoch, um mitzuteilen, auf welchem Port der Server lauschen soll, damit das Routing richtig funktioniert. Wenn Sie also das nächste Mal einen Webserver einrichten, können Sie den zu überwachenden Port bestimmen, indem Sie zuerst PORT prüfen und ihm anschließend einen Standardwert zuweisen:

const app = require('http').createServer((req, res) => res.send('Ahoy!'));
const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Die hervorgehobene Zeile übernimmt den PORT-Wert oder nutzt standardmäßig 3000 als Port, wenn nichts anderes angegeben ist. Führen Sie den Code aus, indem Sie ihn in einer Datei wie server.js speichern und dann Folgendes ausführen:

node server.js

Jetzt sollte die Meldung „Server is listening on port 3000“ (Server lauscht auf Port 3000) erscheinen. Halten Sie den Server mit Ctrl+C an und starten Sie ihn mit dem folgenden Befehl neu:

PORT=9999 node server.js

Die Meldung sollte jetzt lauten: „Server is listening on port 9999“ (Server lauscht auf Port 9999). Das bedeutet, dass die Variable PORT für diese Ausführung temporär von PORT =9999 vor den Node gesetzt wurde. 

Da process.env ein normales Objekt ist, können Sie die Werte setzen bzw. überschreiben:

process.env.MY_VARIABLE = 'ahoy';

Der Code oben setzt oder überschreibt den Wert von MY_VARIABLE. Beachten Sie jedoch, dass dieser Wert nur während der Ausführung dieses Node.js-Prozesses gesetzt wird und nur in von diesem Prozess spawnenden untergeordneten Prozessen verfügbar ist. Vermeiden Sie nach Möglichkeit, Umgebungsvariablen zu überschreiben, und initialisieren Sie einfach eine Konfigurationsvariable, wie im PORT-Beispiel gezeigt.

Wenn Sie auf einem Computer an mehreren Node.js-Projekten arbeiten, kann es sein, dass sich die Namen von Umgebungsvariablen überlappen. Zum Beispiel könnten verschiedene Messaging-Apps verschiedene Twilio Messaging Service SIDs benötigen, die jedoch beide TWILIO_MESSAGE_SERVICE_SID heißen. Um eine projektspezifische Konfiguration zu erreichen, empfiehlt sich die Verwendung von .env-Dateien. Über diese Dateien können Sie eine Vielzahl von unterschiedlichen Umgebungsvariablen und deren Werte festlegen.

In der Regel sind diese Dateien in der Quellcodeverwaltung unerwünscht. Fügen Sie daher beim Erstellen einfach .env zu Ihrer gitignore-Datei hinzu. In vielen Twilio-Demo-Anwendungen sind .env.example-Dateien zu sehen, die Sie nach .env kopieren können, um die Werte dann selbst festzulegen. Eine .env.example -Datei oder eine ähnliche Datei ist sehr praktisch, um eine Vorlagendatei mit anderen am Projekt beteiligten Personen zu teilen.

Wie werden Werte aus dieser Datei geladen? Die einfachste Möglichkeit ist die Verwendung eines npm-Moduls namens dotenv. Installieren Sie das Modul über npm:

npm install dotenv --save

Fügen Sie anschließend die folgende Zeile in Ihrer Eingabedatei ganz oben ein:

require('dotenv').config();

Dieser Code lädt automatisch die .env-Datei im Stammverzeichnis Ihres Projekts und initialisiert die Werte. Voreingestellte Variablen werden dabei ignoriert. In Ihrer Produktionsumgebung sollten Sie allerdings niemals .env-Dateien verwenden. Setzen Sie die Werte lieber direkt auf dem entsprechenden Host. Umschließen Sie dafür Ihre Ladeanweisung mit einer if-Anweisung:

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

Mit diesem Code wird die .env-Datei nur dann geladen, wenn der Server nicht im Produktionsmodus gestartet wurde.

Das wollen wir uns jetzt in Aktion ansehen. Installieren Sie dotenv wie oben gezeigt in einem Verzeichnis. Erstellen Sie anschließend eine dotenv-example.js-Datei im gleichen Verzeichnis und fügen Sie die folgenden Zeilen darin ein:

console.log('No value for FOO yet:', process.env.FOO);

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

console.log('Now the value for FOO is:', process.env.FOO);

Erstellen Sie anschließend im gleichen Verzeichnis eine Datei namens .env mit diesem Inhalt:

FOO=bar

Führen Sie das Skript aus:

node dotenv-example.js

Die Ausgabe sollte wie folgt aussehen:

No value for FOO yet: undefined
Now the value for FOO is: bar

Wie Sie sehen, wurde der Wert mittels dotenv geladen und definiert. Wenn Sie den gleichen Befehl erneut ausführen und dabei NODE_ENV auf production setzen, werden Sie sehen, dass er undefiniert („undefined“) bleibt.

NODE_ENV=production node dotenv-example.js

Die Ausgabe sollte jetzt wie folgt aussehen:

No value for FOO yet: undefined
Now the value for FOO is: undefined

Wenn Sie Ihren eigentlichen Code nicht ändern möchten, können Sie auch das Argument -r von Node verwenden, um dotenv beim Ausführen des Skripts zu laden. Ändern Sie dafür Ihre dotenv-example.js-Datei wie folgt:

console.log('The value for FOO is:', process.env.FOO);

Führen Sie die Datei jetzt zunächst ganz normal aus:

node dotenv-example.js

Das Skript muss ausgeben, dass der Wert für FOO aktuell undefined ist. Führen Sie es jetzt mit dem entsprechenden Flag aus, um dotenv anzufordern:

node -r dotenv/config dotenv-example.js

Damit ist FOO jetzt auf bar gesetzt, da die .env-Datei geladen wurde. Weitere Informationen zu dotenv finden Sie in der zugehörigen Dokumentation.

Alternative Möglichkeit zum Laden von .env-Dateien

Es gibt noch ein anderes Modul auf Basis von dotenv, mit dem sich Umgebungsvariablen bequemer laden lassen. Das Ergebnis ist node-env-run oder nodenv. Dabei handelt es sich um ein Befehlszeilen-Tool, das eine .env-Datei lädt, die Werte mit dotenv initialisiert und dann Ihr Skript ausführt.

Sie können es global installieren, die Empfehlung lautet allerdings, dieses Tool nur für Entwicklungszwecke und lokal für das Projekt zu verwenden. Führen Sie für die Installation Folgendes aus:

npm install node-env-run --save-dev

Erstellen Sie anschließend eine nodenv-example.js-Datei und fügen Sie diesen Code darin ein:

console.log('The value for FOO is:', process.env.FOO);

Da es sich nur um eine Anwendungslogik handelt, müssen wir hier nichts anfordern. Versuchen Sie zuerst eine Ausführung mit „node“:

node nodenv-example.js

Dieser ausgeführte Code sollte „The value for FOO is: undefined“ (Wert für FOO: undefined) ausgeben. Verwenden Sie jetzt, node-env-run, indem Sie Folgendes ausführen:

node_modules/.bin/nodenv nodenv-example.js

Das Ergebnis sollte „The value for FOO is: bar“ (Wert für FOO: bar) lauten, da die .env-Datei geladen wurde.

Diese vorhandenen Werte kann node-env-run überschreiben. Um dies in Aktion zu sehen, führen Sie zunächst den folgenden Befehl aus:

FOO=foo node_modules/.bin/nodenv nodenv-example.js

Die Befehlszeilenausgabe sollte Folgendes enthalten: „The value for FOO is: foo.“ (Wert für FOO: foo). Wenn Sie jetzt den Force-Modus aktivieren, können Sie die bestehenden Werte überschreiben:

FOO=foo node_modules/.bin/nodenv --force nodenv.js

Wie am Anfang sollten Sie wieder bei „The value for FOO is: bar“ landen.

Bei regelmäßiger Nutzung können Sie dieses Tool in ein npm-Skript packen. Fügen Sie es dazu wie folgt zum package.json hinzu:

{
  "name": "twilio-blog",
  "version": "1.0.0",
  "description": "",
  "main": "nodenv-example.js",
  "scripts": {
    "start": "node .",
    "start:dev": "nodenv -f ."
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "node-env-run": "^2.0.1"
  }
}

Dann können Sie einfach Folgendes ausführen:

npm run start:dev

Weitere Informationen zu node-env-run finden Sie in der zugehörigen Dokumentation.

Umgebungsvariablen und npm-Skripte

In manchen Szenarien ist es sinnvoll, den Wert einer Umgebungsvariable zu überprüfen, bevor Sie die Node.js-Anwendung in npm-Skripten öffnen. Das gilt zum Beispiel, wenn Sie in einer Entwicklungsumgebung „node-env-run“ verwenden möchten, in der Produktionsumgebung aber einfach „node“. Nutzen Sie dafür das Tool if-env . Führen Sie für die Installation Folgendes aus:

npm install if-env --save

Installieren Sie das Tool aber nicht als „dev dependency“, da Sie es auch in der Produktion benötigen werden.

Jetzt passen Sie einfach Ihre npm-Skripte in Ihrer package.json-Datei an:

 "scripts": {
    "start": "if-env NODE_ENV=production ?? npm run start:prod || npm run start:dev",
    "start:dev": "nodenv -f .",
    "start:prod": "node ."
  }

Dieses Skript führt jetzt „npm run start:prod“ und anschließend „node“ aus. Wenn der Wert für NODE_ENV „production“ lautet, kann es „npm run start:dev“ and anschließend „nodenv -f“ ausführen. Die Vorgehensweise ist bei jeder Umgebungsvariablen dieselbe.

Probieren Sie es aus, indem Sie Folgendes ausführen:

# should output "The value of FOO is: bar"
npm start
# should output "The value of FOO is: undefined"
NODE_ENV=production npm start

Weitere Informationen zu if-env finden Sie in der zugehörigen Dokumentation.

So installieren Sie npm auf einem Mac

Normalerweise wird npm als Teil der oben genannten Installation mitinstalliert. Ob dem so ist, können Sie mithilfe des npm-Befehls im Terminal prüfen. Wenn es installiert wurde, sehen Sie eine Liste der Verwendungsmöglichkeiten. Wenn nicht, führen Sie Folgendes aus, um npm zu installieren: 

sudo apt install npm

Debugging in Node.js

Als Nächstes geht es ums Debugging. Eine Strategie, die mir immer sehr geholfen hat, ist die DEBUG-Umgebungsvariable, um ausführliche Protokolle für eine Reihe von Modulen zu erhalten. Nehmen Sie zum Beispiel einen einfachen express-Server:

const app = require('express')();
const bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

app.post('/', (req, res, next) => {
console.log(req);
});

app.listen(3000);

Starten Sie ihn mit der DEBUG-Variable auf *:

DEBUG=* node server.js

Dann erhalten Sie ein umfangreiches Protokoll, das ungefähr so aussieht:

Der Clou dabei ist ein leichtgewichtiges Modul namens debug. Initialisieren Sie es ganz einfach mit einem „namespace“, wenn Sie es nutzen möchten. Danach können Sie in diesem Namensraum protokollieren. Wenn jemand die Ausgabe anzeigen möchte, muss er nur den Namensraum in der DEBUG -Variable aktivieren. In diesem Fall verwendet „express“ zahlreiche untergeordnete Namensräume. Wenn Sie alles vom express-Router haben möchten, müssen Sie nur DEBUG mit dem entsprechenden Platzhalter setzen:

DEBUG=express:router* node server.js

Wenn Sie debug in Ihrem Modul verwenden möchten, müssen Sie es zunächst installieren:

npm install debug --save

Wenden Sie es anschließend wie folgt an:

const debug = require('debug')('myApp:someComponent');

debug('Here is a pretty object %o', { someObject: true });

Weitere Informationen zu debug finden Sie in der zugehörigen Dokumentation.

Nutzen Sie sämtliche Node.js-Umgebungsvariablen in Node.js mit Twilio

Was wir hier gezeigt haben, ist nur ein kleiner Ausschnitt dessen, was Sie mit Umgebungsvariablen und den verschiedenen Tools machen können. Nachdem Sie einen kleinen Einblick in Umgebungsvariablen in Node.js bekommen haben, sollten Sie sich jetzt die Node.js-Schnellstarts wie SMS-Schnellstart von Twilio anschauen! Legen Sie kostenlos los.