Zum Inhalt springen
aviral gupta

// 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.

Lektion 4 von 5 in B2 npm und Pakete

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
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen: cart.js enthält export default function total() { … }. Welche Zeile in main.js importiert diese Funktion?

  2. 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);
    
  3. Ü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";
  4. Ü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.

  5. Ü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);
  6. 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);
    
  7. 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.js

Ausgabe

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
  1. Hinweis 1

    Eine Zeile importiert beide Arten: import round2, {STANDARD, REDUCED} from "./rates.js";

  2. Hinweis 2

    net * (1 + STANDARD) ist der Bruttobetrag; übergeben Sie ihn an round2.

  3. 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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.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
  1. Hinweis 1

    import() nimmt jeden String, also können Sie den Specifier zusammensetzen: "./greet-" + lang + ".js".

  2. Hinweis 2

    Warten Sie mit await auf import(); die Funktion liegt im Ergebnis unter .default.

  3. 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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.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
  1. Hinweis 1

    import settings from "./settings.json" with {type: "json"}; liefert Ihnen das geparste Objekt.

  2. Hinweis 2

    settings.name + " " + settings.version ergibt das Banner.

  3. 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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Die Endung weglassen

import {add} from "./cart";

add("tea", 3.5);

Was Node.js ausgibt

Error [ERR_MODULE_NOT_FOUND]: Cannot find module

Warum, 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]: Module

Warum, 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.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Benannte und Default-Exporte

Ein Modul teilt nur, was es exportiert. Benannte Exporte behalten ihren Namen: export function add() oder export const REDUCED = 0.07, importiert mit import {add, REDUCED} from './cart.js' oder umbenannt mit {add as addItem}. Ein Modul kann zusätzlich einen Default-Export haben, export default function total(), den der Importeur frei benennt: import total from './cart.js'. Beides lässt sich mischen: import total, {add} from './cart.js'. import * as cart liefert ein Objekt mit allen Exporten, den Default unter cart.default. Fragt man nach einem Namen, den das Modul nicht exportiert, stoppt das Programm, bevor eine Zeile läuft: SyntaxError: The requested module './cart.js' does not provide an export named 'totl'.

Specifier: Die Endung gehört zum Namen

Der String nach from ist der Specifier. Ein relativer, './cart.js', wird vom importierenden Modul aus aufgelöst, und Node.js ergänzt nichts: './cart' stoppt mit ERR_MODULE_NOT_FOUND und dem Hinweis, "./cart.js" zu importieren, und ein Ordner lädt nicht seine index.js. Ein nackter Specifier wie 'semver' nennt ein Paket in node_modules. Eingebaute Module laden als fs oder node:fs, aber node:sea, node:sqlite, node:test und node:test/reporters gibt es nur mit Präfix; das hält neue eingebaute Module von Paketen fern, die den Namen schon tragen. module.builtinModules listet alle. import('./cart.js') nimmt dieselben Specifier während des Laufs und liefert ein Promise des Modulobjekts: Warten Sie mit await darauf und lesen Sie .default.

Live Bindings, JSON und import.meta

Ein Import ist eine lebendige, schreibgeschützte Sicht auf die Variable des exportierenden Moduls. Führt cart.js count += 1 aus, sieht jeder Importeur den neuen Wert; count = 5 im Importeur scheitert mit TypeError: Assignment to constant variable. Eine JSON-Datei braucht ein Import-Attribut: import settings from './settings.json' with {type: 'json'}. Ohne wirft Node.js ERR_IMPORT_ATTRIBUTE_MISSING, und ein JSON-Modul hat nur einen Default-Export. In ES-Modulen ist import.meta.url die file:-URL des Moduls, import.meta.filename sein absoluter Pfad und import.meta.dirname sein Ordner, egal aus welchem Ordner Sie node starten. Beide sind seit v24.0.0 nicht mehr experimentell; eine .cjs-Datei kann import.meta gar nicht verwenden.

Quellen

Zuletzt geprüft am 30. September 2026