Начало
» Основни познания
»
Как да поправим "ERR_MODULE_NOT_FOUND" в Node.js ESM импортиране
Как да поправим "ERR_MODULE_NOT_FOUND" в Node.js ESM импортиране
ERR_MODULE_NOT_FOUNDозначава, че Node.js е достигнал до зареждащия механизъм на ECMAScript модули и не е могъл да разреши модула, поискан от import, import()или входната точка на програмата. В текущата документация на Node.js тази грешка е конкретно дефинирана като неуспех при разрешаване на зареждащия механизъм на ESM; аналогичната грешка в CommonJS е MODULE_NOT_FOUND. Вижте официалния справочник за грешки в Node.js.
Най-бързото решение е да се определи какъв тип спецификатор е неуспешен, преди да се променя каквото и да било. Относително импортиране, като например , ./utils/logger.jsследва различни правила от импортиране на пакети, като например lodash. Node.js ESM също се разрешава различно от CommonJS: относителното импортиране изисква изрични файлови разширения, а индексите на директории не се отгатват автоматично. Тези разлики обясняват многото неуспехи след преминаване от require()към import.
Какво точно не успява да намери Node.js?
Започнете с първия ред на грешката, а не с целия стек. Обикновено той ви показва както неразрешената цел, така и файла, който се е опитал да я импортира. Класифицирайте неуспешния спецификатор в една от следните групи:
Относителен файл:./utils/logger.js или ../config.js.
Абсолютен файл или URL адрес на файл: абсолютен път или file:URL адрес.
Гол пакет:lodash , express, или @scope/pkg.
Подпът на пакета:some-package/feature.js .
Псевдоним на импортиране на пакет: вътрешен спецификатор, започващ с #, дефиниран чрез package.json"imports".
Първо прочетете първия ред за грешка: този пример идентифицира име на пакет, така че следващите проверки трябва да се фокусират върху инсталирането на зависимости и разрешаването на пакети.
Официалната документация за модулите на Node.js ECMAScript разделя относителните, абсолютните и голи спецификатори, защото те не се разрешават по един и същи начин. След като разберете коя категория е неуспешна, избягвайте случайни поправки, като например изтриване node_modulesили промяна, package.jsonдокато доказателствата не сочат към това.
Локалният ESM импорт включва ли истинското файлово разширение?
За относителни и абсолютни ESM спецификатори, Node.js изисква файловото разширение. Той не търси .js, .mjsили .jsonслед неуспешен относителен импорт. Настоящата документация на Node.js нарича това правило задължителни файлови разширения и също така посочва, че индексите на директории трябва да бъдат напълно посочени.
Ако файлът на диска е src/utils/logger.js, това е безопасният ESM формуляр:
import { logger } from './utils/logger.js';
Не:
import { logger } from './utils/logger';
Node.js ESM не извършва търсене на разширения за относителни импортирания. Запишете действителното файлово разширение в спецификатора на модула.
Това е една от най-важните разлики от CommonJS resolution. Официалната документация на Node.js пакетите обяснява, че require()може да се пробват разширения и папки, докато ESM loader не извършва търсене на разширения.
Импортирате ли директория вместо действителен файл?
Проект на CommonJS може да е разчитал на импортиране на директория, което в крайна сметка е заредило index.js. Не приемайте, че зареждащият файл на ESM ще направи същото. Ако вашата структура е:
src/
config/
index.js
app.js
предпочитам:
import config from './config/index.js';
вместо:
import config from './config';
Локалният неуспех при разрешаването обикновено сочи към точния неразрешен път. Проверете пътя, разширението и дали импортирането е насочено към директория, а не към файл.
Официалната документация на ESM посочва, че индексите на директории, като например тези, ./startup/index.jsтрябва да бъдат напълно посочени. Ако добавянето на разширението все още не е успешно, сравнете всеки сегмент от пътя с действителното дърво на директориите.
Наистина ли проектът работи като ESM?
Node.js поддържа както CommonJS, така и ECMAScript модули. За .jsфайлове, най-ясният маркер на ниво пакет е:
{
"type": "module"
}
Файловете, завършващи на , .mjsвинаги се третират като ES модули, докато файловете, завършващи на , .cjsвинаги се третират като CommonJS. Текущите версии на Node.js могат също да открият ESM синтаксиса в някои двусмислени файлове, но документацията на Node.js препоръчва изрични маркери на пакети, защото те са по-ясни за Node.js, инструменти и бъдеща поддръжка.
Проверете най-близкия контролиращ package.json. Стойност на типа от най-високо ниво module кара .js файловете в този пакет да използват ESM семантика.
Прочетете официалните правила за пакетите и типовете модули, преди да промените "type". Промяната на пакет от CommonJS на ESM може да засегне много файлове едновременно. Също така не забравяйте, че добавянето "type": "module"не инсталира липсваща зависимост или не коригира грешен път; то само определя как се интерпретират съответните .jsфайлове.
Липсващият пакет действително ли е инсталиран в този проект?
Ако грешката назовава гол пакет, като например lodash, проверете дървото на зависимостите, вместо да приемате, че глобално инсталиран пакет или друго работно пространство го прави достъпен.
npm ls lodash
В текущата npm документация за npm ls се казва, че командата изброява инсталираните версии на пакети и може да докладва липсващи или невалидни зависимости. Ако пакетът е директна зависимост по време на изпълнение и не е инсталиран, инсталирайте го в правилния проект:
npm install lodash
За импортиране на гол пакет, проверете дали пакетът е в текущото дърво на зависимостите, преди да промените синтаксиса на ESM.
Официалната документация за инсталиране на npm обяснява, че нормалната инсталация на проект поставя зависимостите в локалното node_modulesдърво и по подразбиране запазва изрично инсталираните пакети в dependencies.
В monorepo, изпълнете проверката в работното пространство, което притежава импортиращия файл. Инсталирането на пакет другаде в хранилището не означава автоматично, че текущият пакет има валидна декларирана зависимост.
Името на пакета правилно ли е, но подпътят е грешен?
Пакет може да съществува и въпреки това да отхвърля дълбоко импортиране. Съвременните пакети могат да дефинират "exports"карта (map) в своите package.json. Когато това поле съществува, Node.js позволява само декларираните там публични точки за вход. Официалната документация за входните точки на пакетите на Node.js гласи, че "exports"има приоритет пред "main"в поддържаните версии на Node.js и капсулира неизброени подпътища.
Да предположим, че зависимост документира този публичен импорт:
import { parse } from 'example-package/parser';
Не го замествайте с предполагаем вътрешен път, като например:
import { parse } from 'example-package/dist/internal/parser.js';
Проверете метаданните на инсталирания пакет, когато се разреши гол пакет, но подпът не. Публичните подпътища се контролират от картата за експортиране на пакета, когато има такава.
Блокиран "exports"подпът често води до , ERR_PACKAGE_PATH_NOT_EXPORTEDа не до ERR_MODULE_NOT_FOUND. Тази промяна в кода за грешка е полезно доказателство: това означава, че Node.js е намерил пакета, но заявеният път не е част от публичния му интерфейс. Използвайте документирания път за импортиране на пакета, вместо да заобикаляте капсулирането.
Може ли пътят да се различава само по правопис или по главни и малки букви?
Проверете действителното файлово дърво за символи. Импортирането, което изглежда работи на файлова система за разработка, която не различава главни и малки букви, може да се провали след внедряване в файлова система, различаваща главни и малки букви.
Например, ако истинският файл е:
src/utils/Logger.js
след това импортиране на:
import logger from './utils/logger.js';
не е преносим, защото Logger.jsи logger.jsмогат да бъдат различни имена на файлове.
Сравнете импорта с реалното дърво на директориите. Проверете всяко име на папка, име на файл, разширение и главни и малки букви.
Също така проверете, че импортирането е относително към импортиращия модул , а не към текущата директория на обвивката. Относителните спецификатори на ESM се разрешават спрямо URL адреса на модула на импортиращия файл.
Как можете да видите какво би разрешил Node.js?
В ES модул import.meta.resolve()може да помогне за проверка на резолюцията:
Официалният справочник на Node.js ESM го описва import.meta.resolve(specifier)като функция за разделяне на относителни модули, която връща абсолютен URL низ и спазва разделянето на пакети и разрешените експорти.
Има важно предупреждение за текущата версия: за относителна file:цел, import.meta.resolve()може да върне URL адреса, дори когато съответният локален файл не съществува. Използвайте го, за да отговорите на въпроса „Към коя цел Node разрешава този спецификатор?“, след което проверете дали полученият файл действително съществува. За липсващи голи пакети или невалидни съпоставяния на пакети, самото разрешаване може да разкрие грешката по-рано.
Трябва ли да изтриете node_modules и lockfile-а?
Не като първия отговор. Липсващо разширение, грешен локален път или неподдържан подпът на пакета няма да бъдат поправени чрез преинсталиране на зависимости.
Ако npm lsотчете непоследователно дърво, проектът има commit package-lock.jsonи искате възпроизводима чиста инсталация, използвайте:
npm ci
В текущата документация на npm ci се посочва, че npm ciсе изисква съществуващ заключващ файл, съществуващата node_modulesдиректория се премахва автоматично, заключеното дърво се инсталира и не се презаписва package.jsonзаключващият файл. Ако package.jsonи заключващият файл не са в съответствие, програмата се затваря, вместо тихо да актуализира заключването.
Избягвайте изтриването package-lock.jsonсамо за да се отстрани грешката. Това може да доведе до разрешаване на нов граф на зависимости и да превърне грешка в разрешаването на модули в промяна на версията на зависимостите.
Кой е най-бързият ред за отстраняване на неизправности?
Как се наричат грешките
Проверете първо
Типично решение
./local/path
Точен път и разширение
Добавете .js/ .mjsи коригирайте относителния път
Директория
Независимо дали сте очаквалиindex.js
Импортиране ./directory/index.jsизрично
package-name
npm ls package-name
Инсталирайте или правилно декларирайте зависимостта
package-name/subpath
Пакет "exports"и официални документи за пакета
Използвайте експортиран публичен подпът
Път, който изглежда правилен
Име на файл (регистър) и действително дърво на проекта
Съвпадение на файловата система точно
Само една среда се проваля
Заключен файл, работно пространство, версия на възела, случай на файлова система
Възпроизвеждане със същото декларирано дърво на зависимости
Какво трябва да избягвате да променяте сляпо?
Не добавяйте "type": "module"само защото импортирането е било неуспешно; първо потвърдете предназначената модулна система на проекта.
Не премахвайте файлови разширения, за да имитирате примери от CommonJS. Node.js ESM изисква изрични разширения за относителни и абсолютни файлови спецификатори.
Не импортирайте дълбоко лични файлове от зависимост, когато нейната "exports"карта предоставя поддържана публична точка за вход.
Не приемайте, че успешната глобална инсталация на npm прави зависимост достъпна за локално приложение.
Не изтривайте заключващ файл като рутинна стъпка за почистване на кеша.
Не приемайте, че работната директория контролира относителния ESM импорт; модулът за импортиране е основата.
Как разбирате, че поправката е завършена?
Изпълнете отново същата входна точка, която първоначално е била неуспешна, и потвърдете, че модулът се разрешава, без да замества грешката с друг проблем с разрешаването. След това изпълнете нормалните тестове на проекта или командата за стартиране, за да сте сигурни, че решението работи отвъд единична команда за импортиране.
След като коригирате основния проблем с разрешаването, изпълнете отново оригиналната команда и след това нормалния тестов или стартиращ работен процес на проекта.
Ако приложението сега достигне до различна грешка, като например ERR_PACKAGE_PATH_NOT_EXPORTED, ERR_UNKNOWN_FILE_EXTENSIONили грешка с име на експорт, не я третирайте като същия проблем. Това означава, че разрешаването на модула е напреднало допълнително и Node.js вече отчита по-специфична несъвместимост.
Долен ред
За Node.js ESM, ERR_MODULE_NOT_FOUNDпроблемът обикновено се решава чрез проследяване на точния спецификатор, вместо да се преинсталира всичко. Локалните файлове се нуждаят от изрични разширения и изрични индекси на директории. Голите пакети трябва да бъдат инсталирани в правилното дърво на зависимости. Подпътищата на пакетите трябва да спазват "exports". Контролиращият елемент package.jsonтрябва да съответства на предвидената модулна система, а имената на файловете трябва да съответстват точно на файловата система.
След като подходите към грешката в този ред – тип спецификатор, реален път, ESM правила, дърво на зависимостите, експортиране на пакети и след това чиста инсталация – обикновено можете бързо да идентифицирате причината, без да въвеждате несвързани промени.