Files
admin/.wiki/concepts/nvm-junction-ismain-gate-gotcha.md

3.3 KiB
Raw Blame History

title, type, tags, sources, related, updated
title type tags sources related updated
nvm-junction isMain-gate gotcha — ESM main() молча не выполняется concept
node
esm
nvm
windows
junction
symlink
cli
gotcha
postmortem
concepts/nvm-windows-node-switch.md
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'ы обеих сторон:

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.