NVM for Windows v2: переписан с нуля — Go в ядре и нативная дружба с Windows

—

от автора

(Node Version Manager — инструмент для управления разными версиями Node.js на одном компьютере: установка, переключение между ними)

Источник: статья автора проекта Corey Butler «Why We Rewrote NVM for Windows» (6 октября 2026) и официальная документация nvm-windows.

После более чем десяти лет жизни версии 1 проект NVM for Windows получил полностью переписанную вторую версию. Это не косметический апдейт: изменены язык и архитектура ядра, модель работы с node.exe, способ хранения настроек, схема дистрибуции и даже бизнес-модель проекта. Ниже — коротко о том, зачем это было сделано и что именно получили пользователи.


Коротко о главном

  • v2 — переписывание с нуля. Ядро управления версиями осталось на Go, а «шимы» (перехватчики запуска node, npm, npx и др.) написаны на Zig.

  • Причина №1 — латентность запуска. К «налогу» Windows на создание процесса добавлялся старт рантайма Go; в сумме это уже заметно человеку.

  • Причина №2 — v1 умел использовать только ссылки. Симлинки не позволяют выполнять логику при запуске Node.js, а v2 нужны .nvmrc, проверки целостности и защиты.

  • Два режима работы: link (нулевая задержка, совместимость с «как есть») и shim (по умолчанию, +25–35 мс, но с современными сценариями).

  • Нативные интеграции Windows: «Приложения и возможности», журнал событий, центр уведомлений, реестр.

  • Две сборки: Community (MIT, бесплатно) и Certified (EULA, с надстройками Governance, Advanced Logging и Trust Artifacts).


Почему проект переписали

1. «Универсальная налог за задержку» в Windows и старт Go

Первая версия писалась в 2014 году — в том числе чтобы изучить Go. С тех пор язык заметно изменился, а автор задался вопросом: остаться на Go или перейти на что-то новое?

Ключевым оказался не язык как таковой, а задержка старта. Автор разложил её на три составляющие:

  1. Латентность ОС (Windows). Почти все языки порождают процесс через CreateProcessW: создание процесса, отображение образа, проверка антивирусом. По замерам это «дно» в 12–30 мс, а под нагрузкой — нередко 100 мс и выше. Эту плату платит любая программа, на каком бы языке она ни была написана.

  2. Латентность рантайма (Go). Go «предоплачивает» запуск рантайма, сборщика мусора и стандартной библиотеки: в экспериментах это добавляло 12–200 мс.

  3. Латентность приложения (логика). Собственно работа самого NVM.

Вместе первые два пункта легко выходят за порог, когда задержка уже ощущается пользователем.

2. Наследие v1: только ссылки

В v1 задержкой при запуске node myfile.js можно было не заниматься: версия разрешалась исключительно симлинками. Симлинк не порождает новый процесс — дополнительная задержка нулевая, поведение идентично прямому запуску node.exe.

Но у такой схемы есть принципиальное ограничение: ссылка — это указатель, а не логика. А v2 требовал именно логики во время выполнения:

  • поддержка .nvmrc и других файлов фиксации версии;

  • проверка целостности и подлинности node.exe;

  • защита от типичных рисков (подмена node.exe, несовпадение пакетных менеджеров и т. п.);

  • прочие улучшения «качества жизни».

3. «Shim Split»: разделить ядро и запуск Node.js

Решение — разделить управление версиями и операции Node.js с помощью шима. Автор прототипировал шим на трёх языках:

Прототип

Стартовая латентность

Комментарий

Go (базовый вариант)

высокий вклад рантайма

меньше всего строк кода

Rust

~10–15 мс

быстрее Go, но заметно медленнее Zig

Zig

<1–3 мс

самый маленький бинарник, лучший результат

Итог: шим- на Zig, nvm.exe — на Go. Позже на Zig появились и другие вспомогательные шимы: они крошечные, изолированные и быстрые. В документации математика уточняется: шим добавляет всего 1–3 мс собственной логики, а основной вклад даёт двойной CreateProcessW — примерно 15 мс на запуск шима, 3 мс логики и ещё 15 мс на запуск node.exe, то есть ~33 мс суммарно.

