NPM

NPM — это пакетный менеджер, он управляет зависимостями. Наше приложение зависит от каких-то пакетов, а эти пакеты зависят от других пакетов и т. д.

Изначально NPM создан для NodeJS, но сейчас там очень много всего и для фронтэнда.

Установка

NPM устанавливается вместе с NodeJS. Его так же можно поставить на Мак с помощью brew или на Линукс с помощью apt.

При установке глобальных пакетов NPM (например, npm install -g webpack) могут вылетать EACCES-ошибки. Это связано с недостаточным уровнем доступа вашего пользователя к /usr/local, куда NPM ставит глобальные пакеты.

Не нужно устанавливать NPM-пакеты под sudo. Права доступа настраиваются парой команд из официального руководства.

Вообще, стоит отдать предпочтение работе только с локальными пакетами (которые устанавливаются в папку node_modules внутри проекта). Так у всех разработчиков на проекте будет одна и та же версия. См. ниже "Запуск бинарников локально". Исключения составляют проверялки кода (линтеры) и прочие не зависящие от конкретного проекта пакеты.

Версионирование

NPM использует соглашение semver: MAJOR.MINOR.PATCH.

При установке пакетов с флагом --save или --save-dev в package.json по-умолчанию записывается его версия с кочергой: ^1.2.3. Это значит, что при последующих установках NPM будет искать в репозитории пакеты не ниже версии 1.2.3, но не выше 2.0.0. То есть все патчи и минорные изменения.

Часто используется ~. Тильда позволяет устанавливать только патчи. Например, ~1.2.3 даст установить все версии 1.2.x до 1.3.0.

Можно установить пакет, жестко прописав его версию: npm install PACKAGE --save --save-exact. Тогда будет 1.2.3 и при последующих установках поиска обновлений не будет. Однако, наш пакет версии 1.2.3 имеет свой собственный package.json. И там уже могут быть нечеткие зависимости и с ^ и с ~.

Для того, чтобы NPM не искал обновления установленных пакетов (при релизе может быть не безопасно) дополнительно генерируется файл package-lock.json. Его нужно хранить в репозитории.

Соглашения

В наших проектах часто используются следующие NPM-скрипты в package.json:

  • npm run dev — запуск окружения для локальной фронтэнд-разработки. Нет минификации, запускается отдельный сервер для обслуживания ресурсов, все работает максимально быстро.
  • npm run prod — сборка ресурсов для продадкшена (запускается на CI) или локальной работы с собранными ресурсами, когда не нужно писать стили и JS (для бэкенд-разработки).

Скрипты, которые необходимо запускать в процессе работы с проектом, нужно упомянуть в README.md.

Запуск бинарников локально

Некоторые пакеты поставляются с утилитами, которые можно запускать из командной строки: gulp, webpack и пр. Симлинки на них NPM собирает в папке node_modules/.bin.

Если такой NPM-пакет упоминается в разделе "scripts" в package.json, то NPM будет пытаться его запустить локально, из папки node_modules, которая находится в проекте. А если он его там не найдет, то попытается найти глобально.

Так, если в package.json есть, например, скрипт "dev": "webpack-dev-server --hot", то, когда мы пишем в консоли npm run dev, запускается webpack-dev-server из папки node_modules, которая в проекте.

NPM с версии 5.2 поставляется вместе с утилитой npx, которая предназначена для запуска исполняемых файлов из локально установленных пакетов без создания npm run ... скриптов. Так npx webpack-dev-server запустить WDS из node_modules текущего проекта. Это удобно, если нужно по-быстрому что-то запустить.

Материалы

Вопросы для самоконтроля

  • Где искать модули?
  • Как создать свой скрипт, чтоб запускать его через npm run myscript?
  • Как понять, какой файл в NPM-пакете основной?
  • Как установить пакет? Как сохранить его в проекте?
  • Зачем нужен файл package.json? Зачем нужен файл package-lock.json?
  • Как посмотреть список устаревших пакетов?
  • Как обновить устаревший пакет из проекта?
  • Что такое Semver и что значит каждая цифра в номерах версий?
  • Как подключить пакет с GitHub? В чем недостаток такого метода и почему его нужно избегать в реальных проектах?