Почему "npm install" переписывает package-lock.json?
Я только недавно обновился до npm@5. Теперь у меня есть файл package-lock.json со всем из package.json. Я ожидаю, что когда я бегу npm install
что версии зависимостей будут извлечены из файла блокировки, чтобы определить, что должно быть установлено в моем каталоге node_modules. Что странно, так это то, что он на самом деле модифицирует и переписывает мой файл package-lock.json.
Например, для файла блокировки была указана машинописная версия версии 2.1.6. Затем, после npm install
команда, версия была изменена на 2.4.1. Это, кажется, побеждает всю цель файла блокировки.
Что мне не хватает? Как мне заставить npm действительно уважать мой файл блокировки?
14 ответов
Обновление 2: проблема для обновления и уточнения документации - проблема Github № 18103.
Обновление 1: Поведение, которое было описано ниже, было исправлено в npm 5.4.2: предполагаемое в настоящее время поведение описано в выпуске Github # 17979.
Оригинальный ответ: поведение package-lock.json
был изменен в npm 5.1.0, как обсуждалось в выпуске № 16866. Поведение, которое вы наблюдаете, очевидно, предназначено для npm начиная с версии 5.1.0.
Это означает, что package.json
может превзойти package-lock.json
всякий раз, когда более новая версия найдена для зависимости в package.json
, Если вы хотите эффективно закрепить свои зависимости, теперь вы должны указать версии без префикса, например, вам нужно записать их как 1.2.0
вместо ~1.2.0
или же ^1.2.0
, Тогда комбинация package.json
а также package-lock.json
даст воспроизводимые сборки. Чтобы было ясно: package-lock.json
один уже не блокирует зависимости корневого уровня!
Является ли это проектное решение было хорошо или не является спорным, существует постоянная дискуссия в результате этой путаницы на Github в вопросе # 17979. (На мой взгляд это сомнительное решение; хотя бы название lock
больше не соответствует действительности.)
Еще одно замечание: есть также ограничение для реестров, которые не поддерживают неизменяемые пакеты, например, когда вы извлекаете пакеты непосредственно из Github вместо npmjs.org. См. Эту документацию блокировок пакетов для дальнейшего объяснения.
Я обнаружил, что будет новая версия npm 5.7.1 с новой командой npm ci
, который будет установлен из package-lock.json
только
Новая команда npm ci устанавливается ТОЛЬКО из вашего файла блокировки. Если ваш package.json и файл блокировки не синхронизированы, он сообщит об ошибке.
Это работает, выбрасывая ваши node_modules и воссоздавая его с нуля.
Помимо гарантии того, что вы получите только то, что находится в вашем файле блокировки, это также намного быстрее (2x-10x!), Чем установка npm, если вы не запускаете с node_modules.
Как вы можете догадаться из названия, мы ожидаем, что оно станет большим благом для сред непрерывной интеграции. Мы также ожидаем, что люди, которые производят развертывание с использованием git-тегов, получат значительную выгоду
Короткий ответ:
- Когда существует package-lock.json, он отменяет package.json
- Когда package.json изменяется, он отменяет package-lock.json
Вот сценарий, который может объяснить вещи (проверено с помощью NPM 6.3.0)
Вы объявляете зависимость в package.json как:
"depA": "^1.0.0"
Тогда вы делаете, npm install
который сгенерирует пакет-lock.json с:
"depA": "1.0.0"
Несколькими днями позже выпущена более новая вспомогательная версия "depA", скажем "1.1.0", тогда справедливо следующее:
npm ci # respects only package-lock.json and installs 1.0.0
npm install # also, respects the package-lock version and keeps 1.0.0 installed
# (i.e. when package-lock.json exists, it overrules package.json)
Затем вы вручную обновляете свой package.json:
"depA": "^1.1.0"
Затем перезапустите:
npm ci # will try to honor package-lock which says 1.0.0
# but that does not satisfy package.json requirement of "^1.1.0"
# so it would throw an error
npm install # installs "1.1.0" (as required by the updated package.json)
# also rewrites package-lock.json version to "1.1.0"
# (i.e. when package.json is modified, it overrules the package-lock.json)
Используйте недавно представленный
npm ci
npm ci обещает наибольшую пользу крупным командам. Предоставление разработчикам возможности "подписаться" на блокировку пакета способствует более эффективной совместной работе больших групп, а возможность установки именно того, что находится в файле блокировки, может сэкономить десятки, если не сотни часов разработчиков в месяц, что освобождает команды тратить больше времени на сборку и доставку удивительных вещей.
Использовать npm ci
команда вместо npm install
,
"ci" означает "чистая установка". Он установит зависимости проекта на основе файла package-lock.json вместо зависимостей файла lenient package.json.
Он будет производить идентичные сборки для других ваших товарищей по команде, и это также намного быстрее.
Кажется, эта проблема исправлена в npm v5.4.2
https://github.com/npm/npm/issues/17979
(Прокрутите вниз до последнего комментария в теме)
Обновить
Фактически исправлено в 5.6.0. В 5.4.2 была кросс-платформенная ошибка, которая все еще вызывала проблему.
В будущем вы сможете использовать --from-lock-file
(или аналогичный) флаг для установки только с package-lock.json
без изменения его.
Это будет полезно для CI и т. Д. Сред, где важны воспроизводимые сборки.
См. https://github.com/npm/npm/issues/18286 для отслеживания этой функции.
Возможно, вам стоит использовать что-то вроде этого
npm ci
Вместо того, чтобы использовать npm install
если вы не хотите менять версию своего пакета.
Согласно официальной документации, оба npm install
а также npm ci
установить зависимости, необходимые для проекта.
Главное отличие в том,
npm install
устанавливает пакеты сpackge.json
в качестве справки. Где в случаеnpm ci
, он устанавливает пакеты сpackage-lock.json
в качестве справки, проверяя каждый раз, когда устанавливается точный пакет.
Вы, вероятно, что-то вроде:
"typescript":"~2.1.6"
в вашем package.json
который npm обновляет до последней минорной версии, в вашем случае 2.4.1
Изменить: вопрос от ОП
Но это не объясняет, почему "npm install" изменит файл блокировки. Разве файл блокировки не предназначен для создания воспроизводимой сборки? Если это так, независимо от значения semver, он все равно должен использовать ту же версию 2.1.6.
Ответ:
Это предназначено для блокировки вашего полного дерева зависимостей. Скажем
typescript v2.4.1
требуетwidget ~v1.0.0
, Когда вы npm установить его захватываетwidget v1.0.0
, Позже ваш коллега-разработчик (или сборщик CI) устанавливает npm и получаетtypescript v2.4.1
ноwidget
был обновлен доwidget v1.0.1
, Теперь ваш модуль узла не синхронизирован. Это то, чтоpackage-lock.json
предотвращает.Или в целом:
В качестве примера рассмотрим
пакет А:
{"name": "A", "version": "0.1.0", "dependencies": {"B": "<0.1.0"}}
пакет B:
{"name": "B", "version": "0.0.1", "dependencies": {"C": "<0.1.0"}}
и пакет C:
{"name": "C", "version": "0.0.1"}
Если это единственные версии A, B и C, доступные в реестре, то обычная установка npm A установит:
A@0.1.0 - B@0.0.1 - C@0.0.1
Однако, если B@0.0.2 опубликован, то новая установка npm установит:
A@0.1.0 - B@0.0.2 - C@0.0.1 при условии, что новая версия не изменила зависимости B. Конечно, новая версия B может включать новую версию C и любое количество новых зависимостей. Если такие изменения нежелательны, автор A может указать зависимость от B@0.0.1. Однако, если автор A и автор B не являются одним и тем же лицом, у автора A нет возможности сказать, что он или она не хочет добавлять недавно опубликованные версии C, когда B вообще не изменился.
ОП Вопрос 2: Итак, давайте посмотрим, правильно ли я понимаю. Вы говорите, что файл блокировки определяет версии вторичных зависимостей, но все еще использует нечеткое сопоставление package.json для определения зависимостей верхнего уровня. Это точно?
Ответ: Нет. Package-lock блокирует все дерево пакетов, включая корневые пакеты, описанные в
package.json
, Еслиtypescript
заблокирован в2.4.1
в вашемpackage-lock.json
должно оставаться таким до тех пор, пока оно не будет изменено. И скажем завтраtypescript
версия релизов2.4.2
, Если я проверю вашу ветку и запуститьnpm install
, npm будет уважать файл блокировки и установить2.4.1
,
Еще package-lock.json
:
package-lock.json автоматически генерируется для любых операций, где npm изменяет либо дерево node_modules, либо package.json. Он описывает точное дерево, которое было сгенерировано, так что последующие установки могут генерировать идентичные деревья, независимо от промежуточных обновлений зависимостей.
Этот файл предназначен для фиксации в исходных хранилищах и предназначен для различных целей:
Опишите единственное представление дерева зависимостей, чтобы товарищи по команде, развертывания и непрерывная интеграция гарантированно устанавливали одинаковые зависимости.
Предоставьте пользователям возможность "путешествовать во времени" к предыдущим состояниям node_modules без необходимости фиксации самого каталога.
Для облегчения большей видимости изменений в дереве с помощью читаемых исходных текстов контроля.
И оптимизировать процесс установки, позволяя npm пропускать повторяющиеся разрешения метаданных для ранее установленных пакетов.
РЕДАКТИРОВАТЬ: название "замок" хитрый, его NPM пытается догнать пряжи. Это не заблокированный файл вообще. package.json
фиксированный пользователем файл, который после установки создаст дерево папок node_modules, и это дерево будет записано в package-lock.json
, Итак, вы видите, наоборот - версии зависимостей будут извлечены из package.json
как всегда и package-lock.json
должен быть назван package-tree.json
(надеюсь, это сделало мой ответ более ясным после стольких отрицательных голосов)
Упрощенный ответ: package.json
ваши зависимости как обычно, в то время как package-lock.json
является "точным и, что более важно, воспроизводимым деревом node_modules" (взято из самой документации npm).
Что касается хитрого имени, его NPM пытается догнать пряжу.
Существует открытая проблема для этого на их странице GitHub: https://github.com/npm/npm/issues/18712
Эта проблема наиболее серьезна, когда разработчики используют разные операционные системы.
на этом сайте также есть информация об изменениях блокировки пакетов в последующих npm i
Это похоже на npm6 - я запустил npm i
ничего не меняя, а мой package-lock.json
был изменен (версии под всеми пакетами в requires
изменено).
Кажется, намеревался и ничего не сломать? Больше информации здесь
Npm install обнаруживает любые изменения, внесенные в файл package.json, чтобы соответствующим образом отразить список зависимостей.
Бывший. Если пользователь добавил или удалил новую зависимость, сборка загрузит или удалит зависимости на локальном компьютере. Мы можем сравнить это с репозиторием .m2 в java, где maven постоянно отслеживает файл pom.xml для обновления зависимостей.
package-lock.json - это копия package.json, используемая во время выполнения внутренними процессами, с той лишь разницей, что package-lock.json доступен пользователю только для чтения.