Опция nodePaths в esbuild расширяет стандартный алгоритм
разрешения модулей, добавляя дополнительные директории, в которых
выполняется поиск импортируемых пакетов и файлов. Она влияет
исключительно на этап resolution и не изменяет процесс трансформации или
бандлинга.
В стандартной схеме Node.js и esbuild поиск зависимостей выполняется последовательно:
node_modules текущего каталогаnode_modulesОпция nodePaths вмешивается в этот процесс, добавляя
один или несколько дополнительных корневых каталогов, которые
проверяются на наличие модулей до или параллельно с обходом стандартных
node_modules.
Если указано несколько путей, каждый из них рассматривается как отдельный корень поиска пакетов.
Опция передаётся в конфигурации esbuild как массив строк:
import esbuild from "esbuild";
esbuild.build({
entryPoints: ["src/index.js"],
bundle: true,
nodePaths: [
"src/shared",
"external_modules",
"../common_libs"
]
});
Каждый путь интерпретируется как директория верхнего уровня, внутри
которой esbuild пытается найти импортируемые зависимости так же, как в
node_modules.
При разрешении импорта, например:
import utils from "utils";
esbuild выполняет последовательность:
Проверка локального node_modules
Проверка всех директорий из nodePaths:
src/shared/utilsexternal_modules/utils../common_libs/utilsПодъём к родительским директориям и повтор стандартного поиска
node_modules
Каждый путь из nodePaths рассматривается как
потенциальный корень пакета, где utils может быть либо
папкой, либо файлом (utils.js, utils/index.js
и т.д.).
Существует схожая концепция переменной окружения
NODE_PATH, однако поведение nodePaths
отличается:
NODE_PATH зависит от окружения процесса и влияет на
Node.js runtimenodePaths задаётся явно в конфигурации сборщика и
влияет только на esbuildnodePaths более предсказуем в контексте сборки, так как
не зависит от внешнего окруженияИспользование nodePaths делает сборку воспроизводимой,
так как все пути зафиксированы в конфигурации проекта.
В монорепозиториях часто возникает ситуация, когда пакеты расположены
вне стандартного node_modules. Например:
repo/
packages/
app/
shared/
ui/
При попытке импорта:
import Button from "ui/Button";
без дополнительной настройки esbuild не сможет разрешить
ui, если он не установлен как зависимость в
node_modules.
С nodePaths можно добавить:
nodePaths: ["packages"]
Теперь packages/ui и packages/shared
становятся доступными как корневые модули, что позволяет использовать
более короткие и стабильные импорты внутри монорепозитория.
Порядок директорий в nodePaths имеет значение. При
наличии конфликтующих модулей:
nodePaths: ["a", "b"]
и наличия utils в обеих директориях, будет использован
первый найденный вариант из a/utils.
Это позволяет управлять приоритетом зависимостей, фактически создавая слой переопределения модулей.
esbuild применяет стандартные правила расширений при поиске модулей
внутри nodePaths:
.js.jsx.ts.tsx.jsonindex.*Пример структуры:
shared/
utils/
index.js
Импорт:
import utils from "utils";
разрешается в shared/utils/index.js, если
shared указан в nodePaths.
external и alias логикойХотя nodePaths влияет на resolution, он не заменяет:
external — исключение модулей из бандлаПри наличии плагинов, изменяющих onResolve, их логика
может полностью перекрыть поведение nodePaths. В этом
случае nodePaths становится частью fallback-механизма.
При использовании TypeScript nodePaths не заменяет
baseUrl или paths из
tsconfig.json. Однако он может использоваться для
синхронизации структуры резолвинга между сборщиком и компилятором
типов.
Типичная схема:
baseUrl: ./packagesnodePaths: ["packages"]Это снижает расхождения между IDE, type-checking и сборкой.
Если путь из nodePaths не существует, esbuild игнорирует
его без ошибки. Это важно для CI-сред, где часть директорий может
отсутствовать.
Такое поведение делает конфигурацию устойчивой к частично собранным или условным структурам проекта.
nodePaths не создаёт виртуальных модулейПо сути это механизм расширения корневых каталогов поиска, а не система переписывания путей.
Добавление большого числа путей в nodePaths увеличивает
количество проверок файловой системы. При глубокой структуре
монорепозитория это может повлиять на время первой сборки.
Оптимизация заключается в:
esbuild активно кеширует результаты resolution. Поэтому повторные
сборки с неизменной структурой nodePaths практически не
увеличивают время выполнения, даже при большом числе импортов.
Кеш учитывает:
nodePaths