NPM: Полный справочник для опытных разработчиков
-
Node Package Manager (npm) — это не просто инструмент для установки пакетов, а полнофункциональная экосистема управления зависимостями, публикации модулей и автоматизации рабочих процессов. Для опытного разработчика важно понимать не только базовые команды, но и тонкие механизмы версионирования, разрешения зависимостей, оптимизации и лучшие практики при разработке собственных библиотек.
1. Архитектура и базовые концепции
1.1 Структура реестра и локального хранилища
npm состоит из трёх ключевых компонентов:
- Реестр npm (
registry.npmjs.org) — центральный репозиторий всех опубликованных пакетов с метаданными - npm CLI — локальный инструмент для взаимодействия с реестром и управления проектами
- node_modules — локальное хранилище установленных пакетов в вашем проекте
# Проверка текущего реестра npm config get registry # Изменение реестра (например, на зеркало) npm config set registry https://registry.yarnpkg.com1.2 Семантическое версионирование (semver)
Версии пакетов следуют формату
MAJOR.MINOR.PATCH:^1.2.3 — совместимо с версиями 1.x.x (изменения в minor и patch) ~1.2.3 — совместимо с версиями 1.2.x (изменения только в patch) 1.2.3 — точная версия >=1.2.3 — 1.2.3 и выше 1.2.3 - 2.0.0 — диапазон версий2. Управление зависимостями
2.1 Типы зависимостей в package.json
{ "dependencies": { "express": "^4.18.2" }, "devDependencies": { "typescript": "^5.0.0", "jest": "^29.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" }, "optionalDependencies": { "bcrypt": "^5.0.0" }, "bundledDependencies": [ "lodash" ] }Ключевые отличия:
dependencies— необходимы в productiondevDependencies— нужны только для разработки (не устанавливаются приnpm install --production)peerDependencies— указывают, какие версии других библиотек ожидаются в проекте-потребителеoptionalDependencies— пакеты, которые не должны ломать установку при ошибкеbundledDependencies— пакеты, которые включаются в распределение npm
2.2 Алгоритм разрешения зависимостей
npm использует flat tree algorithm (начиная с npm 3+):
project/ ├── node_modules/ │ ├── express/ (версия 4.18.2) │ ├── body-parser/ (зависимость express) │ └── debug/ (зависимость body-parser)При конфликтах версий npm размещает дополнительные копии на уровне зависимостей:
project/ ├── node_modules/ │ ├── packageA@1.0.0/ │ │ └── node_modules/ │ │ └── packageB@2.0.0/ (конфликт версии) │ └── packageB@1.0.0/2.3 Lock-файлы и воспроизводимость
# package-lock.json — точная фиксация всех версий (npm) npm install # npm-shrinkwrap.json — публикуется вместе с пакетом npm shrinkwrap # Игнорирование lock-файла при установке npm install --no-save3. Установка пакетов из различных источников
3.1 Установка из npm реестра
# Последняя версия npm install express # Конкретная версия npm install express@4.17.1 # Диапазон версий npm install "express@>=4.17.0 <5.0.0" # Последняя beta-версия npm install express@latest-beta # Dev-зависимость npm install --save-dev typescript # Global установка npm install -g pm2 # Без сохранения в package.json npm install lodash --no-save3.2 Установка из GitHub
# Из главной ветки репозитория npm install github:username/repository # Из определённой ветки npm install github:username/repository#branch-name # Из конкретного коммита npm install github:username/repository#commit-sha # С прямым URL на репозиторий npm install https://github.com/username/repository.git # Из приватного репозитория (требует токена) npm install git+https://github.com/username/private-repo.gitКонфигурация для приватных репозиториев:
# Глобально для github.com npm config set git+https://github.com/:_authToken YOUR_TOKEN # Или через .npmrc echo "//github.com/:_authToken=YOUR_TOKEN" >> ~/.npmrc3.3 Локальная установка пакетов
# Установка из локальной папки (npm) npm install ../my-local-package # Через npm link (создаёт symlink) cd ~/my-library npm link cd ~/my-project npm link my-library # Прямой путь в package.json { "dependencies": { "my-package": "file:../my-local-package" } } # Установка из tar-архива npm install ./package.tar.gz # Установка из zip npm install ./package.zipОсобенность npm link: создаёт глобальную symlink-ссылку, которая работает с различными проектами для локальной разработки.
3.4 Установка с пользовательского реестра
# Конкретный реестр для scoped-пакета npm config set @myorg:registry https://private-registry.example.com # Или в .npmrc @myorg:registry=https://private-registry.example.com //private-registry.example.com/:_authToken=TOKEN # Установка из приватного реестра npm install @myorg/private-package4. Жизненный цикл npm скриптов и хуки
4.1 Полный жизненный цикл npm команд
npm имеет систему хуков, которые выполняются на разных этапах выполнения команд. Это позволяет автоматизировать разработку и развертывание приложений.
Общий порядок выполнения:
pre<command> → <command> → post<command>Каждая npm команда может быть окружена
preиpostскриптами, которые выполняются автоматически.4.2 Жизненный цикл install и postinstall
postinstall— это один из самых важных и часто используемых хуков в npm. Он выполняется сразу после успешной установки зависимостей.Когда выполняется:
- После
npm install(установка всех зависимостей) - После
npm ci(clean install) - После любой операции, которая модифицирует
node_modules(например,npm link) - Для каждого пакета отдельно — если пакет имеет собственный
postinstall, он выполняется при установке этого пакета
Для чего нужен:
- Компиляция нативных модулей (например,
node-gypдля пакетов с C++ кодом) - Создание необходимых директорий и файлов конфигурации
- Загрузка дополнительных ресурсов
- Генерация типов TypeScript или документации
- Инициализация пакета
- Установка Git хуков (например, через
husky) - Кэширование или оптимизация
Пример использования в package.json:
{ "name": "my-app", "version": "1.0.0", "scripts": { "postinstall": "node scripts/setup.js && npm run build:types", "build:types": "tsc --emitDeclarationOnly" } }Практический пример — установка Git хуков через Husky:
{ "name": "my-project", "devDependencies": { "husky": "^8.0.0" }, "scripts": { "postinstall": "husky install" } }При выполнении
npm installбудут автоматически установлены Git хуки.Пример — компиляция нативных модулей:
Для пакетов типа
node-sqlite3илиbcrypt, которые содержат нативный код:{ "name": "sqlite3", "scripts": { "postinstall": "node-gyp rebuild" } }4.3 Полный цикл жизненных циклов npm команд
Цикл для
npm install:preinstall → install → postinstallЦикл для
npm version:preversion → version → postversionЦикл для
npm publish:prepublishOnly → prepare → prepublish → publish → postpublishЦикл для пользовательских скриптов:
npm run build # Выполнится в этом порядке: # 1. prebuild (если существует) # 2. build # 3. postbuild (если существует)4.4 Другие важные хуки
preinstall
Выполняется перед установкой зависимостей. Используется редко.
Для чего:
- Проверка версии Node.js
- Предварительная валидация окружения
- Отказ в установке если не соблюдены требования
{ "scripts": { "preinstall": "node -v && npm -v" } }prepare
Выполняется:
- После
npm install - После
npm ci - Перед
npm publish - Когда пакет устанавливается из Git репозитория
Для чего:
- Компиляция TypeScript в JavaScript
- Генерация файлов
- Подготовка пакета к публикации
Часто используется вместо
postinstallдля более надёжного выполнения.{ "scripts": { "prepare": "npm run build", "build": "tsc" } }prepublishOnly
Выполняется только перед публикацией (
npm publish), но не при локальной установке.Для чего:
- Запуск тестов перед публикацией
- Проверка версии
- Очистка артефактов
- Финальная валидация кода
{ "scripts": { "prepublishOnly": "npm run test && npm run lint && npm run build" } }Различие между
prepareиprepublishOnly:Хук npm install npm ci npm publish Git install prepare



