Node.js-тулинг
Инструменты вокруг Node.js — nvm для переключения версий, npm/yarn/pnpm для зависимостей, сборщики, линтеры и менеджеры процессов.
Что такое Node.js-тулинг
Сам Node.js — только среда выполнения JavaScript. Всё остальное, из чего складывается рабочий проект, живёт вокруг: выбор версии Node, установка зависимостей, сборка, линтинг, запуск в проде. Ниже — что из этого что.
nvm — что это
nvm (Node Version Manager) — утилита для установки нескольких версий Node.js на одной машине и мгновенного переключения между ними.
Зачем: старый проект работает на Node 18, новый требует Node 22, а на сервере стоит третья версия. Глобально установленная Node одна, и без nvm переключение означает переустановку.
nvm install 22 # поставить конкретную версию
nvm install --lts # последнюю LTS
nvm use 18 # переключиться в текущей сессии терминала
nvm alias default 22 # версия по умолчанию для новых сессий
nvm ls # что установлено
Ключевая деталь: nvm use действует только в текущем окне терминала. В новом всё вернётся к default — это регулярно сбивает с толку.
Проект фиксирует свою версию файлом .nvmrc в корне репозитория:
echo "22" > .nvmrc
nvm use # прочитает .nvmrc и переключится
Технически nvm — это shell-функция, а не бинарник: она правит PATH текущей оболочки, потому и работает только в ней. Отсюда же следствие: под Windows настоящий nvm не работает — там ставят отдельный проект nvm-windows с похожими командами. Более быстрые альтернативы — fnm и Volta, они кроссплатформенные.
Менеджеры пакетов
| npm | yarn | pnpm | |
|---|---|---|---|
| Идёт с Node | Да | Нет | Нет |
| Место на диске | Копия пакетов в каждом проекте | Копия | Общий store и жёсткие ссылки |
| Скорость установки | Базовая | Выше | Обычно самая высокая |
| Строгость зависимостей | Плоское дерево | Плоское | Строгое: нельзя импортировать то, чего нет в package.json |
| Lock-файл | package-lock.json |
yarn.lock |
pnpm-lock.yaml |
Главный практический аргумент за pnpm — диск и время: он не копирует один и тот же пакет в двадцать проектов, а хранит один экземпляр в общем store. На CI-раннере и в Docker-сборке это экономит минуты.
package.json и lock-файл
package.json описывает проект и диапазоны версий, lock-файл фиксирует точные версии всего дерева, включая транзитивные зависимости.
{
"scripts": { "dev": "vite", "build": "vite build", "test": "vitest run" },
"dependencies": { "express": "^4.19.2" },
"devDependencies": { "vitest": "^2.0.0" }
}
^4.19.2 разрешает 4.20.0, но не 5.0.0. Без lock-файла двое разработчиков получат разные версии — это и есть «у меня работает».
Отсюда правило для CI/CD: в пайплайне и в Docker-образе ставьте зависимости через npm ci, а не npm install. ci ставит ровно то, что в lock-файле, падает при расхождении с package.json и не переписывает lock. install может тихо обновить версии — сборка перестанет быть воспроизводимой.
Разделение dependencies / devDependencies тоже практично: в продовом образе ставится npm ci --omit=dev, и образ худеет.
Сборщики и линтеры
- Vite — стандарт для фронтенда: мгновенный дев-сервер, сборка через Rollup.
- esbuild / SWC — сборщики на Go и Rust, на порядок быстрее webpack; часто работают внутри других инструментов.
- webpack — исторический стандарт, гибкий и медленный; всё ещё много где живёт.
- TypeScript — статическая типизация поверх JS, ловит ошибки до запуска.
- ESLint — поиск проблем в коде, Prettier — форматирование. Первый про смысл, второй про запятые; ставят обычно оба и вешают на pre-commit.
Запуск в проде
Node-процесс однопоточный: он использует одно ядро, а при необработанном исключении просто умирает. Значит, нужен супервизор.
pm2 start app.js -i max # по процессу на ядро, автоперезапуск
pm2 startup && pm2 save # подняться после ребута
-i max поднимает кластер по числу ядер CPU — иначе на VPS с 4 ядрами будет работать одно. Альтернатива pm2 без лишних зависимостей — юнит systemd с Restart=always; в Kubernetes перезапуском занимается сам оркестратор, и pm2 там лишний.
Отдельная боль — node_modules: сотни мегабайт и десятки тысяч файлов. В Docker-образе это лечится многоступенчатой сборкой (собрали в одном слое, в финальный положили только результат и продовые зависимости) и .dockerignore, куда node_modules кладут первой строкой.
Связанные термины
Готовы запустить GPU-задачу?
Запустить GPU-сервер