4. Нативные интеграции вместо «теневых установок»

Вторая большая цель v2 — сделать Node.js «полноценным гражданином» ИТ-экосистемы. Исторически менеджеры версий работали в обход системы: обходили права, создавали «теневые» установки, жили на самодельных автоматизациях. Всё это — ради продуктивности разработчика.

v2 пытается сохранить продуктивность, но действовать внутри экосистемы, а не вокруг неё. Отсюда — четыре нативные интеграции Windows (подробнее ниже): регистрация установок в системе, журнал событий, центр уведомлений и реестр.

5. Устойчивость: разделение Community и Certified

Отдельная, «невидимая» часть работы — governance и compliance. По словам автора, за последние годы большая часть его времени уходила не на дизайн и код, а на переписку с аудиторами, госструктурами и регуляторами, подтверждение отчётов CrowdStrike, проверку соответствия требованиям и разбор ложных срабатываний антивирусов после каждого релиза.

Поэтому проект разделил общественные усилия и работу по governance/compliance:

  • Community Builds — открытый исходный код (MIT), полный функционал приложения, без централизованного управления;

  • Certified Builds — те же возможности плюс корпоративные надстройки, распространяются по годовой подписке через клиентский портал.


Что нового в v2

Установка Node.js

  • Параллельные установки — можно ставить несколько версий Node.js одновременно.

  • Архивы .7z вместо .zip — загрузки примерно на 40% меньше.

  • Иметь установленный 7-Zip — необязательно. Если он установлен, NVM использует его для максимально быстрой распаковки; иначе применяется встроенный (более медленный) распаковщик.

  • Кэш загрузок — повторные установки переиспользуют скачанные и распакованные файлы.

  • Локальные и air-gapped установки — установка из локального каталога архивов (local_dir / cache) без обращения в интернет. Часть сценариев (в том числе air_gapped и офлайн-лицензия) относится к надстройке Governance.

  • Без обязательных прав администратора — больше не нужно запускать консоль «от имени администратора».

Два режима работы

Режим переключается в любой момент:

nvm use shim      # современный режим (по умолчанию)nvm use link      # классический режим ссылок# либо через конфигурациюnvm cfg set mode=shim

Link mode — версия выбирается ссылкой (NTFS junction) на активный node.exe, ссылка лежит в PATH. nvm use меняет цель ссылки, а не сам PATH. Ощущения — как от «голого» node.exe с nodejs.org, задержка 0 мс. Ограничения: нет современного workflow, а для путей UNC создаётся симлинк, требующий привилегии SeCreateSymbolicLinkPrivilege (включается режимом разработчика Windows или групповой политикой). Важно: v2 не запрашивает UAC — при нехватке прав появится нативное уведомление с подсказкой.

Shim mode (по умолчанию) — версию выбирает подписанный шим. Он даёт:

  • автовыбор версии по .nvmrc, .node-version, package.json и другим настроенным файлам;

  • автоустановку недостающей версии при nvm use;

  • единообразную обработку несовпадения пакетных менеджеров;

  • проверку издателя node.exe при каждом запуске;

  • блокировку вредоносных пакетов;

  • нативное журналирование;

  • «карантинный период» (cooldown) для npm/npx/yarn/pnpm/vlt/bun — по умолчанию выключен в Community и равен 2 дням в Certified;

  • (в Certified + Governance) ограничение прав Node.js/V8.

Плата за это — ~25–35 мс на запуск, что для подавляющего большинства сценариев незаметно.

