Семантическая версия Система нумерации, на которую зависит ваш npm install

Обновлено

Три цифры Semver — это договор. MAJOR нарушает, MINOR добавляет, PATCH исправляет — и когда ваша сборка ломается после npm install, в девяносто случаях из ста кто-то игнорирует этот договор. Вот как работает система нумерации, что на самом деле делают ^ и ~ в package.json, и почему обязательным является коммит локального файла.

Семантическая версия: Система нумерации, на которую зависит ваш npm install 1
Реклама · УДАЛИТЬ?

Ваша сборка сломалась. Работало в пятницу. npm install в понедельник был втянут react-query@5 и теперь половина ваших хуков исчезла. Вы смотрите на стек-трейс, который раньше не существовал, и где-то в стороне собирается пыль в изменении версий.

Это история по semver. Конкретно, это ваша вина.

Что означают три цифры на самом деле

MAJOR.MINOR.PATCH — это всё. Три слота, три правила:

  • ОБНОВИТЬ (1.2.3 → 1.2.4): Исправление ошибки. В вашем коде ничего не нужно менять. Вам просто нужно меньше поведения, которое сломано.
  • МИНОР (1.2.3 → 1.3.0): Добавлена новая функция, совместима с обратной совместимостью. Вы не обязаны использовать её, но она есть.
  • МАЙОР (1.2.3 → 2.0.0): Что-то сломалось. Функция была переименована, удалена или изменила сигнатуру. Устаревший API исчез или работает иначе.

Ключевое слово в трёх случаях — обратная совместимость. МИНОР и ПАТЧ — это обещания: «мы не нарушили ничего, что вы уже использовали». МАЙОР — это предупреждение: «мы нарушили».

Когда поддерживатель повышает МАЙОР, и вы не замечаете, потому что фиксировали ^1.0.0 в package.json и файл с блокировками был устаревшим — это ваша вина. Спецификация работала ровно так, как и было предусмотрено.

Социальный контракт по semver

Semver — это конвенция, а не закон. Пакеты могут утверждать, что следуют за ним, и затем выпускать МИНОР с разрушающими изменениями. Когда это происходит, это плохая воля со стороны поддерживателя. Но когда пакет правильно повышает МАЙОР для сигнализации о разрушении и вы его втягиваете без осознания — вы сами нарушаете свою собственную сборку.

Это и есть причина существования изменений. Ввод CHANGELOG.md пункт, который гласит «Удалено устаревшее v1Api — используйте v2Api вместо» — это то, что поддерживатель выполняет свою часть. Не читать это — это ваша игнорирование своей части. Изменение — это двуминутное чтение. Сессия отладки, которую оно предотвращает, не может быть такой.

^ против ~ — реальные механизмы

В package.json, ^ (caret) и ~ (tilde) определяют диапазоны версий. Они выглядят похоже и ведут себя совершенно по-разному.

Caret (^): Позволяет любую версию, не повышающую МАЙОР. Это по умолчанию npm при запуске npm install some-package.

  • ^1.2.3 решает >=1.2.3 <2.0.0
  • ^0.2.3 решает >=0.2.3 <0.3.0 — особый случай: 0.x рассматривает МИНОР как разрушающий
  • ^0.0.3 решает >=0.0.3 <0.0.40.0.x фиксирует точно, без возможности изменений

Tilde (~): Позволяет обновления ПАТЧ только в рамках указанного МИНОР.

  • ~1.2.3 решает >=1.2.3 <1.3.0
  • ~1.2 решает >=1.2.0 <1.3.0 — то же самое, что ~1.2.0
  • ~1 решает >=1.0.0 <2.0.0 — эквивалентно ^1.0.0 на данном этапе

Примеры диапазонов версий

ДиапазонЧто он позволяетТочные совпадения
1.2.3То же самое версияТолько 1.2.3
^1.2.3Любые МИНОР/ПАТЧ ≥ 1.2.31.2.4, 1.3.0, 1.99.0 — НЕТ 2.0.0
^0.2.3ПАТЧ в пределах 0.2.x только0.2.4, 0.2.99 — НЕТ 0.3.0
~1.2.3ПАТЧ в пределах 1.2.x только1.2.4, 1.2.99 — НЕТ 1.3.0
~1.2Любое обновление ПАТЧ в 1.2.x1.2.0, 1.2.1, 1.2.99
>=1.2.3 <2.0.0Явный диапазонТо же самое, что и ^1.2.3
1.2.xЛюбое обновление ПАТЧ в 1.21.2.0, 1.2.1, 1.2.99
*Любое возможноеВсё, что чувствует npm сегодня

