Пошук уроків, статей та іншого контенту
Навчимося читати правила Semantic Versioning і задавати безпечні діапазони версій пакетів.
Semantic Versioning, або SemVer, — це правило запису версій програмних пакетів.
Версія має формат:
MAJOR.MINOR.PATCHНаприклад:
2.4.1Кожна частина має своє значення:
MAJOR — несумісні зміни, які можуть зламати код користувачів;
MINOR — нова функціональність без порушення сумісності;
PATCH — виправлення помилок без зміни публічного API.
Тому версія 2.4.1 читається так:
2 — основна версія;
4 — четверте розширення функціональності для версії 2;
1 — перше виправлення помилок у цій версії.
Припустімо, пакет має версію 1.4.2.
Виправили помилку, але не змінили API:
1.4.2 → 1.4.3Зазвичай таку версію можна оновлювати без зміни коду застосунку.
Додали нову можливість, не ламаючи вже наявний код:
1.4.2 → 1.5.0Старі функції повинні продовжити працювати.
Змінили API несумісним способом:
1.4.2 → 2.0.0Після такого оновлення може знадобитися змінити код застосунку.
SemVer описує очікування від авторів пакетів. Це корисний стандарт, але він не гарантує, що кожен пакет ідеально дотримується правил.
package.jsonЗалежності Node.js-проєкту зазвичай записують у файлі package.json.
Наприклад:
{
"name": "weather-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2",
"dotenv": "~16.3.1",
"date-fns": "2.30.0"
}
}Тут для кожного пакета задано свій діапазон версій:
^4.18.2 — дозволяє сумісні оновлення;
~16.3.1 — дозволяє лише оновлення виправлень;
2.30.0 — дозволяє тільки конкретну версію.
Символи ^ і ~ називають операторами діапазону версій.
Запис без операторів означає точну версію:
{
"dependencies": {
"date-fns": "2.30.0"
}
}Такий запис не дозволяє npm вибирати іншу версію пакета в межах діапазону.
Точні версії корисні, коли:
потрібна максимально передбачувана збірка;
пакет критично важливий для застосунку;
команда хоче оновлювати залежності лише вручну.
Однак навіть за наявності точних версій прямих залежностей потрібно зважати на транзитивні залежності — пакети, які встановлюються через інші пакети.
^Оператор ^ дозволяє оновлення, які не змінюють першу ненульову частину версії.
Для звичайної версії 1.x це означає оновлення до наступної MAJOR-версії:
^1.4.2 означає >=1.4.2 і <2.0.0Отже, можуть бути встановлені такі версії:
1.4.3
1.5.0
1.9.7А такі — ні:
1.4.1
2.0.0Для пакета з версією 0.x правила обережніші.
^0.4.2 означає >=0.4.2 і <0.5.0А для версії, де нульові і MAJOR, і MINOR:
^0.0.5 означає >=0.0.5 і <0.0.6Це важливо, бо версії 0.x часто використовують для пакетів, API яких ще не вважається стабільним.
~Оператор ~ дозволяє оновлення PATCH-версії в межах поточної MINOR-версії:
~1.4.2 означає >=1.4.2 і <1.5.0Можливі версії:
1.4.3
1.4.9Неможливі:
1.4.1
1.5.0
2.0.0Порівняння:
^1.4.2 → від 1.4.2 до версій перед 2.0.0
~1.4.2 → від 1.4.2 до версій перед 1.5.0
1.4.2 → лише 1.4.2Вибір залежить від того, які оновлення ви готові приймати автоматично.
Для більшості стабільних пакетів часто використовують:
{
"dependencies": {
"express": "^4.18.2"
}
}Це дозволяє отримувати нові MINOR- і PATCH-версії, але не переходити автоматично на нову MAJOR-версію.
Використовуйте ~:
{
"dependencies": {
"some-package": "~1.4.2"
}
}Так застосунок отримає виправлення помилок, але не нову MINOR-функціональність.
Використовуйте точну версію:
{
"dependencies": {
"some-package": "1.4.2"
}
}Це зменшує кількість несподіваних змін, але оновлення доведеться виконувати вручну.
Створимо невеликий Node.js-проєкт і встановимо пакет із діапазоном версій.
mkdir semver-demo
cd semver-demo
npm init -y
npm install lodash@^4.17.21Після цього в package.json з’явиться залежність, приблизно така:
{
"dependencies": {
"lodash": "^4.17.21"
}
}У проєкті можна використовувати пакет:
const _ = require('lodash');
const values = [3, 1, 2, 3];
console.log(_.uniq(values));Результат:
[ 3, 1, 2 ]Діапазон ^4.17.21 дозволяє npm встановити версію 4.x.x, яка не нижча за 4.17.21, але не дозволяє автоматично перейти на 5.0.0.
package-lock.jsonПісля встановлення залежностей npm створює або оновлює файл package-lock.json.
У ньому фіксуються конкретні версії встановлених пакетів. Тому є різниця між:
версією або діапазоном у package.json;
фактично встановленою версією в package-lock.json.
Наприклад:
{
"dependencies": {
"lodash": "^4.17.21"
}
}Дозволяє різні сумісні версії 4.x, але lock-файл може зафіксувати конкретну:
4.17.21Lock-файл варто додавати до системи контролю версій. Це допомагає різним розробникам і середовищам отримувати однакове дерево залежностей.
Якщо потрібно встановити залежності саме за lock-файлом, використовують:
npm ciЦя команда призначена для чистих і відтворюваних встановлень, зокрема в CI-середовищах.
Для версій, які ще не готові до стабільного використання, застосовують позначки:
2.0.0-alpha.1
2.0.0-beta.2
2.0.0-rc.1Їхнє призначення:
alpha — рання тестова версія;
beta — версія для ширшого тестування;
rc — кандидат на фінальний реліз.
Попередні версії можуть містити зміни або помилки, яких немає у стабільних релізах. Тому їх зазвичай не встановлюють у production без особливої потреби.
^ і ~^1.2.3 → дозволяє MINOR- і PATCH-оновлення
~1.2.3 → дозволяє лише PATCH-оновленняЯкщо потрібні тільки виправлення, ^ може дозволити більше змін, ніж ви очікуєте.
0.xЗапис:
^0.4.2не означає діапазон до 1.0.0. Він обмежений версіями, меншими за 0.5.0.
Для пакетів 0.x потрібно уважно перевіряти правила сумісності.
package-lock.json без причиниLock-файл допомагає відтворити встановлення залежностей. Його видалення може призвести до встановлення інших транзитивних версій і несподіваних помилок.
Навіть якщо пакет використовує SemVer, помилка в реалізації або неправильне маркування релізу можливі. Перед оновленням важливих залежностей перевіряйте зміни та запускайте тести.
latest як звичайну версію залежностіМітка latest може вказувати на новий реліз у майбутньому. Для передбачуваних залежностей краще використовувати конкретну версію або явний діапазон.
Версія SemVer має формат MAJOR.MINOR.PATCH.
MAJOR означає несумісні зміни.
MINOR додає сумісну функціональність.
PATCH містить виправлення помилок.
^1.4.2 дозволяє версії від 1.4.2 до версій перед 2.0.0.
~1.4.2 дозволяє версії від 1.4.2 до версій перед 1.5.0.
Точна версія, наприклад 1.4.2, забороняє оновлення в межах діапазону.
Для версій 0.x оператор ^ працює обережніше.
package-lock.json фіксує фактично встановлені версії.
Безпечний діапазон залежить від того, чи потрібні автоматичні MINOR-оновлення, лише PATCH-оновлення або повна фіксація версії.