it-roy-ru.com

Почему "npm install" переписывает package-lock.json?

Я только недавно обновился до npm @ 5. Теперь у меня есть файл package-lock.json со всем из package.json. Я ожидаю, что при запуске npm install версии зависимостей будут извлечены из файла блокировки, чтобы определить, что должно быть установлено в моем каталоге node_modules. Что странно, так это то, что он на самом деле модифицирует и переписывает мой файл package-lock.json.

Например, для файла блокировки был указан TypeScript версии 2.1.6. Затем, после команды npm install, версия была изменена на 2.4.1. Это, кажется, побеждает всю цель файла блокировки.

Что мне не хватает? Как мне заставить npm действительно уважать мой файл блокировки?

385
Viper Bailey

Update 3: Как отмечают и другие ответы, команда npm ci появилась в npm 5.7.0 как дополнительный способ достижения быстрых и воспроизводимых сборок в контексте CI. См. документацию и блог npm для получения дополнительной информации.


Обновление 2: Проблема с обновлением и уточнением документации: проблема GitHub # 18103 .


Update 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. Смотрите эту документацию о блокировках пакетов для дальнейшего объяснения.

280
jotaen

Я обнаружил, что будет новая версия npm 5.7.1 с новой командой npm ci, которая будет устанавливаться только из package-lock.json

Новая команда npm ci устанавливается ТОЛЬКО из вашего файла блокировки. Если ваш package.json и файл блокировки не синхронизированы, он сообщит об ошибке.

Это работает, выбрасывая ваши node_modules и воссоздавая его с нуля.

Помимо гарантии того, что вы получите только то, что находится в вашем файле блокировки, это также намного быстрее (2x-10x!), Чем установка npm, если вы не запускаете с node_modules.

Как вы можете догадаться из названия, мы ожидаем, что оно станет большим благом для сред непрерывной интеграции. Мы также ожидаем, что люди, которые производят развертывание с использованием git-тегов, получат значительную выгоду.

102
Ivan Shcherbakov

Используйте недавно представленный

npm ci

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

Представляем npm ci для более быстрой и надежной сборки

59
Gal Margalit

Короткий ответ:

  • Когда существует package-lock.json, он отменяет package.json
  • Когда package.json изменен, он отменяет package-lock.json

Вот сценарий, который может объяснить вещи (проверено с помощью NPM 6.3.0)

Вы объявляете зависимость в package.json как:

"depA": "^1.0.0"

Затем вы делаете npm install, который сгенерирует package-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)
9
Ahmad Abdelghany

Вы, вероятно, что-то вроде:

"TypeScript":"~2.1.6"

в вашем package.json, который npm обновляет до последней минорной версии, в вашем случае 2.4.1

Правка: вопрос от ОП

Но это не объясняет, почему «установка npm» изменит файл блокировки. Разве файл блокировки не предназначен для создания воспроизводимой сборки? Если так, независимо от значения semver он должен использовать тот же 2.1.6 версия.

Ответ:

Это предназначено для блокировки вашего полного дерева зависимостей. Допустим, TypeScript v2.4.1 требует widget ~v1.0.0. Когда вы npm установите его захватывает widget v1.0.0. Позже ваш коллега-разработчик (или CI build) устанавливает npm и получает TypeScript v2.4.1, но widget был обновлен до widget v1.0.1. Теперь ваш модуль узла не синхронизирован. Это это то, что package-lock.json мешает.

Или в целом:

В качестве примера рассмотрим 

пакет А:

{"имя": "А", "версия": "0.1.0", "зависимости": { "B": "<0.1.0"}} 

пакет B:

{"имя": "B", "версия": "0.0.1", "зависимости": { "C": "<0.1.0"}}

и пакет C:

{"name": "C", "version": "0.0.1"}

Если это единственные версии A, B и C доступны в реестре, затем обычная установка npm A установлю:

[email protected] - [email protected] - [email protected] 

Однако, если [email protected] опубликован, тогда новая установка npm установит:

[email protected] - [email protected] - [email protected] при условии, что новая версия не изменила зависимости B. Конечно, новая версия B может включать новую версия C и любое количество новых зависимостей. Если такие изменения нежелательно, чтобы автор A мог указать зависимость от [email protected] . Однако, если автор A и B не являются одним и тем же лицом, существует автор А не может сказать, что он или она не хочет вмешиваться недавно опубликованные версии C, когда B вообще не изменился.


ОП Вопрос 2: Итак, давайте посмотрим, правильно ли я понимаю. Что ты есть Говорят, что файл блокировки указывает версии вторичного зависимости, но все еще опирается на нечеткое соответствие package.json определить зависимости верхнего уровня. Это точно?

Ответ: Нет. Package-lock блокирует все дерево пакетов, включая корневые пакеты описаны в package.json. Если TypeScript заблокирован в 2.4.1 в вашем package-lock.json, он должен оставаться таким до тех пор, пока не станет изменилось. И скажем, завтра TypeScript выпускает версию 2.4.2. Если я проверю вашу ветку и запусту npm install, npm будет уважать lockfile и установите 2.4.1.

Подробнее о package-lock.json:

package-lock.json автоматически генерируется для любых операций, где npm изменяет либо дерево node_modules, либо package.json. Он описывает точное дерево, которое было сгенерировано, так что последующие установки могут генерировать идентичные деревья, независимо от промежуточных обновлений зависимостей.

Этот файл предназначен для фиксации в исходных хранилищах и предназначен для различных целей:

Опишите единственное представление дерева зависимостей, чтобы товарищи по команде, развертывания и непрерывная интеграция гарантированно устанавливали одинаковые зависимости.

Предоставьте пользователям возможность «путешествовать во времени» к предыдущим состояниям node_modules без необходимости фиксации самого каталога.

Для облегчения видимости изменений в дереве с помощью читаемых исходных кодов различий.

И оптимизировать процесс установки, позволяя npm пропускать повторные разрешения метаданных для ранее установленных пакетов.

https://docs.npmjs.com/files/package-lock.json

6
Matt

Используйте команду npm ci вместо npm install.

«ci» означает «чистая установка». Он установит зависимости проекта на основе файла package-lock.json вместо зависимостей файла lenient package.json.

Он будет производить идентичные сборки для других ваших товарищей по команде, и это также намного быстрее.

5
Daniel Tonon

В будущем вы сможете использовать флаг --from-lock-file (или аналогичный) для установки only из package-lock.json без его изменения. 

Это будет полезно для CI и т.д. Сред, где важны воспроизводимые сборки.

Смотрите https://github.com/npm/npm/issues/18286 для отслеживания этой функции.

5
Timothy Higinbottom

Кажется, эта проблема исправлена ​​в npm v5.4.2

https://github.com/npm/npm/issues/17979

(Прокрутите вниз до последнего комментария в теме)

Обновление

Фактически исправлено в 5.6.0. В 5.4.2 была кросс-платформенная ошибка, которая все еще вызывала проблему.

https://github.com/npm/npm/issues/18712

Обновление 2

Смотрите мой ответ здесь: https://stackoverflow.com/a/53680257/1611058

npm ci - это команда, которую вы должны использовать при установке существующих проектов.

3
Daniel Tonon

Для этого существует открытая проблема на их странице github: https://github.com/npm/npm/issues/18712

Эта проблема наиболее серьезна, когда разработчики используют разные операционные системы.

1
hrdwdmrbl

Правка: название «замок» хитрый, его 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 пытается догнать пряжу.

0
Z. Khullah