prepublishOnly



postversion
Выполняется после обновления версии в
package.jsonс помощьюnpm version.Для чего:
- Автоматический коммит и тег в Git
- Публикация пакета
- Уведомление о новой версии
{ "scripts": { "postversion": "git push && git push --tags && npm publish" } }4.5 Цикл для глобальной установки пакетов
Когда устанавливается глобальный пакет с
npm install -g, хуки работают иначе:npm install -g my-cli-tool # Выполнится: preinstall → install → postinstallНо для глобальных пакетов
postinstallдолжен выполняться с осторожностью, так как может повлиять на всю систему.4.6 Практический пример комплексного использования хуков
{ "name": "@company/my-library", "version": "1.2.0", "scripts": { "preinstall": "node scripts/check-node-version.js", "postinstall": "husky install && npm run generate:types", "prepare": "npm run build", "prebuild": "npm run clean && npm run lint", "build": "tsc && esbuild src/index.ts --bundle --outfile=dist/index.js", "postbuild": "npm run test", "prepublishOnly": "npm run test:full && npm run audit", "postpublish": "npm run notify:slack", "postversion": "git push && git push --tags" } }Порядок выполнения при различных командах:
При
npm install:1. preinstall (проверка версии Node.js) 2. postinstall (установка Git хуков и генерация типов) 3. prepare (компиляция кода)При
npm run build:1. prebuild (очистка, линтинг) 2. build (основная компиляция) 3. postbuild (запуск тестов)При
npm publish:1. prepublishOnly (полное тестирование и аудит) 2. prepare (компиляция) 3. publish (публикация в npm) 4. postpublish (уведомление в Slack)При
npm version patch:1. preversion (проверки) 2. version (обновление версии) 3. postversion (Git push и публикация)5. Разработка и публикация собственных библиотек
5.1 Инициализация и структура проекта
npm init -y npm linkСтруктура стандартной библиотеки:
my-library/ ├── package.json ├── package-lock.json ├── README.md ├── .npmignore # Что исключить из публикации ├── .gitignore ├── src/ │ └── index.ts ├── dist/ # Скомпилированный код ├── types/ # TypeScript definitions ├── tests/ └── .github/workflows/ # CI/CD5.2 Конфигурация package.json для библиотеки
{ "name": "@username/my-library", "version": "1.0.0", "description": "Краткое описание", "main": "dist/index.js", "types": "types/index.d.ts", "exports": { ".": { "import": "./dist/index.mjs", "require": "./dist/index.js", "types": "./types/index.d.ts" }, "./package.json": "./package.json" }, "files": [ "dist", "types", "README.md" ], "scripts": { "build": "tsc && esbuild src/index.ts --bundle --outfile=dist/index.js", "test": "jest", "prepublishOnly": "npm run build && npm run test", "version": "npm run format && git add -A src" }, "keywords": [ "useful", "keywords" ], "author": "Your Name", "license": "MIT", "peerDependencies": { "react": ">=16.8.0" }, "repository": { "type": "git", "url": "https://github.com/username/my-library.git" }, "bugs": { "url": "https://github.com/username/my-library/issues" }, "homepage": "https://github.com/username/my-library#readme" }Критические поля:
main— entry point для CommonJStypes— путь к TypeScript definitionsexports— conditional exports для разных модульных системfiles— массив файлов/папок для включения в пакетprepublishOnly— выполняется перед публикацией
5.3 Настройка для ESM и CJS одновременно
{ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.js" }, "./package.json": "./package.json" } }Скрипт build для обеих систем:
# package.json scripts "build": "npm run build:cjs && npm run build:esm", "build:cjs": "tsc --module commonjs --outDir dist --declaration", "build:esm": "tsc --module es2020 --outDir dist --outFileExtension .mjs"5.4 Публикация в npm
# Версионирование npm version major # 1.0.0 → 2.0.0 npm version minor # 1.0.0 → 1.1.0 npm version patch # 1.0.0 → 1.0.1 # Публикация (требует npm аккаунт) npm login npm publish # Публикация scoped-пакета как public npm publish --access public # Pre-release версия npm publish --tag beta npm install my-package@beta # Распубликование старой версии npm publish --force # Отмена публикации (только в первые 72 часа) npm unpublish my-package@1.0.05.5 CI/CD для автоматической публикации
.github/workflows/publish.yml:
name: Publish to npm on: push: tags: - 'v*' jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' registry-url: 'https://registry.npmjs.org' - run: npm ci - run: npm run build - run: npm run test - run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}6. Оптимизация и производительность
6.1 Анализ размера bundle
# Анализ зависимостей npm ls # Размер пакета перед публикацией npm pack # Отчёт об использовании диска npm ls --depth=0 # Поиск дублирующихся версий npm dedupe6.2 Виртуальные зависимости и workspaces
# Инициализация монорепозитория npm init -w ./packages/package-a npm init -w ./packages/package-broot package.json:
{ "name": "my-monorepo", "private": true, "workspaces": [ "packages/*" ] }Команды для workspaces:
# Установка для всех workspaces npm install # Запуск скрипта для конкретного workspace npm run build -w ./packages/package-a # Добавление зависимости в workspace npm install lodash -w ./packages/package-a # Линк между internal пакетами автоматический6.3 Снижение размера установки
# Production-only установка (без devDependencies) npm install --production # Чистка кэша npm cache clean --force # Деструктивная оптимизация (удаление дублей) npm dedupe --force # Игнорирование опциональных зависимостей npm install --no-optional7. Продвинутые техники
7.1 npm scripts и автоматизация
{ "scripts": { "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", "prebuild": "npm run clean", "build": "tsc", "postbuild": "npm run test", "start": "node dist/index.js", "dev": "ts-node src/index.ts", "lint": "eslint src --fix", "format": "prettier --write 'src/**/*'", "precommit": "npm run lint && npm run test" } }Жизненный цикл скриптов:
pre{script}— выполняется перед скриптом{script}— сам скриптpost{script}— выполняется после скрипта
7.2 Переменные окружения и конфигурация
# npm-переменные доступны в скриптах через process.env npm_package_name npm_package_version npm_package_main # Передача переменных npm run build -- --production # Конфигурация через .npmrc npm-auth-token=abc123 registry=https://registry.npmjs.org7.3 Работа с приватными пакетами
.npmrc для приватного реестра:
@myorg:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=github_tokenИли переменная окружения:
export NPM_TOKEN=your_token echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc7.4 Версионирование и теги
# Публикация на конкретный тег npm publish --tag experimental npm install my-package@experimental # Перемещение тега npm dist-tag add my-package@1.0.0 latest npm dist-tag rm my-package experimental # Просмотр всех тегов пакета npm dist-tag ls my-package8. Отладка и диагностика
8.1 Логирование и verbose-режим
# Подробный лог всех операций npm install --verbose # Максимальный уровень логирования npm --loglevel verbose install # Очистка логов npm cache clean --force # Проверка целостности установки npm audit npm audit fix8.2 Разрешение проблем с зависимостями
# Поиск конфликтов peer-зависимостей npm ls # Принудительное переустановление npm ci # clean install с lock-файла # Очистка node_modules rm -rf node_modules package-lock.json npm install # Диагностика проблем с путями npm config get prefix npm list -g # Удаление осиротевших пакетов npm prune npm prune --production8.3 Отладка хуков и скриптов
# Просмотр всех конфигурированных скриптов npm run # Выполнение скрипта с максимальным логированием npm run build --verbose # Проверка конкретного хука (без фактического выполнения) npm run --dry-run postinstall # Просмотр переменных окружения доступных в скриптах npm run env9. Лучшие практики
При разработке библиотек:
- Используйте
exportsдля условных импортов вместоmain - Поставляйте TypeScript definitions или используйте
@types - Регулярно запускайте
npm auditдля проверки уязвимостей - Поддерживайте
peerDependenciesв актуальном состоянии - Используйте semantic versioning строго
- Документируйте breaking changes в CHANGELOG
- Автоматизируйте публикацию через CI/CD
- Используйте
prepublishOnlyдля финальной валидации перед публикацией - Используйте
postinstallдля инициализации необходимых ресурсов (Git хуки, компиляция нативного кода)
При работе с зависимостями:
- Регулярно обновляйте пакеты:
npm update - Проверяйте уязвимости:
npm audit - Используйте lock-файлы в version control
- Минимизируйте количество зависимостей
- Проверяйте лицензии:
npm ls --depth=0 - Избегайте использования
postinstallв публичных пакетах если это не критично (замедляет установку)
При локальной разработке:
- Используйте
npm linkдля синхронной разработки нескольких пакетов - Настройте правильные
.npmignoreиfilesполя - Тестируйте локально через
npm packперед публикацией - Используйте workspaces для монорепозиториев
- Проверяйте выполнение хуков локально перед коммитом
- Используйте
npm run --dry-runдля тестирования скриптов
При настройке хуков:
- Всегда заканчивайте
postinstallскрипты успешно (exit code 0) - Избегайте долгих операций в
postinstall(замедляют установку) - Используйте
prepareвместоpostinstallдля более надёжного выполнения в различных сценариях - Используйте
prepublishOnlyдля критических проверок перед публикацией - Документируйте, что делают ваши хуки в README
- Тестируйте хуки в CI/CD среде перед публикацией
Заключение
npm — это мощный инструмент, который выходит далеко за пределы простой установки пакетов. Понимание системы жизненного цикла и хуков (особенно
postinstallиprepublishOnly) позволяет автоматизировать критические операции и обеспечивает надёжное развертывание приложений. Для опытного разработчика овладение механизмами разрешения зависимостей, публикации собственных библиотек, настройки хуков и оптимизации рабочих процессов — критически важно для создания надёжных и масштабируемых проектов. Глубокое знание npm позволяет избежать множества типичных ошибок и значительно ускоряет разработку. - Реестр npm (
© 2024 - 2025 ExLends, Inc. Все права защищены.