mitmario.dev

Wie Node ein Modul findet

Node.js Sandbox 3 Min Lesezeit 3 BeispieleLektion 5 von 7

Cannot find module ist die Fehlermeldung, die dich in Node am häufigsten begrüßt. Sie ist auch die undankbarste, weil sie dir sagt, dass etwas fehlt, aber nicht, wo Node gesucht hat.

Diese Lektion räumt das auf. Danach kannst du vorhersagen, wo Node nachschaut, und die Meldung sagt dir dann von selbst, was los ist.

Drei Arten von Angaben

Was zwischen den Anführungszeichen steht, nennt sich Spezifizierer. Node schaut sich den Anfang an und entscheidet daran, wie gesucht wird.

Fängt es mit ./ oder ../ an, ist es ein Pfad. Gesucht wird relativ zu der Datei, in der der Import steht, nicht relativ zum Arbeitsverzeichnis. Das ist derselbe Unterschied wie in der vorigen Lektion, nur diesmal nimmt Node ihn dir ab.

Fängt es mit node: an, ist es eingebaut. Node schaut gar nicht auf die Festplatte.

Alles andere ist ein Paket. Also ein Name ohne Punkt und ohne Schrägstrich am Anfang, wie express oder slugify. Danach wird in node_modules gesucht.

Drei Arten von Angaben
import { readFile } from "node:fs/promises";
import { rechne } from "./lib/rechnen.mjs";

console.log("eingebaut:", typeof readFile);
console.log("relativ:", rechne(4));

Wie die Suche nach einem Paket abläuft

Bei einem Paketnamen schaut Node zuerst in das node_modules neben der Datei. Findet es dort nichts, geht es einen Ordner nach oben und schaut wieder. Und noch einen. Und so weiter, bis zur Wurzel des Dateisystems.

Das erklärt eine Beobachtung, über die man sonst stolpert: Eine Datei tief unten in src/routen/admin/ findet ein Paket, obwohl dort weit und breit kein node_modules liegt. Es liegt oben im Projektstamm, und Node hat sich hochgearbeitet.

Für Pakete gibt es noch eine zweite Schicht. In der package.json eines Pakets kann ein Feld "exports" stehen, und darin legt der Autor fest, welche Dateien von außen überhaupt erreichbar sind und unter welchem Namen. Deshalb funktioniert import x from "paket/extra" bei manchen Paketen und bei anderen nicht. Mehr brauchst du dazu vorerst nicht zu wissen.

Die vier Ursachen, in der Reihenfolge ihrer Häufigkeit

Ein Tippfehler. Unspektakulär, aber es ist wirklich die Nummer eins. Lies den Pfad in der Fehlermeldung Zeichen für Zeichen, sie zeigt dir genau, wonach gesucht wurde.

Die vergessene Dateiendung. In ESM ist sie Pflicht, und das ist die Gewohnheit, die aus Bündler-Projekten mitkommt.

Ein Pfad, der nicht stimmt
// Die Datei liegt in lib/, hier fehlt der Ordner im Pfad.
import { rechne } from "./rechnen.mjs";

console.log(rechne(4));

Hier fehlt nicht die Endung, sondern der Ordner. Die Fehlermeldung nennt trotzdem genau den Ort, an dem gesucht wurde, und dort liegt eben nichts. Diese Zeile zu lesen ist schneller als zu raten.

Ein vergessenes npm install. Steht der Name ohne ./ da und meldet Node Cannot find package, dann hat es in node_modules gesucht und nichts gefunden. Meistens, weil das Projekt frisch geklont und noch nicht installiert wurde.

Groß- und Kleinschreibung. Der Fall, der dich am teuersten zu stehen kommt.

Groß und klein ist nicht dasselbe
// Die Datei heißt rechnen.mjs, hier steht Rechnen.mjs.
import { rechne } from "./lib/Rechnen.mjs";

console.log(rechne(4));

Auf macOS und unter Windows unterscheidet das Dateisystem meistens nicht zwischen Groß- und Kleinschreibung. Rechnen.mjs findet dort also die Datei rechnen.mjs, und dein Programm läuft. Linux unterscheidet sehr wohl, und auf Linux läuft dein Server. Das Ergebnis ist ein Fehler, der ausschließlich in der Produktion auftritt und den du lokal nicht nachstellen kannst.

Deshalb die Empfehlung: Halte dich bei Dateinamen an eine Schreibweise und bleib dabei. Kleinbuchstaben mit Bindestrichen sind die üblichste, und sie hat den Vorteil, dass es nichts zu verwechseln gibt.

Zum Mitnehmen

Ein Pfad mit ./ am Anfang meint eine Datei neben dir. Derselbe Name ohne ./ meint ein Paket. Das ist kein Schreibstil, sondern eine andere Suche.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, auf dem Server geprüft

    Öffnet sich mit dem Basis Konto.