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

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

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

Ответы (12)

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


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


Обновление 1: Поведение, описанное ниже, было исправлено в npm 5.4.2: текущее предполагаемое поведение описано в GitHub issue # 17979.


Исходный ответ: Поведение package-lock.json было изменено в npm 5.1.0, как описано в issue # 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 продолжается обсуждение issue # 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, получат значительный выигрыш.

Npm install обнаруживает любые изменения, внесенные в файл package.json, чтобы соответствующим образом отразить список зависимостей.

Пример. Если пользователь добавил или удалил новую зависимость, сборка загрузит или удалит зависимости на локальном компьютере. Мы можем сравнить это с репозиторием .m2 в java, где maven постоянно отслеживает файл pom.xml для обновления зависимостей.

package-lock.json - это копия package.json, используемая во время выполнения внутренними процессами, с той лишь разницей, что package-lock.json доступен пользователю только для чтения.

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

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

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

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

«ci» означает «непрерывное интегрирование».

Он установит зависимости проекта на основе файла package-lock.json вместо мягких зависимостей файла package.json.

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

Подробнее об этом можно прочитать в этом сообщении блога: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable

РЕДАКТИРОВАТЬ: имя «замок» является хитрым, его NPM пытается догнать Yarn. Это вообще не заблокированный файл.package.json - это фиксированный пользователем файл, который после "установки" сгенерирует дерево папок node_modules, и это дерево будет записано в package-lock.json. Как видите, все наоборот - версии зависимостей будут извлекаться из package.json как всегда, а package-lock.json следует называть package-tree. json

(надеюсь, это прояснило мой ответ после стольких голосов против)


Упрощенный ответ: package.json имеет ваши зависимости как обычно, а package-lock.json - это «точное и, что более важно, воспроизводимое дерево node_modules» (взято из сам документ npm).

Что касается хитрого названия, его NPM пытается догнать Yarn.

У вас наверняка что-то вроде:

"typescript":"~2.1.6"

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

Изменить: вопрос из OP

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

Ответ:

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

Или в более общем смысле:

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

пакет A:

{"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 установит:

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 вообще не изменился.


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

Ответ: Нет. Package-lock блокирует все дерево пакетов, включая корневые пакеты, описанные в package.json. Если машинописный текст заблокирован at 2.4.1 в вашем package-lock.json, он должен оставаться таким, пока не станет измененный. И, допустим, завтра машинописный текст выпускает версию 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

It appears this issue is fixed in npm v5.4.2

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

(Scroll down to the last comment in the thread)

Update

Actually fixed in 5.6.0. There was a cross platform bug in 5.4.2 that was causing the issue to still occur.

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

Update 2

See my answer here: https://stackoverflow.com/a/53680257/1611058

npm ci is the command you should be using when installing existing projects now.

Short Answer:

  • npm install honors package-lock.json only if it satisfies the requirements of package.json.
  • If it doesn't satisfy those requirements, packages are updated & package-lock is overwritten.
  • If you want the install to fail instead of overwriting package-lock when this happens, use npm ci.

Here is a scenario that might explain things (Verified with NPM 6.3.0)

You declare a dependency in package.json like:

"depA": "^1.0.0"

Then you do, npm install which will generate a package-lock.json with:

"depA": "1.0.0"

Few days later, a newer minor version of "depA" is released, say "1.1.0", then the following holds true:

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)

Next, you manually update your package.json to:

"depA": "^1.1.0"

Then rerun:

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 для более быстрых и надежных сборок

На их странице github есть открытая проблема: https://github.com/npm/npm/issues/18712

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

Вероятно, вам стоит использовать что-то вроде этого

npm ci

Вместо использования npm install если вы не хотите менять версию своего пакета.

Согласно официальной документации, как npm install, так и npm ci устанавливают зависимости, необходимые для проекта.

Основное отличие в том, что npm install устанавливает пакеты, используя packge.json в качестве ссылки. Если в случае npm ci, он устанавливает пакеты, принимая package-lock.json в качестве ссылки, проверяя каждый раз, когда устанавливается точный пакет.

2022 WebDevInsider