Разрешение версий и автоматизация

  • Файлы фиксации версии: по умолчанию проверяются .nvmrc, .node-version, затем package.json; список настраивается (auto_detect), поддерживаются и собственные файлы.

  • Спецификаторы версий: latest, lts, lts/iron, мажор (24), мажор-минор (24.1), точная версия, пользовательские алиасы.

  • Ограничения (constraints): ^18, ~20.1, >=16, >=18 <21, 18.x, * — в том числе в engines.node.

  • nvm pin — записывает точную версию в .nvmrc или в engines/devEngines файла package.json.

  • Автоустановка отсутствующей версии и автоустановка набора глобальных модулей с каждой новой версией (auto_installed_modules).

  • Пользовательские алиасы — короткие имена версий (nvm alias add).

  • Отладка выбора версии: node --nvm-which --version или npm --nvm-which --version печатает, откуда взялась версия (source, requested, resolved, путь к node.exe).

Безопасность

  • Блокировщик вредоносных пакетов. Останавливает npm/pnpm/yarn/vlt (и bun, если включён shim_bun) при совпадении имени и версии пакета с набором OpenSSF Malicious Packages. Проверка идёт по подписанному локальному файлу malware.db со всеми механизмами его обновления и проверки целостности. При срабатывании команда прерывается:

    NVM blocked left-pad - recognized as malware (OpenSSF). (NVM4602)

    Это не антивирус и не сканер файлов: Community-сборки проверяют явно устанавливаемый пакет и прямые зависимости package.json, Certified дополнительно читает lock-файл и весь транзитивный граф. Отключение — nvm config set skip_malware_checks=true (не рекомендуется).

  • Проверка издателя node.exe при каждом запуске в shim-режиме.

  • NVM Firewall (Governance) — allow/block-списки версий Node.js.

  • Ограничение прав Node.js (Governance) — запуск node в режиме default-deny (--permission), заморозка интринсиков V8 (--frozen-intrinsics), запрет eval() и new Function() (--disallow-code-generation-from-strings).

Нативные интеграции Windows

  1. Windows Apps. Каждая управляемая версия Node.js регистрируется в системе и видна в «Приложениях и возможностях». По словам автора, это, вероятно, первый менеджер версий рантайма, который так делает. Ценность не в красивой витрине: система и сканеры (CrowdStrike, Qualys и др.) начинают отличать «намеренно установленную» версию от подброшенного файла node.exe — например, переименованного из evil.exe.

  2. Источник событий Windows. v2 регистрируется как нативный Event Source — структурные логи доступны в Event Viewer, их можно забирать в SIEM. Это основа для аудита сред разработчиков.

  3. Центр уведомлений Windows. v2 — провайдер Notification Center, поэтому уведомления уважают пользовательские настройки (например, «тихие часы») и не теряются, если вы отошли за кофе. Для ИБ это ещё и различимый источник телеметрии: видно, что уведомление от NVM for Windows, а не от универсальной утилиты вроде node-notifier или BurntToast.

  4. Реестр Windows. Самая значимая и самая незаметная интеграция: плоский settings.txt из v1 заменён записями в реестре. Это и решение пользовательских проблем, и фундамент для централизованных политик: администраторы могут форсировать режим работы (shim/link), задавать каталоги хранения версий, ограничивать наборы доступных версий, «запирать» права Node.js, задавать cooldown модулей независимо от пакетного менеджера. В строгих средах можно заблокировать nodejs.org/dist и использовать прокси-зеркало, чтобы исключить скачивание неутверждённых (например, уязвимых EOL) версий.

Корпоративная обвязка

  • Скачивание: зеркала и авторское приватное зеркало, HTTP-прокси (в Governance — расширенный: IWA/NTLM/Negotiate, PAC/WPAD).

  • Развёртывание: ADMX/ADML и скрипты для групповых политик Active Directory, Entra, Intune; MSI-установщики и PowerShell-скрипты в Certified.

  • Наблюдаемость: встроенное журналирование в Event Viewer доступно всем; надстройка Advanced Logging даёт структурированные логи для SIEM (включая события блокировки пакетов).

  • Артефакты доверия (Trust Artifacts): подписанный SBOM (CycloneDX), аттестации SLSA уровня Build L3, результаты SAST (gosec и PSScriptAnalyzer), отчёт по open-source-лицензиям и VEX.


Источники

ссылка на оригинал статьи https://habr.com/ru/articles/1107892/