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 текущего проекта. Это удобно, если нужно по-быстрому что-то запустить.
Материалы
- Бесплатный курс JS: Настройка окружения
- What everybody should know about npm + слайды — местами устаревший доклад, но пока лучше ничего не нашел.
- Официальная документация NPM
Вопросы для самоконтроля
- Где искать модули?
- Как создать свой скрипт, чтоб запускать его через
npm run myscript? - Как понять, какой файл в NPM-пакете основной?
- Как установить пакет? Как сохранить его в проекте?
- Зачем нужен файл
package.json? Зачем нужен файлpackage-lock.json? - Как посмотреть список устаревших пакетов?
- Как обновить устаревший пакет из проекта?
- Что такое Semver и что значит каждая цифра в номерах версий?
- Как подключить пакет с GitHub? В чем недостаток такого метода и почему его нужно избегать в реальных проектах?