--- title: "nvm-junction isMain-gate gotcha — ESM main() молча не выполняется" type: concept tags: [node, esm, nvm, windows, junction, symlink, cli, gotcha, postmortem] sources: [] related: [concepts/nvm-windows-node-switch.md] updated: 2026-08-18 --- # nvm-junction isMain-gate gotcha `import.meta.url === pathToFileURL(process.argv[1]).href` ломается, когда `node` вызывается через junction/симлинк-префикс (nvm-windows, nvm/mise/volta на *nix — те же грабли). Симптом: CLI-бинарь **молча no-op** — `--help`, флаги, даже strict-parse ошибки: exit 0, пустой stdout для ЛЮБОГО вызова. ## Root cause ESM резолвит `import.meta.url` в **realpath** файла, а `process.argv[1]` держит **литеральный** путь из командной строки (через junction). Строки разные → `main()` не вызывается, скрипт просто завершается. Конкретика (найдено в CLI-F&F sched 2026-08-18): ``` C:\nvm4w\nodejs\node_modules\@sched\daemon\dist\cli.js --help # junction C:\nvm4w\nodejs → realpath C:\Users\vitya\AppData\Local\nvm\v22.22.0 # import.meta.url = file:///C:/Users/vitya/AppData/Local/nvm/v22.22.0/.../cli.js (realpath) # process.argv[1] = C:\nvm4w\nodejs\node_modules\@sched\daemon\dist\cli.js (literal) # → != → main() не выполняется ``` Realpath-инвокация (`node /cli.js`) работает идеально — поэтому баг «плавающий»: у разработчика (из исходников) работает, у оператора (global-установка под version-manager'ом) — нет. ## Фикс Сравнивать realpath'ы обеих сторон: ```ts import { realpathSync } from 'node:fs' import { fileURLToPath } from 'node:url' function isCliMain(argv1, metaUrl) { if (!argv1) return false return realpathSync(fileURLToPath(metaUrl)) === realpathSync(argv1) } ``` TDD-покрытие: junction-регрессия через `fs.symlinkSync('junction')`, real-path true, другой файл false, `argv1` undefined false. (sched `apps/daemon/src/cli.ts`, коммит `bd38aab`, daemon 0.3.2.) Альтернатива — не использовать isMain-гейт вовсе (как @sched/cli: бинарь всегда main). ## Кого бьёт Любой `bin` в npm-пакете с isMain-гейтом, установленный **глобально** под version-manager'ом с junction/symlink-префиксом npm-рута: - nvm-windows (`C:\nvm4w\nodejs` → junction на активную версию) - nvm / volta / mise на *nix (симлинки в `~/.nvm/...`) ## Диагностика за 30 секунд ``` # из-под глобальной установки: schedd --help # пусто, exit 0 → подозрение node $(which schedd) --help # realpath-инвокация → полный help → подтверждено ``` ## Проверено на Node 24 На Node 24.19.0 (nvm-windows, junction) тот же realpath-фикс работает: `--help` полный, exit 0, stderr чист. См. [nvm-windows-node-switch](nvm-windows-node-switch.md).