Hur man åtgärdar "ERR_MODULE_NOT_FOUND" i Node.js ESM-importer
ERR_MODULE_NOT_FOUNDbetyder att Node.js nådde ECMAScript-modulladdaren och kunde inte lösa modulen som begärdes av en import, import(), eller programstartpunkten. I den aktuella Node.js-dokumentationen definieras detta fel specifikt som ett ESM-laddarlösningsfel; det analoga CommonJS-felet är MODULE_NOT_FOUND. Se den officiella Node.js-felreferensen .
Den snabbaste lösningen är att identifiera vilken typ av specifikation som misslyckades innan något ändras. En relativ import som ./utils/logger.jsföljer andra regler än en paketimport som lodash. Node.js ESM löses också annorlunda än CommonJS: relativa importer kräver explicita filändelser och katalogindex gissas inte automatiskt. Dessa skillnader förklarar många fel efter övergången från require()till import.
Vad exakt är det Node.js inte hittar?
Börja med den första raden i felet, inte hela stackspårningen. Den visar normalt både det olösta målet och filen som försökte importera det. Klassificera den felaktiga specificeraren i en av dessa grupper:
Relativ fil:./utils/logger.js eller ../config.js.
Absolut fil eller fil-URL: en absolut sökväg eller file:URL.
Barförpackning:lodash , express, eller @scope/pkg.
Paketets undersökväg:some-package/feature.js .
Paketimportalias: en intern specifikation som börjar med #, definierad genom package.json"imports".
Läs den första felraden först: det här exemplet identifierar ett rent paketnamn, så nästa kontroller bör fokusera på beroendeinstallation och paketlösning.
Den officiella dokumentationen för Node.js ECMAScript-moduler separerar relativa, nakna och absoluta specifikationer eftersom de inte löses på samma sätt. När du väl vet vilken kategori som misslyckades, undvik slumpmässiga korrigeringar som att ta bort node_moduleseller ändra package.jsontills bevisen pekar dit.
Inkluderar en lokal ESM-import den verkliga filändelsen?
För relativa och absoluta ESM-specifikationer kräver Node.js filändelsen. Den söker inte efter .js, .mjseller .jsonefter en misslyckad relativ import. Den nuvarande Node.js-dokumentationen kallar denna regel obligatoriska filändelser och anger också att katalogindex måste vara fullständigt specificerade.
Om filen på disken är src/utils/logger.js, är detta den säkra ESM-formen:
import { logger } from './utils/logger.js';
Inte:
import { logger } from './utils/logger';
Node.js ESM utför inte filändelsesökning för relativa importer. Skriv det faktiska filändelsen i modulspecifikationen.
Detta är en av de viktigaste skillnaderna från CommonJS-upplösningen. Den officiella dokumentationen för Node.js-paket förklarar att require()man kan testa tillägg och mappar, medan ESM-laddaren inte utför någon sökning efter tillägg.
Importerar du en katalog istället för en faktisk fil?
Ett CommonJS-projekt kan ha förlitat sig på en katalogimport som så småningom laddade en index.js. Anta inte att ESM-laddaren kommer att göra detsamma. Om din struktur är:
src/
config/
index.js
app.js
föredra:
import config from './config/index.js';
snarare än:
import config from './config';
Ett lokalt lösningsfel pekar vanligtvis på den exakta olösta sökvägen. Kontrollera sökvägen, filändelsen och om importen är riktad mot en katalog snarare än en fil.
Den officiella ESM-dokumentationen anger att katalogindex som ./startup/index.jsmåste vara fullständigt specificerade. Om tillägget av tillägget fortfarande misslyckas, jämför varje sökvägssegment med det faktiska katalogträdet.
Körs projektet verkligen som ESM?
Node.js stöder både CommonJS- och ECMAScript-moduler. För .jsfiler är den tydligaste markören på paketnivå:
{
"type": "module"
}
Filer som slutar på .mjsbehandlas alltid som ES-moduler, medan filer som slutar på .cjsalltid behandlas som CommonJS. Nuvarande Node.js-versioner kan också upptäcka ESM-syntax i vissa tvetydiga filer, men Node.js-dokumentationen rekommenderar explicita paketmarkörer eftersom de är tydligare för Node.js, verktyg och framtida underhåll.
Kontrollera närmaste kontrollerande package.json. Ett överordnat typvärde för module gör att .js-filer i det paketet använder ESM-semantik.
Läs de officiella reglerna för paket och modultyper innan du ändrar "type". Att ändra ett paket från CommonJS till ESM kan påverka många filer samtidigt. Kom också ihåg att tillägg "type": "module"inte installerar ett saknat beroende eller korrigerar en felaktig sökväg; det avgör bara hur relevanta .jsfiler tolkas.
Är det saknade paketet faktiskt installerat i det här projektet?
Om felet namnger ett naket paket som lodash, kontrollera beroendeträdet istället för att anta att ett globalt installerat paket eller en annan arbetsyta gör det tillgängligt.
npm ls lodash
Den nuvarande npm-dokumentationen för npm ls säger att kommandot listar installerade paketversioner och kan rapportera saknade eller ogiltiga beroenden. Om paketet är ett direkt runtime-beroende och inte är installerat, installera det i rätt projekt:
npm install lodash
För import av ett naket paket, verifiera att paketet finns i det aktuella beroendeträdet innan du ändrar ESM-syntaxen.
Den officiella npm-installationsdokumentationen förklarar att en normal projektinstallation placerar beroenden i det lokala node_modulesträdet och som standard sparar explicit installerade paket till dependencies.
I ett monorepo, kör kontrollen i arbetsytan som äger importfilen. Att ett paket installeras någon annanstans i repositoriet betyder inte automatiskt att det aktuella paketet har ett giltigt deklarerat beroende.
Är paketnamnet rätt, men undersökvägen fel?
Ett paket kan existera och ändå avvisa en djup import. Moderna paket kan definiera en "exports"karta i sin package.json. När det fältet finns tillåter Node.js endast de publika entrypunkter som deklareras där. Den officiella Node.js package-entry-point-dokumentationen säger "exports"att har företräde framför "main"i stödda Node.js-versioner och inkapslar olistade undersökvägar.
Anta att ett beroende dokumenterar denna publika import:
import { parse } from 'example-package/parser';
Ersätt den inte med en gissad intern sökväg som:
import { parse } from 'example-package/dist/internal/parser.js';
Kontrollera metadata för installerat paket när ett naket paket matchas men en undersökväg inte gör det. Offentliga undersökvägar styrs av paketets exportkarta när en sådan finns.
En blockerad "exports"undersökväg producerar ofta ERR_PACKAGE_PATH_NOT_EXPORTEDsnarare än ERR_MODULE_NOT_FOUND. Den förändringen i felkoden är ett användbart bevis: det betyder att Node.js hittade paketet men den begärda sökvägen är inte en del av dess publika gränssnitt. Använd paketets dokumenterade importsökväg istället för att kringgå inkapsling.
Kan sökvägen skilja sig endast genom stavning eller versaler/versaler?
Kontrollera det faktiska filträdet för tecken. Importer som verkar fungera på ett utvecklingsfilsystem som inte är skiftlägeskänsligt kan misslyckas efter distribution till ett filsystem som är skiftlägeskänsligt.
Till exempel, om den riktiga filen är:
src/utils/Logger.js
sedan en import av:
import logger from './utils/logger.js';
är inte portabel, eftersom Logger.jsoch logger.jskan ha olika filnamn.
Jämför importen med det verkliga katalogträdet. Kontrollera alla mappnamn, filnamn, tillägg och versaler.
Kontrollera också att importen är relativ till importmodulen , inte till skalets aktuella katalog. ESM:s relativa specifikationer tolkas relativt till modul-URL:en för importfilen.
Hur kan du se vad Node.js skulle lösa?
I en ES-modul import.meta.resolve()kan följande hjälpa till att inspektera upplösningen:
Den officiella Node.js ESM-referensen beskriver den import.meta.resolve(specifier)som en modul-relativ upplösningsfunktion som returnerar en absolut URL-sträng och respekterar paketupplösning och tillåtna exporter.
Det finns en viktig varning gällande den aktuella versionen: för ett relativt file:mål import.meta.resolve()kan URL:en returneras även när motsvarande lokala fil inte finns. Använd den för att svara på frågan "Vilket mål löser noden denna specifikation till?" och verifiera sedan att den resulterande filen faktiskt finns. För saknade nakna paket eller ogiltiga paketmappningar kan själva lösningen fortfarande avslöja felet tidigare.
Bör du ta bort node_modules och lockfilen?
Inte som det första svaret. Ett saknat tillägg, fel lokal sökväg eller en paketundersökväg som inte stöds kommer inte att repareras genom att ominstallera beroenden.
Om npm lsdet rapporteras ett inkonsekvent träd, projektet har en committed package-lock.json, och du vill ha en reproducerbar ren installation, använd:
npm ci
Den nuvarande npm ci-dokumentationen anger att den npm cikräver en befintlig låsfil, tar bort den befintliga node_moduleskatalogen automatiskt, installerar det låsta trädet och skriver inte package.jsonom låsfilen. Om package.jsonoch låsfilen inte överensstämmer avslutas den istället för att tyst uppdatera låset.
Undvik att radera package-lock.jsonbara för att felet ska försvinna. Det kan orsaka att ett nytt beroendediagram löses och förvandla ett modulupplösningsfel till en ändring av beroendets version.
Vilken är den snabbaste felsökningsordningen?
Vad felet heter
Kontrollera först
Typisk fix
./local/path
Exakt sökväg och förlängning
Lägg till .js/ .mjsoch korrigera den relativa sökvägen
En katalog
Oavsett om du förväntade digindex.js
Importera ./directory/index.jsexplicit
package-name
npm ls package-name
Installera eller deklarera beroendet korrekt
package-name/subpath
Paket "exports"och officiell paketdokumentation
Använd en exporterad offentlig undersökväg
En väg som ser rätt ut
Filnamnsfall och faktiskt projektträd
Matcha filsystemet exakt
Endast en miljö misslyckas
Låsfil, arbetsyta, nodversion, filsystemsfall
Reproducera med samma deklarerade beroendeträd
Vad bör du undvika att ändra blint?
Lägg inte till "type": "module"bara för att en import misslyckades; bekräfta först projektets avsedda modulsystem.
Ta inte bort filändelser för att imitera CommonJS-exempel. Node.js ESM kräver explicita filändelser för relativa och absoluta filspecifikationer.
Djupimportera inte privata filer från ett beroende när dess "exports"mappning tillhandahåller en offentlig startpunkt som stöds.
Anta inte att en lyckad global npm-installation gör ett beroende tillgängligt för en lokal applikation.
Ta inte bort en låsfil som ett rutinmässigt steg för cachens rensning.
Anta inte att arbetskatalogen styr relativa ESM-importer; importmodulen är basen.
Hur vet du att reparationen är klar?
Kör samma startpunkt som ursprungligen misslyckades igen och bekräfta att modulen löses utan att ersätta felet med ett annat lösningsproblem. Kör sedan projektets vanliga tester eller startkommando så att du vet att åtgärden fungerar utöver en enda import-sats.
När du har åtgärdat det underliggande lösningsproblemet, kör om det ursprungliga kommandot och sedan projektets normala test- eller startarbetsflöde.
Om programmet nu får ett annat fel, till exempel ERR_PACKAGE_PATH_NOT_EXPORTED, ERR_UNKNOWN_FILE_EXTENSION, eller ett export-name-fel, ska du inte behandla det som samma problem. Det betyder att modulupplösningen har fortskridit ytterligare och att Node.js nu rapporterar en mer specifik inkompatibilitet.
Slutsats
För Node.js ESM ERR_MODULE_NOT_FOUNDlöses det vanligtvis genom att spåra den exakta specificeraren snarare än att ominstallera allt. Lokala filer behöver explicita tillägg och explicita katalogindex. Paket utan attribut måste installeras i rätt beroendeträd. Paketets undersökvägar måste respektera "exports". Kontrollerna package.jsonmåste matcha det avsedda modulsystemet och filnamnen måste matcha filsystemet exakt.
När du närmar dig felet i den ordningen – specificeringstyp, verklig sökväg, ESM-regler, beroendeträd, paketexporter och sedan ren installation – kan du vanligtvis snabbt identifiera orsaken utan att införa orelaterade ändringar.