Zum Inhalt springen
aviral gupta

// I3.3 · ca. 34 Min. · Aufbau

ES-Module in Node.js: "type", .mjs und .cjs

Nach dieser Lektion wissen Sie, warum Node.js eine Datei als ES-Modul oder als CommonJS behandelt, und ersetzen require, __dirname und das Laden von JSON durch die ES-Modul-Varianten.

Lektion 3 von 5 in I3 Module, Node.js und npm

Danach können Sie

  • Erklären, wie Node.js für eine Datei ES-Modul oder CommonJS wählt: "type" in package.json, .mjs und .cjs
  • Eingebaute Node.js-Module mit node: und CommonJS-Dateien aus einem ES-Modul importieren, ohne require
  • Dateien neben einem Modul mit import.meta.dirname finden und JSON mit einem Import-Attribut importieren
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion I3.2. Was gibt main.js aus?

    // tools.js
    export default function shout(text) {
      return text.toUpperCase();
    }
    
    // main.js
    import loud from "./tools.js";
    console.log(loud("hi"));
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. package.json sagt "commonjs". Was passiert bei node main.js?

    // package.json
    {"type": "commonjs"}
    
    // main.js
    import {platform} from "node:os";
    console.log(typeof platform());
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie das Präfix, das ein eingebautes Node.js-Modul kennzeichnet.

    import {readFileSync} from "____:fs";
    from ":fs";
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jeder Datei zu, wie Node.js sie lädt.

  5. Üben · Aufgabe 5 von 7

    Eine alte Gewohnheit in einem ES-Modul. Was passiert?

    // main.js
    const fs = require("node:fs");
    console.log(typeof fs.readFileSync);
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. data.txt liegt neben main.js, und Sie starten node app/main.js aus dem Ordner über app. Was passiert?

    // app/data.txt
    hello
    
    // app/main.js
    import {readFileSync} from "node:fs";
    console.log(readFileSync("data.txt", "utf8").trim());
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe: Schreiben Sie in einem neuen Ordner eine package.json mit "type": "module", eine CommonJS-Datei units.cjs, die kmToMiles(km) über module.exports exportiert, auf eine Nachkommastelle gerundet, und runs.json mit [5, 10, 21.1]. main.js importiert beide, das JSON mit einem Import-Attribut, und gibt den eigenen Dateinamen und die Läufe in Meilen aus. Führen Sie node main.js aus.

    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 ES-Modul, das CommonJS, JSON und eine Datei nutzt

main.js ist ein ES-Modul, weil die package.json des Projekts "type": "module" sagt. Es importiert eingebaute Module mit node:, eine CommonJS-Datei, deren module.exports als Default-Export ankommt, und eine JSON-Datei mit einem Import-Attribut. Es liest notes.txt neben sich über import.meta.dirname und lädt node:os erst bei Bedarf, mit einem dynamischen Import.

main.js

import {readFileSync} from "node:fs";
import {join} from "node:path";
import legacy from "./legacy.cjs"; // a CommonJS file: its module.exports
import settings from "./settings.json" with {type: "json"};

console.log(typeof require, typeof __dirname); // CommonJS only
console.log(import.meta.filename.endsWith("main.js"));

// A file next to this module, wherever node is started from:
const notes = readFileSync(join(import.meta.dirname, "notes.txt"), "utf8");
console.log(notes.trim());

console.log(legacy.greet("Ada"));
console.log(settings.theme);

const os = await import("node:os"); // a dynamic import
console.log(typeof os.platform());

legacy.cjs

module.exports = {
  greet(name) {
    return "Hello, " + name;
  }
};

settings.json

{"theme": "dark"}

notes.txt

Remember: import, not require.

Ausführen mit

node main.js

Ausgabe

undefined undefined
true
Remember: import, not require.
Hello, Ada
dark
string
  • typeof wirft bei require und __dirname nicht: Sie sind in einem ES-Modul schlicht nicht definiert.
  • legacy.cjs ist wegen seiner Endung CommonJS, egal was in package.json steht.
  • join(import.meta.dirname, "notes.txt") findet die Datei auch dann, wenn node aus einem anderen Ordner gestartet wird.

Übungen

Übung 1 von 2

Eine Datei neben dem Modul

loadWords() soll words.txt lesen, die neben main.js liegt, und ihre Zeilen als Array zurückgeben. Der Startcode baut den Pfad mit __dirname, das es in einem ES-Modul nicht gibt, der Aufruf wirft also. Nutzen Sie stattdessen import.meta.dirname.

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

    Führen Sie die Tests aus: ReferenceError: __dirname is not defined in ES module scope. Was ersetzt es?

  2. Hinweis 2

    import.meta.dirname ist der Ordner des aktuellen Moduls.

  3. Hinweis 3

    join(import.meta.dirname, "words.txt")

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

import {readFileSync} from "node:fs";
import {join} from "node:path";

