Вы когда-нибудь задумывались о том, что собираетесь зафиксировать свой код и что делать с файлом 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 создаст файл \ update package-lock.json, который позволяет заблокировать все версии для всего дерева зависимостей.
  • Используйте npm install для добавления новых зависимостей, обновления зависимостей и после получения изменений из исходного репозитория.
  • Используйте npm ci во время непрерывной интеграции.

Заключение

При работе над общим проектом настоятельно рекомендуется зафиксировать файл блокировки пакета в системе управления версиями: это позволит любому члену вашей команды, вашим развертываниям, вашей непрерывной интеграции и всем, кто запускает npm install в исходном коде вашего пакета, получить точно такое же дерево зависимостей, на котором вы разрабатывали.

Подробнее

Package.json

Package-lock.json

Семантические версии

Npm-install

Нпм-чи

Npm-термоусадочная пленка

Спасибо за прочтение. Не стесняйтесь делиться!