Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке package-lock.json?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**package-lock.json** фіксує точну версію, URL реєстру і SHA-512 хеш цілісності кожної залежності Node.js-проєкту (прямої та транзитивної). ```json { "express": { "version": "4.18.2", "integrity": "sha512-..." } } ``` **Головне:** комітьте в git і використовуйте `npm ci` в CI/CD для гарантованих однакових встановлень.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**package-lock.json** - це файл, який npm генерує автоматично. Він фіксує точну версію кожної залежності, включно з транзитивними, щоб `npm install` давав однаковий результат на будь-якій машині. ## Теорія ### TL;DR - **Аналогія:** package.json - це рецепт: "борошно версії 4.x." package-lock.json - товарний чек: "партія 4.17.21 від постачальника X." - Головна різниця: package.json дозволяє діапазони версій; package-lock.json фіксує конкретне дерево залежностей. - `npm ci` читає lockfile строго і зупиняється при будь-якому розходженні. `npm install` може оновити версії в межах дозволених діапазонів. - Завжди комітьте package-lock.json. Ніколи не додавайте його в .gitignore. ### Швидкий приклад ```bash # package.json дозволяє діапазон версій echo '{"dependencies":{"lodash":"^4.17.0"}}' > package.json npm install # Встановлює lodash@4.17.21, створює package-lock.json # На іншій машині або в CI: npm ci # Встановлює рівно lodash@4.17.21, не "останню доступну" ``` `npm ci` спочатку видаляє `node_modules`, потім відновлює з lockfile. Без сюрпризів. ### Що зберігає lockfile Lockfile записує resolved-версію, URL реєстру і SHA-512 хеш цілісності для кожного пакету. Коли запускаєш `npm ci`, npm перевіряє ці хеші перед записом у `node_modules`. Якщо хеш не збігається, встановлення падає з помилкою. Спрощений запис виглядає так: ```json "express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", "integrity": "sha512-..." } ``` Це формат v3, запроваджений у npm 7. Він містить усі підняті (hoisted) пакети і їхні транзитивні залежності у пласкій структурі. ### Ключова різниця package.json каже "потрібен express версії приблизно 4.18.x." Реєстр може видати 4.18.2 сьогодні і 4.18.5 наступного місяця. package-lock.json записує, що саме було встановлено. Без lockfile два розробники, що запустили `npm install` з різницею в тиждень, можуть отримати різні версії транзитивної залежності, яку вони взагалі не додавали. І один з них отримає баг у продакшені. ### Коли що використовувати - Командний проєкт: комітьте lockfile, запускайте `npm ci` в CI/CD. - Dockerfile для продакшену: `RUN npm ci --omit=dev`, не `RUN npm install`. - Соло-прототип: однаково комітьте. Майбутній ти скажеш дякую. - Потрібно оновити конкретний пакет: `npm update lodash`. Не видаляйте lockfile. ### Типові помилки **1. Додавати package-lock.json у .gitignore** Це найпоширніше джерело "у мене працює, у тебе ні." Кожен розробник отримує трохи різні транзитивні залежності. ```bash # Неправильно: package-lock.json в .gitignore # Розробник A отримує lodash@4.17.21 # Розробник B тиждень потому отримує lodash@4.17.22 (інша поведінка в одному edge case) ``` Виправлення: приберіть з .gitignore і закомітьте. **2. Використовувати `npm install` в CI замість `npm ci`** ```dockerfile # Неправильно RUN npm install # Може оновити версії якщо діапазони дозволяють # Правильно RUN npm ci --omit=dev ``` `npm install` може автоматично підтягнути новішу версію. `npm ci` вважає будь-яке розходження жорсткою помилкою і зупиняє білд. **3. Видаляти lockfile для вирішення merge-конфліктів** ```bash rm package-lock.json && npm install # Резолвить усе з нуля ``` Це підтягне останні дозволені версії всіх пакетів у твоїх діапазонах. Ти втрачаєш історію залежностей і можеш отримати регресії. Для конкретних конфліктів краще `npm install <package>` або `npm dedupe`. **4. Змішувати пакетні менеджери в одному проєкті** Якщо в проєкті є package-lock.json, не запускай `yarn install` для додавання пакету. Отримаєш два lockfile з різними деревами залежностей. Обирай один менеджер і дотримуйся його. ### Де зустрічається Я бачив продакшн-інцидент, де транзитивна залежність випустила мінорну версію зі зламаним JSON-парсером. Команда комітила package-lock.json, але використовувала `npm install` у пайплайні, і оновлення проскочило. Перехід на `npm ci` зупинив аналогічну проблему наступного разу. - React-застосунки: фіксує `react@18.2.0` і `scheduler@0.23.0` разом для стабільного рендерингу. - Express-сервери: закріплює `helmet@7.1.0`, щоб оновлення middleware не змінило поведінку між деплоями. - Next.js: фіксує `webpack@5.89.0` для передбачуваного результату білду. - Docker-образи: `npm ci` у Dockerfile гарантує відповідність контейнера тому, що тестували локально. ### Питання на співбесіді **Q:** Яка різниця між `npm install` і `npm ci`? **A:** `npm install` створює або оновлює lockfile і встановлює пакети. `npm ci` видаляє `node_modules`, читає lockfile без змін і падає, якщо package.json і lockfile розходяться. Для CI/CD і Docker використовуй `npm ci`. **Q:** Чи потрібно комітити package-lock.json для npm-бібліотеки (не застосунку)? **A:** Ні. Бібліотеки комітять тільки package.json. Lockfile бібліотеки нав'язував би конкретні транзитивні версії всім, хто її встановлює. **Q:** Що станеться, якщо хеш цілісності в lockfile не збігається з реєстром? **A:** npm перезавантажує тарбол за `resolved` URL і повторно перевіряє SHA-512. Якщо все одно не збігається, встановлення завершується помилкою цілісності. Це захист від підміни пакетів. **Q:** У монорепо з npm workspaces - один lockfile чи кілька? **A:** Один, в корені. npm піднімає (hoist) спільні залежності в кореневий `node_modules` і записує повне дерево workspaces в цей єдиний файл. ## Приклади ### Фіксація залежностей для Express-застосунку ```json // package.json { "dependencies": { "express": "^4.18.0", "helmet": "^7.0.0" } } ``` ```bash npm install # package-lock.json тепер містить: # express@4.18.2 з повним деревом транзитивних залежностей # helmet@7.1.0 з повним деревом транзитивних залежностей ``` Карет (^) у package.json дозволяє все від 4.18.0 до (не включаючи) 5.0.0. Lockfile обирає одну версію і тримається за неї. Коли наступного місяця вийде 4.19.0, `npm ci` однаково встановить 4.18.2 скрізь. ### npm ci у Dockerfile для продакшену ```dockerfile FROM node:20-alpine WORKDIR /app # Копіюємо файли пакетів перед вихідним кодом COPY package.json package-lock.json ./ # Встановлюємо точні версії з lockfile, без dev-залежностей RUN npm ci --omit=dev COPY . . CMD ["node", "index.js"] ``` Копіювання package.json і package-lock.json перед рештою вихідного коду дозволяє Docker кешувати шар з `npm ci`. Якщо змінились тільки вихідні файли, Docker використовує кешований `node_modules` і білд стає швидшим. Якщо змінився будь-який з файлів пакетів, Docker інвалідує кеш і перевстановлює залежності.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.