Вы когда-нибудь задумывались о том, что собираетесь зафиксировать свой код и что делать с файлом package-lock.json? Давайте поговорим об этом.
TL;DR
- Если вы работаете над общим проектом с несколькими разработчиками и хотите, чтобы установки оставались идентичными для всех разработчиков и сред, вам необходимо использовать
package-lock.json
. package-lock.json
автоматически создается для любых операций, где npm изменяет деревоpackage.json
илиnode_modules
(по умолчанию с npm ^ 5.x.x).- Если
package.json
был обновлен новым модулем или более новой версией, он будет иметь приоритет над _6 _ (^ v5.1.0). - Новая команда
npm ci
(для CI / CD) устанавливается только из файла блокировки пакета. Еслиpackage.json
иpackage-lock.json
не синхронизированы, он сообщит об ошибке (npm ^ 5.7.1). - файл блокировки пакета должен быть зафиксирован в исходных репозиториях.
Вступление
npm в двух словах
npm - наиболее распространенный менеджер пакетов для JavaScript. Он состоит из клиента командной строки, также называемого npm, и онлайн-базы данных общедоступных и оплачиваемых частных пакетов, называемой реестром npm.
package.json
Все пакеты npm определены в файлах с именем package.json. Содержимое package.json должно быть записано в формате JSON , а в файле определения должны присутствовать как минимум два поля: имя и версия. В этом файле также определены зависимости.
npm install
Команда npm instal
устанавливает все пакеты, определенные в файле package.json, и их зависимости в папку node_modules
, создавая ее, если она еще не существует.
Вы можете установить определенный пакет, запустив npm install <package-name>.
Флаг --save
устанавливает и добавляет запись в файл package.json dependencies (по умолчанию с npm 5).
Управление версиями пакетов
npm работает со схемой семантические версии (semver): (MAJOR.MINOR.PATCH)
.
Когда вы устанавливаете пакет с помощью npm, в ваш package.json добавляется запись, содержащая имя пакета и semver, которые следует использовать. Если вы не укажете точную версию, npm установит последнюю версию (версия с тегом latest
в реестре NPM).
npm поддерживает следующие подстановочные знаки в этом определении semver:
Все версии по умолчанию имеют префикс ^
(каретка). Это означает, что изменения разрешены до MINOR
части. Так, например, наличие зависимости от версии ^1.3.1
означает, что и 1.3.5
, и 1.4.0
будут считаться действительными, и будет использоваться «самая последняя» из них, если она доступна.
Аналогичная логика применима к ~
(тильда). Если используется перед номером версии, это означает: разрешить только PATCH
segment изменения. Итак, в приведенном выше примере, если бы у нас было ~3.2.3
, единственным подходящим кандидатом из этих двух был бы 3.2.4
.
Команды npm outdated
и npm update
позволяют отслеживать и обновлять зависимости соответственно в соответствии с определенными диапазонами.
Зависимости
Дерево зависимостей
npm устанавливает дерево зависимостей, где каждый установленный пакет получает свой собственный набор зависимостей, даже если он имеет общую зависимость с другим пакетом.
Это означает, что npm может устанавливать разные версии одного и того же пакета. Например, если у нас есть два пакета A и B с общей зависимостью «dep_A», каждый пакет может использовать разные версии «dep_A». Результирующая структура каталогов будет следующей:
node_modules/
├── package_A/
│ └── node_modules/
│ ├── dep_A/
│ └── dep_B/
└── package_b/
└── node_modules/
├── dep_A/
└── dep_C/
Фактически, каждая зависимость будет иметь свой собственный каталог node_modules
и так далее.
- npm ^ 3.X.X выполняет некоторые оптимизации, чтобы попытаться поделиться зависимостями, когда это возможно.
Ад зависимости
Мы видели, что npm обрабатывает версии и зависимости, что может пойти не так?
При работе над общим проектом с процедурой развертывания вы хотите убедиться, что любой, кто устанавливает зависимости для проекта (разработчик, сервер CI и т. Д.), Каждый раз будет получать одни и те же результаты. Итак, очевидно, вы решили указать точную версию устанавливаемых зависимостей, но как насчет зависимостей этих зависимостей и т. Д.? - вы не можете контролировать полное дерево зависимостей.
Давайте посмотрим на общий случай:
Вы напрямую зависите от express
точной версии 4.17.1
- ›_ 31_ зависит от body-parser
диапазона ~1.17.4
-› _ 34_ зависит от accepts
диапазона~1.3.4
- ›и т. Д.
Вы можете управлять только экспресс-версией, но даже если вы вообще не трогали свой package.json
, вы могли получить другое дерево зависимостей, которое разрешалось двумя независимыми исполнениями npm install.
Блокировка пакета
Использование файлов блокировки гарантирует, что все результаты установки останутся идентичными и воспроизводимыми для всего дерева зависимостей каждый раз из любого места. Это делается путем указания версии, местоположения и хэша целостности.
Файлы блокировки предназначены для блокировки всех версий всего дерева зависимостей во время создания файла блокировки.
Пакет-lock.json
Файл блокировки npm, package-lock.json
, автоматически создается для любых операций, где npm изменяет либо package.json
, либо node_modules
дерево (по умолчанию с npm ^ 5.x.x).
Это означает, что при запуске npm install
будет сгенерирован package-lock.json
файл, если он не существовал с текущими версиями node_modules
.
Формат файла
Этот файл содержит отображение имени пакета на объект зависимости. Объекты зависимостей обладают следующими свойствами:
версия Это спецификатор, который однозначно идентифицирует этот пакет и должен быть использован при получении его новой копии.
dev Если true, то эта зависимость зависит только от разработки.
требует указывает список модулей, которые необходимы для правильного запуска и работы вашего приложения, независимо от того, где оно будет установлено. Версия должна соответствовать через нормальные правила соответствия являются зависимостью либо в нашем dependencies
, либо на более высоком уровне, чем мы.
Поле requires
в вашем файле блокировки будет использовать диапазоны. (по умолчанию с npm ^ 6.x.x)
зависимости. Зависимости этой зависимости точно так же, как на верхнем уровне.
Полный формат файла: https://docs.npmjs.com/files/package-lock.json
Так что же такого непонятного и почему разработчики продолжают удалять этот файл? До package-lock
единственным источником правды для установки был package.json
. Когда впервые была выпущена блокировка пакетов, изменение в package.json
не повлияло на блокировку пакетов, что не было интуитивно понятным для разработчиков, которые привыкли работать с package.json
.
Начиная с npm ^ 5.1.x поведение изменилось: package.json
будет отменять package-lock.json
, если package.json
был обновлен новым модулем или более новой версией, например:
- Если модуля нет в package-lock, но он есть в package.json - модуль будет установлен.
- Пакет A версии 1.0.0 существует как в package.json, так и в package-lock. Если пакет A редактируется вручную до версии 1.1.0 в package.json, будет установлена версия 1.1.0.
npm ci
Итак, package.json
и package-lock.json
могут жить вместе, но подождите, есть еще одна вещь, о которой нам нужно поговорить ...
Команда npm ci
, представленная в npm 5.7.0, игнорирует package.json
и устанавливает зависимости, указанные в package-lock.json
только.
npm ci
- это более быстрый и надежный способ установки зависимостей в тестовых средах, непрерывной интеграции или во время развертывания. Повышенная скорость и надежность сокращают потери времени и продвигают передовой опыт.
npm ci
устанавливается ТОЛЬКО из файла блокировки, поэтому вы должны зафиксировать файл блокировки.- Это намного быстрее (в 2–10 раз!), Чем
npm install.
- Если
package.json
и файл блокировки не синхронизированы, он сообщит об ошибке. - Он работает, выбрасывая ваши node_modules и воссоздавая их с нуля.
- Не изменится
package.json
илиpackage-lock.json.
Обновления версий
По умолчанию npm добавляет префикс каретки (^
) для диапазона SEMVER при установке зависимостей через npm install
(для включения функции закрепления и обновлений).
Это поведение по умолчанию можно изменить:
npm config set save-prefix='~'
устанавливает по умолчанию тильду.
npm config set save-exact true
удалит автоматический префикс.
Полезные команды
npm outdated:
Проверить наличие устаревших версий (показывает все установленные пакеты).
npm update
: обновите все перечисленные пакеты до последней версии, с соблюдением семвера.
npm-check-updates:
Проверить наличие устаревших версий (показаны только основные пакеты от package.json
).
npm-check-updates -u
: обновляет зависимости вашего package.json до последних версий, игнорируя указанные версии.
npm-audit:
Просканируйте ваш проект на наличие уязвимостей.
Лучшая практика
- При запуске нового проекта используйте
npm init
для созданияpackage.json
файла. - После того, как вы перечислили все пакеты, которые хотите использовать в своем проекте, установите и сохраните их, используя
npm install --save
. - Помните: npm по умолчанию сохранит ваши зависимости с префиксом
^
, чтобы сохранить точные версии, вы можете запуститьnpm config set save-exact true.
- Запуск
npm install
создаст файл \ updatepackage-lock.json
, который позволяет заблокировать все версии для всего дерева зависимостей. - Используйте
npm install
для добавления новых зависимостей, обновления зависимостей и после получения изменений из исходного репозитория. - Используйте
npm ci
во время непрерывной интеграции.
Заключение
При работе над общим проектом настоятельно рекомендуется зафиксировать файл блокировки пакета в системе управления версиями: это позволит любому члену вашей команды, вашим развертываниям, вашей непрерывной интеграции и всем, кто запускает npm install в исходном коде вашего пакета, получить точно такое же дерево зависимостей, на котором вы разрабатывали.
Подробнее
Спасибо за прочтение. Не стесняйтесь делиться!