Error: Cannot find module './Utils/logger'Das funktioniert perfekt auf Ihrem Computer und schlägt in dem Moment fehl, in dem es bereitgestellt wird. Für diese Fehlerklasse gibt es nur wenige Ursachen, die fast alle auf einen Unterschied zwischen Ihrer Entwicklungsumgebung und dem Server zurückzuführen sind.
📋 Table of Contents
- Ursache 1: Groß-/Kleinschreibung (am häufigsten)
- Ursache 2: Das Paket befindet sich in devDependencies
- Ursache 3: node_modules in Docker kopiert
- Ursache 4: Native Module, die für die falsche Plattform erstellt wurden
- Ursache 5: Fehlende Dateierweiterungen in ESM
- ist Ursache 6: TypeScript-Pfadaliase werden zur Laufzeit nicht aufgelöst
- Ursache 7: Die Build-Ausgabe wurde nicht bereitgestellt
- Systematisch diagnostizieren
- Prävention
- Häufig gestellte Fragen
- Fazit
Ursache 1: Groß-/Kleinschreibung (am häufigsten)
macOS und Windows verwenden standardmäßig Dateisysteme, bei denen die Groß-/Kleinschreibung nicht berücksichtigt wird. Linux nicht. Alsorequire('./Utils/logger') löst eine Datei mit dem Namenutils/logger.jsauf auf Ihrem Laptop und schlägt auf dem Server fehl.
// File on disk: src/utils/logger.js
const logger = require('./Utils/logger'); // works on macOS, fails on Linux
const logger = require('./utils/logger'); // ✅ correct everywhere
Finden Sie diese vor der Bereitstellung, indem Sie überprüfen, was Git tatsächlich aufgezeichnet hat, was unabhängig von Ihrem lokalen Dateisystem maßgeblich ist.
# List tracked paths and eyeball the casing
git ls-files | grep -i utils
# Catch a rename that Git ignored because only the case changed
git config core.ignorecase false
git status
Wenn Git den falschen Fall aufgezeichnet hat, erzwingen Sie die Umbenennung über einen Zwischennamen.
git mv src/Utils src/utils-tmp
git mv src/utils-tmp src/utils
git commit -m "fix: correct directory casing for case-sensitive filesystems"
Die zuverlässige Prävention ist ein CI-Job, der unter Linux läuft. Dies wird bei jeder Pull-Anfrage und nicht bei der Bereitstellung erfasst.
Ursache 2: Das Paket befindet sich in devDependencies
Produktionsinstallationen überspringen Entwicklungsabhängigkeiten, sodass alles, was vom Laufzeitcode importiert wird, eine reguläre Abhängigkeit sein muss.
npm ci --omit=dev # devDependencies are not installed
{
"dependencies": {
"express": "^5.0.0"
},
"devDependencies": {
"dotenv": "^17.0.0" // ❌ but required at runtime in server.js
}
}
# Move it
npm uninstall dotenv
npm install dotenv
Um jeden Fall auf einmal zu finden, installieren Sie Produktionsabhängigkeiten in einem sauberen Verzeichnis und starten Sie die Anwendung.
rm -rf node_modules
npm ci --omit=dev
node dist/server.js
Ursache 3: node_modules in Docker kopiert
Kopieren eines lokal erstelltennode_modules In ein Image werden native Module beschädigt, da für macOS oder Ihre Architektur kompilierte Binärdateien nicht auf der Plattform des Containers geladen werden können.
# .dockerignore — essential
node_modules
npm-debug.log
.git
dist
.env
# Dockerfile — install inside the image
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
Kopierenpackage*.json vor dem Rest der Quelle ist eine bewusste Layer-Caching-Entscheidung: Abhängigkeiten werden nur dann neu installiert, wenn sich das Manifest ändert, nicht bei jeder Quellbearbeitung.
Ursache 4: Native Module, die für die falsche Plattform erstellt wurden
Pakete mit kompilierten Komponenten –bcrypt, sharp, canvas, Datenbanktreiber – erzeugen plattformspezifische Binärdateien.
Error: Cannot find module '.../node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node'
Erstellen Sie sie auf der Zielplattform neu oder installieren Sie sie wie oben im Container.
npm rebuild bcrypt --build-from-source
# Alpine images need build tools for native compilation
RUN apk add --no-cache python3 make g++
Wo eine reine JavaScript-Alternative existiert –bcryptjs stattbcrypt, zum Beispiel – durch die Verwendung wird diese gesamte Kategorie von Bereitstellungsproblemen beseitigt.
Ursache 5: Fehlende Dateierweiterungen in ESM
ES-Module erfordern die Erweiterung in relativen Importen. CommonJS nicht. Bei der Migration zwischen ihnen kommt dies sofort zum Vorschein.
// package.json has "type": "module"
import { logger } from './utils/logger'; // ❌ ERR_MODULE_NOT_FOUND
import { logger } from './utils/logger.js'; // ✅
Beim Kompilieren von TypeScript zu ESM muss der Importspezifizierer aufverweisen Ausgabe Datei, also schreiben Sie.js obwohl die Quelle.ts.
import { logger } from './utils/logger.js'; // correct — refers to compiled output
ist Ursache 6: TypeScript-Pfadaliase werden zur Laufzeit nicht aufgelöst
Aliase intsconfig.json sind eine praktische Kompilierzeit. Der Compiler schreibt sie nicht neu, sodass das ausgegebene JavaScript weiterhin@/utils/loggerenthält , die Node nicht auflösen kann.
{
"compilerOptions": {
"paths": { "@/*": ["./src/*"] }
}
}
// Compiles fine, fails at runtime:
// Error: Cannot find module '@/utils/logger'
import { logger } from '@/utils/logger';
Schreiben Sie entweder die Pfade nach dem Kompilieren neu oder registrieren Sie einen Laufzeit-Resolver.
npm install -D tsc-alias
# package.json
"build": "tsc && tsc-alias"
Bei der Bündelung mit esbuild, tsup oder ähnlichem werden auch Aliase während des Builds aufgelöst, weshalb dies bei gebündelten Bereitstellungen selten auftritt.
Ursache 7: Die Build-Ausgabe wurde nicht bereitgestellt
A .gitignore or .dockerignore Eintrag fürdist ist richtig – aber dann muss der Build auf dem Server oder in CI laufen. Bestätigen Sie, was tatsächlich versendet wurde.
# Inspect the running container
docker exec -it <container> ls -la /app/dist
docker exec -it <container> ls -la /app/node_modules | head
Systematisch diagnostizieren
# 1. Which exact path is Node looking for?
node dist/server.js
# Read the full error — it prints the resolved path it tried.
# 2. Does that path exist on the server?
ls -la /app/dist/utils/
# 3. Is the package installed?
ls /app/node_modules | grep package-name
npm ls package-name
# 4. Trace resolution in detail
NODE_DEBUG=module node dist/server.js 2>&1 | head -50
# 5. Confirm the Node version matches your local one
node --version
NODE_DEBUG=module druckt alle Verzeichnisknotenprüfungen, wodurch das Problem normalerweise innerhalb weniger Zeilen offensichtlich wird.
Prävention
- Führen Sie CI unter Linux aus, damit Probleme mit der Groß-/Kleinschreibung vor dem Zusammenführen fehlschlagen
- Testen Sie mit
npm ci --omit=devin CI, um falsch platzierte Abhängigkeiten abzufangen - Immer
.dockerignoredeinnode_modules - Übernehmen Sie die Sperrdatei und verwenden Sie
npm ci, niemalsnpm install, in Builds - Pinnen Sie die Node-Hauptversion in der Docker-Datei und in
engines - Bevorzugen Sie reine JavaScript-Pakete, bei denen kein natives Modul erforderlich ist
Häufig gestellte Fragen
F: Warum funktioniert es lokal, aber nicht in Docker?
A: Unterschiedliche Berücksichtigung der Groß-/Kleinschreibung im Dateisystem, unterschiedliche Plattform für native Binärdateien und ein anderer Abhängigkeitssatz, wenn Sie lokal mit Entwicklungsabhängigkeiten installieren. Alle drei werden durch die Installation im Image eliminiert.
F: Soll ich node_modules festschreiben?
A: Nein. Übertragen Sie die Sperrdatei und installieren Sie sie während des Builds. Festgeschriebene Abhängigkeiten brechen bei Plattformänderungen und blähen das Repository stark auf.
F: NPM CI oder NPM in der Produktion installieren?
A: npm ci. Es installiert genau das, was in der Sperrdatei angegeben ist, und schlägt fehl, wenn Manifest und Sperrdatei nicht übereinstimmen, was Sie in einem Build wünschen.
F: Wie finde ich Nichtübereinstimmungen zwischen Groß- und Kleinschreibung in einer großen Codebasis?
A: Bauen Sie auf Linux in CI auf. Dies ist die einzig zuverlässige Methode – lokale Tools in einem Dateisystem, bei dem die Groß-/Kleinschreibung nicht beachtet wird, können das Problem nicht erkennen.
F: Das Modul befindet sich in node_modules, wird aber immer noch nicht gefunden. Warum?
A: Normalerweise ein verschachtelter Abhängigkeitskonflikt, ein defekter Symlink aus einem Arbeitsbereichs-Setup oder ein Paket, dessenexports In diesem Feld wird der Unterpfad, den Sie importieren, nicht angezeigt. Überprüfen Sieexportsdes Pakets Karte in ihrempackage.json.
Fazit
Nur für die ProduktionMODULE_NOT_FOUNDFehler entstehen durch Umgebungsunterschiede. Überprüfen Sie sie in der Reihenfolge:Groß- und Kleinschreibung gegenüber Linux, Laufzeitimporte sitzen in devDependencies, lokal erstellte node_modules wurden in das Image kopiert, native Module wurden für die falsche Plattform kompiliert, fehlendes.js Erweiterungen unter ESM und unaufgelöste TypeScript-Pfadaliase. Die strukturelle Lösung für fast alle ist die gleiche: Erstellen und installieren Sie sie in der Zielumgebung, führen Sie CI unter Linux aus und verwenden Sienpm ci mit einer festgeschriebenen Sperrdatei.
🔗 Share this article
✍️ Leave a Comment