Aufwärmen · Aufgabe 1 von 7
Aufwärmen: Die package.json eines Projekts enthält das Skript unten. Welcher Befehl führt es im Projektordner aus?
{
"scripts": {
"start": "node src/server.js"
}
}// B1.1 · ca. 32 Min. · Einstieg
Nach dieser Lektion richten Sie ein kleines Node.js-Projekt ein, das im beabsichtigten Modulsystem läuft, seine Konfiguration ohne Typfehler aus einer .env-Datei liest und mit einer klaren Meldung und einem Exit-Code ungleich 0 scheitert.
Lektion 1 von 5 in B1 Node ausführen und Projektgrundlagen
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
{
"scripts": {
"start": "node src/server.js"
}
}Vorhersagen · Aufgabe 2 von 7
// .env
// PORT=3000
// DEBUG=false
// app.mjs
const port = process.env.PORT;
console.log(port + 1);
console.log(process.env.DEBUG ? 'debug on' : 'debug off');Üben · Aufgabe 3 von 7
Üben · Aufgabe 4 von 7
// index.js
const fs = require('node:fs');
console.log(typeof fs.readFileSync);Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
// teaser.mjs
import { readFile } from 'node:fs/promises';
async function loadConfig() {
try {
return readFile('missing.json', 'utf8');
} catch {
return '{}';
}
}
console.log(await loadConfig());Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Dieses Programm lädt .env selbst mit process.loadEnvFile, das tut, was node --env-file=.env main.js täte, und läuft deshalb mit einfachem node main.js. Die erste Zeile zeigt die Falle: PORT kommt als String an, also hängt + 1 nur an, und der String "false" ist truthy. Dann wandelt es jeden Wert einmal um, am Rand des Programms, und liest eine optionale features.json mit dem await im try, sodass die fehlende Datei im catch landet und das Programm auf {} ausweicht.
main.js
import {loadEnvFile} from 'node:process';
import {readFile} from 'node:fs/promises';
// Does what node --env-file=.env main.js does: each line becomes a string in process.env.
loadEnvFile('.env');
console.log(typeof process.env.PORT, process.env.PORT + 1, Boolean(process.env.DEBUG));
// Convert once, at the edge of the program.
const port = Number(process.env.PORT);
const debug = process.env.DEBUG === 'true';
console.log({port, debug});
// Await inside try, so a missing file lands in catch.
let features = {};
try {
features = JSON.parse(await readFile('features.json', 'utf8'));
} catch (error) {
if (error.code !== 'ENOENT') throw error;
console.log('features.json:', error.code, '- using {}');
}
console.log({port, debug, features});
.env
PORT=8080
DEBUG=false
Ausführen mit
node main.jsAusgabe
string 80801 true
{ port: 8080, debug: false }
features.json: ENOENT - using {}
{ port: 8080, debug: false, features: {} }Übung 1 von 2
Schreiben Sie readConfig(env). env ist ein Objekt aus Strings, wie process.env nach node --env-file=.env. Geben Sie {port, debug} zurück: port ist PORT als Zahl, 3000, wenn PORT nicht gesetzt ist; debug ist nur dann true, wenn DEBUG genau "true" ist. Werfen Sie einen Error, wenn PORT keine ganze Zahl von 1 bis 65535 ist. In einem echten Programm rufen Sie readConfig(process.env) auf; die Tests übergeben stattdessen einfache Objekte, deshalb läuft das auch im Browser.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
env.PORT ?? '3000' nimmt 3000 nur, wenn PORT gar nicht gesetzt ist.
Number("abc") ist NaN, und das ist keine ganze Zahl: Number.isInteger(port) erkennt es.
Vergleichen Sie den String: env.DEBUG === 'true'. Alles andere, auch "false", ergibt false.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// env is an object of strings, like process.env.
export function readConfig(env) {
const port = Number(env.PORT ?? '3000');
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new Error('PORT must be a whole number from 1 to 65535, got "' + env.PORT + '"');
}
return {port, debug: env.DEBUG === 'true'};
}
console.log(readConfig({PORT: '8080', DEBUG: 'false'}));
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// env is an object of strings, like process.env.
export function readConfig(env) {
return {port: env.PORT, debug: env.DEBUG};
}
console.log(readConfig({PORT: '8080', DEBUG: 'false'}));
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {readConfig} from './main.js';
test('PORT="8080" wird zur Zahl 8080', () => {
const got = readConfig({PORT: '8080'}).port;
assert.equal(got, 8080, `port war ${JSON.stringify(got)}`);
});
test('DEBUG="false" ergibt false und DEBUG="true" ergibt true', () => {
assert.equal(readConfig({DEBUG: 'false'}).debug, false, 'DEBUG="false" sollte den Wahrheitswert false ergeben');
assert.equal(readConfig({DEBUG: 'true'}).debug, true, 'DEBUG="true" sollte den Wahrheitswert true ergeben');
});
test('ohne PORT ist port 3000', () => {
const got = readConfig({}).port;
assert.equal(got, 3000, `port war ${JSON.stringify(got)}`);
});
test('PORT="abc" oder "70000" wirft einen Error', () => {
assert.throws(() => readConfig({PORT: 'abc'}), Error, 'PORT="abc" sollte werfen');
assert.throws(() => readConfig({PORT: '70000'}), Error, 'PORT="70000" sollte werfen');
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 2 von 2
Schreiben Sie loadJson(path, fallback) mit readFile aus node:fs/promises. Die Funktion liefert das geparste JSON der Datei. Existiert die Datei nicht (error.code ist ENOENT), liefert sie stattdessen fallback. Jeder andere Fehler, etwa kaputtes JSON, muss weiterhin geworfen werden. Die letzten Zeilen von main.js fangen diesen Fehler schon ab, geben ihn aus und setzen process.exitCode = 1. Starten Sie es mit node main.js und prüfen Sie es mit node --test.
Diese Übung braucht Node.js auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
Setzen Sie nur den Aufruf von readFile in try, mit await, damit seine Ablehnung in Ihrem catch landet.
Prüfen Sie im catch error.code === 'ENOENT' und geben Sie fallback zurück; sonst werfen Sie error erneut.
Parsen Sie nach dem try: Dann wird ein SyntaxError aus JSON.parse nicht für eine fehlende Datei gehalten.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import {readFile} from 'node:fs/promises';
// The parsed JSON in the file, or fallback when the file does not exist.
export async function loadJson(path, fallback) {
let text;
try {
text = await readFile(path, 'utf8');
} catch (error) {
if (error.code === 'ENOENT') return fallback;
throw error;
}
return JSON.parse(text);
}
try {
console.log(await loadJson('settings.json', {}));
} catch (error) {
console.error('Cannot read settings:', error.message);
process.exitCode = 1;
}
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
import {readFile} from 'node:fs/promises';
// The parsed JSON in the file, or fallback when the file does not exist.
export async function loadJson(path, fallback) {
const text = await readFile(path, 'utf8');
return JSON.parse(text);
}
try {
console.log(await loadJson('settings.json', {}));
} catch (error) {
console.error('Cannot read settings:', error.message);
process.exitCode = 1;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {loadJson} from './main.js';
test('liest und parst settings.json', async () => {
const got = await loadJson('settings.json', {});
assert.deepEqual(got, {theme: 'dark'}, `loadJson("settings.json") lieferte ${JSON.stringify(got)}`);
});
test('eine fehlende Datei ergibt den fallback', async () => {
const got = await loadJson('missing.json', {theme: 'light'});
assert.deepEqual(got, {theme: 'light'}, `loadJson("missing.json", fallback) lieferte ${JSON.stringify(got)}`);
});
test('kaputtes JSON wirft weiterhin einen SyntaxError', async () => {
await assert.rejects(loadJson('broken.json', {}), SyntaxError, 'loadJson("broken.json") sollte mit einem SyntaxError scheitern, nicht fallback liefern');
});
settings.json
{"theme": "dark"}
broken.json
{"theme": }
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenconst fs = require('node:fs');
console.log(typeof fs.readFileSync);
Was Node.js ausgibt
ReferenceError: require is not defined in ES module scope, you can use import insteadWarum, und die Lösung
Die package.json des Projekts sagt "type": "module", also ist main.js ein ES-Modul, und ES-Module haben kein require. Schreiben Sie stattdessen import fs from 'node:fs'; oder benennen Sie eine Datei, die CommonJS bleiben muss, in .cjs um.
import {join} from 'node:path';
console.log(join(__dirname, 'config.json'));
Was Node.js ausgibt
ReferenceError: __dirname is not defined in ES module scopeWarum, und die Lösung
__dirname und __filename gehören zu CommonJS; ES-Module haben sie nicht. Nehmen Sie import.meta.dirname und import.meta.filename, die seit v24.0.0 stabil sind: join(import.meta.dirname, 'config.json').
import {readFile} from 'node:fs/promises';
async function loadConfig() {
try {
return readFile('config.json', 'utf8');
} catch {
return '{}';
}
}
console.log(await loadConfig());
Was Node.js ausgibt
Error: ENOENT: no such file or directory, open 'config.json'Warum, und die Lösung
return reicht das Promise aus dem try hinaus, bevor es abgelehnt wird, also sieht der catch-Block den Fehler nie, und die Ablehnung beendet das Programm mit Exit-Code 1. Schreiben Sie return await readFile(...): Dann wird die Ablehnung im try ausgelöst, und der catch-Block liefert '{}'.
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.