The * Диапазон — это стратегия «доверяй, не проверяй» по версиям. Вы не фиксируете ничего. Если библиотека выпускает полностью переписанную API, вы получите это на следующем v9.0.0 с чистым кэшем. Используйте только в приложениях на верхнем уровне, которые не зависят от других пакетов — и даже тогда, только если воспроизводимость действительно не важна для вас (она важна). npm install с чистой кэш-памятью. Используйте его только в приложениях первого уровня, которые не зависят от других пакетов — и даже тогда, только если воспроизводимость действительно не имеет для вас значения (она имеет).

Идентификаторы предварительных выпусков

Перед стабильным выпуском, поддерживатели ставят метку предварительного выпуска:

  • 1.0.0-alpha.1 — ранний, нестабильный, API, вероятно, всё ещё меняется
  • 1.0.0-beta.2 — функционально завершён, всё ещё подвергается тестированию, ожидайте некоторых несовершенств
  • 1.0.0-rc.1 — кандидат на выпуск, должен быть пригоден для производства, если не появится что-то в финальных тестах

Предварительные выпуски сортируются ниже стабильного выпуска: 1.0.0-alpha.1 < 1.0.0. И критически, ^1.0.0 установит нет — предварительные выпуски совпадают только в том случае, если вы явно указываете их в диапазоне. Это поведение предотвращает случайное включение альфа-версии, когда вы хотели отслеживать стабильные выпуски. 2.0.0-beta.1 — предварительные выпуски соответствуют только в том случае, если вы явно указываете их в диапазоне. Это поведение предотвращает случайное включение альфа-версии, когда вы хотели отслеживать стабильные выпуски.

Если вы используете пакет, который имеет только предварительные выпуски, фиксируйте полную строку версии: "some-package": "1.0.0-beta.2". Не используйте ^ или ~ с предварительными выпусками, если вы не знаете, что поддерживатель их тщательно относится — большинство не так делают.

Проверка диапазона до того, как вы его закрепите

Перед закреплением диапазона версий в package.json, стоит убедиться, что вы действительно соглашаетесь устанавливать. Инструмент Semver Version Calculator принимает диапазон версий и список кандидатов и показывает, какие из них совпадают — полезно, когда вы не уверены, охватывает ли ~2.3 конкретную версию, которую вам нужно, или когда вы рассматриваете запрос и диапазон кажется неправильным.

Три режима сбоев

Большинство сбоев, связанных с semver, следуют одному из трёх шаблонов:

  1. ^ + повышение МАЙОР + удалённый файл блокировки: Вы закрепили ^1.0.0, поддерживатель выпустил 2.0.0, файл блокировки был удалён или никогда не был зафиксирован, CI устанавливает 2.0.0. Исправление: зафиксируйте свой файл блокировки. В каждом проекте. Никаких исключений.
  2. * в библиотеке, которую вы публикуете: Вы — автор библиотеки, который использовал * для зависимости. Каждый пользователь, который использует ваш пакет, наследует вашу звёздочку. Вы сделали их граф зависимостей вашей проблемой. Исправление: используйте явные диапазоны в любом пакете, который вы публикуете в npm.
  3. Предварительный выпуск без файла блокировки: Разрешённый диапазон втянул 1.0.0-alpha.3, API изменился с alpha.1, ничего не работает. Исправление: явно фиксируйте предварительные выпуски и — скажите это со мной — зафиксируйте файл блокировки.

Читайте изменение

Когда выпускается версия МАЙОР для чего-либо в вашей зависимости, потратите две минуты на изменение. Разработчики написали его так, чтобы вы не пришлось разбираться в разрушении из стека-трейса в 3 часа ночи.

Если библиотека выпускает разрушающие изменения под МИНОР с отсутствием изменений — это плохая воля. Оставьте заявку. Назовите это публично. Но если МАЙОР был очевидным, руководство по миграции было подробным, и вы его втянули без проверки — инструменты сделали то, что вы и говорили. Контракт был написан в трёх цифрах. Вы просто не прочитали его.

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?