Пакетные менеджеры: npm vs yarn vs pnpm

npm, yarn и pnpm — инструменты для установки, управления и публикации JavaScript-пакетов, каждый со своей стратегией хранения зависимостей и скоростью работы.

Зачем нужно

Пакетный менеджер автоматизирует загрузку библиотек из реестра (npmjs.com), фиксирует точные версии в lockfile и управляет скриптами проекта. Без него разработчики вручную загружали бы зависимости и не могли воспроизводить одинаковое окружение на разных машинах.

Где используется

  • Установка зависимостей при клонировании проекта (npm install)
  • Запуск скриптов: сборка, тесты, линтинг
  • Monorepo-проекты с workspaces (yarn workspaces, pnpm workspaces)
  • CI/CD пайплайны — кеширование node_modules для ускорения сборки

Сравнение

Характеристика       npm          yarn (classic)   pnpm
─────────────────────────────────────────────────────────
Lockfile             package-lock  yarn.lock        pnpm-lock.yaml
Хранение пакетов     node_modules  node_modules     ~/.pnpm-store (symlinks)
Скорость             ★★★          ★★★★            ★★★★★
Дисковое место       много         много            мало (hard links)
Workspaces           да            да               да (лучшая поддержка)
Phantoms deps        да            да               нет (strict)

Основные команды

# Инициализация проекта
npm init -y
yarn init -y
pnpm init

# Установка всех зависимостей
npm install
yarn
pnpm install

# Добавление пакета
npm install express
yarn add express
pnpm add express

# Добавление devDependency
npm install --save-dev eslint
yarn add --dev eslint
pnpm add -D eslint

# Удаление пакета
npm uninstall express
yarn remove express
pnpm remove express

# Запуск скрипта из package.json
npm run build
yarn build
pnpm build          # можно без run для стандартных скриптов

# Глобальная установка
npm install -g typescript
yarn global add typescript
pnpm add -g typescript

package.json scripts

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext .ts,.tsx",
    "test": "vitest run",
    "prepare": "husky"
  }
}

Workspaces (monorepo)

// package.json корня monorepo
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": ["packages/*", "apps/*"]
}
# Установить зависимость в конкретный workspace
npm install lodash -w packages/utils
yarn workspace packages/utils add lodash
pnpm add lodash --filter packages/utils

# Запустить скрипт во всех workspace
npm run build --workspaces
pnpm -r run build

Lockfile — фиксация версий

# Никогда не удалять и всегда коммитить lockfile
git add package-lock.json()    # npm
git add yarn.lock            # yarn
git add pnpm-lock.yaml       # pnpm

# Установить точно по lockfile (в CI)
npm ci                       # только npm
yarn install --frozen-lockfile
pnpm install --frozen-lockfile

Частые ошибки

  • Смешивать менеджеры в одном проекте — разные lockfile конфликтуют. Выбрать один и задокументировать
  • Не коммитить lockfile — разные разработчики получат разные версии транзитивных зависимостей
  • npm install в CI вместо npm cinpm ci использует lockfile строго и быстрее
  • Устанавливать production-зависимость через --save-dev — попадает в не то поле package.json
  • pnpm: phantom dependencies — пакет доступен в коде, но не прописан в package.json (pnpm ловит это)

Связанные темы

Ресурсы