77 lines
3.3 KiB
Markdown
77 lines
3.3 KiB
Markdown
---
|
||
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 <realpath>/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).
|