Aufwärmen · Aufgabe 1 von 7
// B2.4 · ca. 34 Min. · Einstieg
import/export, import.meta.dirname, eingebaute node:-Module
Nach dieser Lektion können Sie ein Programm in ES-Module aufteilen, die teilen, was sie exportieren, Module und JSON-Dateien laden, wenn Sie sie brauchen, und Dateien neben einem Modul finden.
Danach können Sie
- Benannte und Default-Exporte schreiben und sie mit einem vollständigen relativen Specifier importieren
- Module mit import() und JSON mit with {type: "json"} laden und Live Bindings vorhersagen
- import.meta.dirname und import.meta.filename nutzen und wissen, welche eingebauten Module node: brauchen
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen. main.js importiert count und increment aus counter.js und ruft increment zweimal auf. Was gibt node main.js aus?
// counter.js export let count = 0; export function increment() { count += 1; } // main.js import {count, increment} from "./counter.js"; increment(); increment(); console.log(count);Üben · Aufgabe 3 von 7
cart.js liegt neben main.js. Ergänzen Sie den Rest des Specifiers, damit Node.js die Datei findet.
import {add} from "./cart____";import {add} from "./cart";Üben · Aufgabe 4 von 7
cart.js exportiert add und count mit Namen und total als Default. Ordnen Sie jedem Import zu, was er main.js liefert.
Üben · Aufgabe 5 von 7
Die Datei /home/ada/shop/src/main.js enthält diese Zeile. Sie sind in /home/ada/shop und führen node src/main.js aus. Was gibt sie aus?
console.log(import.meta.dirname);Denksport · Aufgabe 6 von 7
Knobelaufgabe. main.js lädt greet.js mit import(). Was gibt es aus?
// greet.js export default function greet(name) { return "Hello, " + name + "!"; } // main.js const greeting = await import("./greet.js"); console.log(typeof greeting, typeof greeting.default);Anwenden · Aufgabe 7 von 7
Mini-Aufgabe. Schreiben Sie in einem Ordner, dessen package.json "type": "module" setzt, lib/money.js mit einem benannten Export CURRENCY und einem Default-Export money(amount), der 3.5 als 3.50 EUR formatiert. Legen Sie settings.json mit einem Shopnamen an. Importieren Sie in main.js beides aus lib/money.js, importieren Sie settings.json mit seinem Import-Attribut und geben Sie den Shopnamen und money(3.5) aus. Geben Sie mit node:path basename(import.meta.filename) aus. Laden Sie lib/money.js zum Schluss noch einmal mit import() und prüfen Sie, dass der Default dieselbe Funktion ist.
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
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
Ein Warenkorb in einem eigenen Modul
cart.js führt eine Anzahl und eine Liste von Artikeln und exportiert add und count mit Namen und total als Default. main.js importiert alle drei, legt zwei Artikel an und liest count davor und danach: Der Import folgt der Variablen in cart.js. Auch format.js hat einen Default-Export, den main.js money nennt. Zum Schluss zeigt import * as cart alle Exporte von cart.js in einem Objekt. Es läuft auch im Browser.
main.js
import total, {add, count} from "./cart.js";
import money from "./format.js";
import * as cart from "./cart.js";
console.log("items at start:", count);
add("tea", 3.5);
add("cake", 4);
console.log("items now:", count);
console.log("total:", money(total()));
console.log("cart.js exports:", Object.keys(cart).join(", "));
console.log("same count:", cart.count === count);
cart.js
// A tiny shopping cart. Its state lives in this module.
export let count = 0;
const items = [];
export function add(name, price) {
items.push({name, price});
count += 1;
}
export default function total() {
return items.reduce((sum, item) => sum + item.price, 0);
}
format.js
export default function format(amount) {
return amount.toFixed(2) + " EUR";
}
Ausführen mit
node main.jsAusgabe
items at start: 0
items now: 2
total: 7.50 EUR
cart.js exports: add, count, default
same count: true- count ist 0, dann 2: main.js liest die lebendige Variable von cart.js, keine Kopie.
- format.js nennt seine Funktion format, aber main.js importiert den Default-Export als money: Den Namen wählt der Importeur.
- Das Modulobjekt enthält den Default-Export unter dem Schlüssel default, neben den benannten.
Ändern und ausführen
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.
Übungen
Übung 1 von 3
Benannte und Default-Exporte
rates.js ist vorgegeben: Es exportiert STANDARD (0.19) und REDUCED (0.07) mit Namen und round2 als Default. Importieren Sie in main.js alle drei. Exportieren Sie dann als Default eine Funktion gross(net, reduced = false), die die Steuer zum passenden Satz aufschlägt und mit round2 rundet, sodass gross(10) 11.9 ist und gross(10, true) 10.7. Exportieren Sie außerdem mit Namen rates, ein Objekt {standard, reduced} mit beiden Sätzen.
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.
Hinweise
Hinweis 1
Eine Zeile importiert beide Arten: import round2, {STANDARD, REDUCED} from "./rates.js";
Hinweis 2
net * (1 + STANDARD) ist der Bruttobetrag; übergeben Sie ihn an round2.
Hinweis 3
Wählen Sie den Satz mit reduced ? REDUCED : STANDARD und bauen Sie rates als {standard: STANDARD, reduced: REDUCED}.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import round2, {STANDARD, REDUCED} from "./rates.js";
export default function gross(net, reduced = false) {
return round2(net * (1 + (reduced ? REDUCED : STANDARD)));
}
export const rates = {standard: STANDARD, reduced: REDUCED};
Auf dem eigenen Computer ausführen
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 round2 (default) and STANDARD, REDUCED (named) from ./rates.js here.
export default function gross(net, reduced = false) {
return net;
}
export const rates = {};
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import * as main from './main.js';
test('der Default-Export ist eine Funktion', () => {
assert.equal(typeof main.default, 'function', `der Default-Export ist ${typeof main.default}`);
});
test('schlägt den Regelsatz auf und rundet auf Cent', () => {
assert.equal(main.default(10), 11.9, `gross(10) lieferte ${main.default(10)}`);
assert.equal(main.default(19.99), 23.79, `gross(19.99) lieferte ${main.default(19.99)}`);
});
test('schlägt auf Wunsch den ermäßigten Satz auf', () => {
assert.equal(main.default(10, true), 10.7, `gross(10, true) lieferte ${main.default(10, true)}`);
});
test('exportiert rates mit Namen', () => {
assert.deepEqual(main.rates, {standard: 0.19, reduced: 0.07}, `rates ist ${JSON.stringify(main.rates)}`);
});
rates.js
// Tax rates as fractions, and a helper that rounds to cents.
export const STANDARD = 0.19;
export const REDUCED = 0.07;
export default function round2(amount) {
return Math.round(amount * 100) / 100;
}
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 3
Ein Modul nach Namen laden
greet-en.js und greet-de.js haben je einen Default-Export greet(name). Schreiben Sie in main.js die async-Funktion greet(lang, name): Sie lädt "./greet-" + lang + ".js" mit import() und gibt zurück, was der Default-Export dieses Moduls für name liefert, also ist greet("de", "Ada") gleich "Hallo, Ada!". Gibt es kein solches Modul, lehnt import() ab: Fangen Sie das ab und geben Sie "No greeting for " + lang zurück. Prüfen Sie die Tests mit node --test.
Diese Übung braucht Node.js auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
Hinweise
Hinweis 1
import() nimmt jeden String, also können Sie den Specifier zusammensetzen: "./greet-" + lang + ".js".
Hinweis 2
Warten Sie mit await auf import(); die Funktion liegt im Ergebnis unter .default.
Hinweis 3
Setzen Sie den Import in try/catch: Ein fehlendes Modul lässt das erwartete import() werfen.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// Loads ./greet-<lang>.js when it is needed and greets name with its default export.
export async function greet(lang, name) {
try {
const module = await import("./greet-" + lang + ".js");
return module.default(name);
} catch {
return "No greeting for " + lang;
}
}
Auf dem eigenen Computer ausführen
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
// Loads ./greet-<lang>.js when it is needed and greets name with its default export.
export async function greet(lang, name) {
return "";
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {greet} from './main.js';
test('grüßt auf Englisch mit greet-en.js', async () => {
const got = await greet('en', 'Ada');
assert.equal(got, 'Hello, Ada!', `greet('en', 'Ada') lieferte ${JSON.stringify(got)}`);
});
test('grüßt auf Deutsch mit greet-de.js', async () => {
const got = await greet('de', 'Ada');
assert.equal(got, 'Hallo, Ada!', `greet('de', 'Ada') lieferte ${JSON.stringify(got)}`);
});
test('sagt es, wenn es kein Modul für die Sprache gibt', async () => {
const got = await greet('fr', 'Ada');
assert.equal(got, 'No greeting for fr', `greet('fr', 'Ada') lieferte ${JSON.stringify(got)}`);
});
greet-en.js
export default function greet(name) {
return "Hello, " + name + "!";
}
greet-de.js
export default function greet(name) {
return "Hallo, " + name + "!";
}
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 3 von 3
JSON-Einstellungen neben dem Modul
settings.json liegt neben main.js. Importieren Sie die Datei mit ihrem Import-Attribut und schreiben Sie zwei Funktionen. banner() liefert Name und Version aus der Datei, getrennt durch ein Leerzeichen: "shop 1.4.2". settingsPath() liefert den absoluten Pfad von settings.json, gebaut mit join aus node:path und import.meta.dirname, sodass er stimmt, egal aus welchem Ordner Sie node starten. Prüfen Sie die Tests mit node --test.
Diese Übung braucht Node.js auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
Hinweise
Hinweis 1
import settings from "./settings.json" with {type: "json"}; liefert Ihnen das geparste Objekt.
Hinweis 2
settings.name + " " + settings.version ergibt das Banner.
Hinweis 3
import {join} from "node:path"; dann join(import.meta.dirname, "settings.json").
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import {join} from "node:path";
import settings from "./settings.json" with {type: "json"};
export function banner() {
return settings.name + " " + settings.version;
}
export function settingsPath() {
return join(import.meta.dirname, "settings.json");
}
Auf dem eigenen Computer ausführen
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 settings.json (it needs an import attribute) and join from node:path here.
export function banner() {
return "";
}
export function settingsPath() {
return "";
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {banner, settingsPath} from './main.js';
test('banner() zeigt Name und Version aus settings.json', () => {
assert.equal(banner(), 'shop 1.4.2', `banner() lieferte ${JSON.stringify(banner())}`);
});
test('settingsPath() ist settings.json im Ordner von main.js', () => {
const got = settingsPath();
const folder = import.meta.dirname;
assert.ok(got.startsWith(folder) && got.endsWith('settings.json') && got.length === folder.length + 'settings.json'.length + 1, `settingsPath() lieferte ${JSON.stringify(got)}; erwartet: settings.json in ${folder}`);
});
settings.json
{"name": "shop", "version": "1.4.2"}
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 herunterladenHäufige Fehler
Die Endung weglassen
import {add} from "./cart";
add("tea", 3.5);
Was Node.js ausgibt
Error [ERR_MODULE_NOT_FOUND]: Cannot find moduleWarum, und die Lösung
In einem ES-Modul nimmt Node.js einen relativen Specifier wörtlich: Es sucht eine Datei namens cart, findet keine und schreibt Did you mean to import "./cart.js"? unter den Fehler. Schreiben Sie den vollen Namen, import {add} from "./cart.js". Dasselbe gilt für Ordner: import "./lib/index.js", nicht "./lib".
Klammern um einen Default-Export
import {round2} from "./rates.js";
console.log(round2(12.345));
Was Node.js ausgibt
SyntaxError: The requested module './rates.js' does not provide an export named 'round2'Warum, und die Lösung
round2 ist der Default-Export von rates.js. Klammern verlangen einen benannten Export, und rates.js hat mit Namen nur STANDARD und REDUCED. Importieren Sie den Default ohne Klammern, import round2 from "./rates.js", oder beides zugleich: import round2, {STANDARD} from "./rates.js". Die Prüfung geschieht, bevor eine Zeile von main.js läuft.
JSON ohne sein Attribut importieren
import settings from "./settings.json";
console.log(settings.name);
Was Node.js ausgibt
TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: ModuleWarum, und die Lösung
Die volle Meldung endet mit needs an import attribute of "type: json". Node.js verlangt das Attribut für jedes JSON-Modul, damit sich eine Datei nicht als JavaScript ausgeben kann: import settings from "./settings.json" with {type: "json"}. Bei import() übergeben Sie es als zweites Argument: await import("./settings.json", {with: {type: "json"}}).
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.