export function loadWords() {
  const text = readFileSync(join(import.meta.dirname, "words.txt"), "utf8");
  return text.trim().split("\n");
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 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 {readFileSync} from "node:fs";
import {join} from "node:path";

export function loadWords() {
  const text = readFileSync(join(__dirname, "words.txt"), "utf8");
  return text.trim().split("\n");
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {loadWords} from './main.js';

test('loadWords liest die drei Wörter', () => {
  const words = loadWords();
  assert.deepEqual(words, ['apple', 'banana', 'cherry'], `loadWords gab ${JSON.stringify(words)}`);
});

words.txt

apple
banana
cherry

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 2

Ein CommonJS-Helfer in einem ES-Modul

legacy.cjs ist eine alte CommonJS-Datei mit toCelsius und toFahrenheit auf module.exports. convert(value, to) in main.js soll sie nutzen: to "C" rechnet von Fahrenheit um, to "F" von Celsius. Der Startcode ruft require in der Funktion auf, das ein ES-Modul nicht hat. Importieren Sie stattdessen legacy.cjs oben in der Datei.

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

    Führen Sie die Tests aus: require is not defined in ES module scope. Wie lädt ein ES-Modul eine andere Datei?

  2. Hinweis 2

    Das module.exports einer CommonJS-Datei kommt als Default-Export an.

  3. Hinweis 3

    import temperature from "./legacy.cjs"; oben in main.js

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

import temperature from "./legacy.cjs";

export function convert(value, to) {
  return to === "C" ? temperature.toCelsius(value) : temperature.toFahrenheit(value);
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export function convert(value, to) {
  const temperature = require("./legacy.cjs");
  return to === "C" ? temperature.toCelsius(value) : temperature.toFahrenheit(value);
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {convert} from './main.js';

test('212 Fahrenheit sind 100 Celsius', () => {
  const got = convert(212, 'C');
  assert.equal(got, 100, `convert(212, 'C') gab ${got}`);
});

test('20 Celsius sind 68 Fahrenheit', () => {
  const got = convert(20, 'F');
  assert.equal(got, 68, `convert(20, 'F') gab ${got}`);
});

legacy.cjs

module.exports = {
  toCelsius: (f) => Math.round(((f - 32) * 5) / 9),
  toFahrenheit: (c) => Math.round((c * 9) / 5 + 32)
};

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

require in einem ES-Modul

const {readFileSync} = require("node:fs");
console.log(readFileSync("main.js", "utf8").length > 0);

Was Node.js ausgibt

ReferenceError: require is not defined in ES module scope, you can use import instead

Warum, und die Lösung

Eine .js-Datei in einem Paket mit "type": "module" ist ein ES-Modul, in dem es require nicht gibt. Schreiben Sie oben import {readFileSync} from "node:fs";. Nur wenn Sie wirklich CommonJS brauchen, nennen Sie die Datei .cjs.

JSON ohne Import-Attribut importieren

import settings from "./settings.json";
console.log(settings.theme);

Was Node.js ausgibt

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]

Warum, und die Lösung

Node.js importiert JSON nur, wenn der Import sagt, was er erwartet, damit eine Datei nie versehentlich als Code läuft. Ergänzen Sie das Import-Attribut: import settings from "./settings.json" with {type: "json"};. Oder lesen Sie die Datei mit readFileSync und JSON.parse.

Ein benannter Import aus einer CommonJS-Datei

import {greet} from "./legacy.cjs";
console.log(greet("Ada"));

Was Node.js ausgibt

SyntaxError: Named export 'greet' not found. The requested module './legacy.cjs' is a CommonJS module, which may not support all module.exports as named exports.

Warum, und die Lösung

Node.js kann benannte Exporte nur aus manchem CommonJS-Code erraten, und hier gelingt es nicht. Der Default-Export funktioniert immer, weil er module.exports selbst ist: import legacy from "./legacy.cjs"; dann legacy.greet("Ada"), oder const {greet} = legacy;.

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

Welches System eine Datei nutzt

Node.js kennt zwei Modulsysteme: ES-Module (import und export) und das ältere CommonJS (require und module.exports). Bei einer .js-Datei schaut es in die nächstgelegene package.json: "type": "module" macht sie zum ES-Modul, "type": "commonjs" zu CommonJS. Eine .mjs-Datei ist immer ein ES-Modul und eine .cjs-Datei immer CommonJS, egal was in package.json steht. Ohne "type"-Feld versucht Node.js es mit CommonJS und wechselt mit einer Warnung, sobald es import oder export sieht. Schreiben Sie in neuen Projekten immer "type": "module".

Kein require in einem ES-Modul

require, module.exports, __dirname und __filename gehören zu CommonJS. In einem ES-Modul sind sie nicht definiert: require("node:fs") wirft einen ReferenceError. Nutzen Sie stattdessen import: import {readFileSync} from "node:fs", mit dem Präfix node: für eingebaute Module. Ein ES-Modul kann eine CommonJS-Datei importieren: Ihr module.exports kommt als Default-Export an, import legacy from "./legacy.cjs". Um ein Modul erst bei Bedarf zu laden, nutzen Sie await import("node:os"), das in beiden Systemen funktioniert.

import.meta und JSON

import.meta.filename ist der volle Pfad des aktuellen Moduls und import.meta.dirname sein Ordner; import.meta.url ist dasselbe als file:-URL. Ein relativer Pfad wie readFileSync("data.txt") wird ab dem Ordner gelesen, in dem node gestartet wurde, nicht ab dem Ordner des Moduls, bauen Sie den Pfad also zusammen: join(import.meta.dirname, "data.txt"). JSON-Dateien lassen sich mit einem Import-Attribut importieren: import settings from "./settings.json" with {type: "json"}. Ohne das Attribut schlägt der Import fehl.

Quellen

Zuletzt geprüft am 5. Oktober 2026