Для чего нужен package lock json
Зачем в npm 7 оставили поддержку package-lock.json?
Краткий ответ на этот вопрос выглядит так: «Потому что yarn.lock не полностью удовлетворяет нуждам npm. Если полагаться исключительно на него, это ухудшит возможности npm по формированию оптимальных схем установки пакетов и возможности по добавлению в проект нового функционала». Ответ более подробный представлен в данном материале.
Базовая структура файла yarn.lock
Файл yarn.lock представляет собой описание соответствия спецификаторов зависимостей пакетов и метаданных, описывающих разрешение этих зависимостей. Например:
Вопрос тут заключается в следующем: «Если yarn.lock достаточно хорош для менеджера пакетов Yarn — почему npm не может просто использовать этот файл?».
Детерминированные результаты установки зависимостей
Результаты установки пакетов с помощью Yarn гарантированно будут одними и теми же при использовании одного и того же файла yarn.lock и одной и той же версии Yarn. Применение различных версий Yarn может привести к тому, что файлы пакетов на диске будут расположены по-разному.
Рассмотрим следующий граф зависимостей:
Вот пара схем деревьев зависимостей, каждое из которых можно признать корректным.
Вложенные зависимости и дедупликация зависимостей
Более того, существует целый класс ситуаций, предусматривающих работу с вложенными зависимостями и дедупликацию зависимостей, когда файл yarn.lock не способен точно отразить результат разрешения зависимостей, который будет, на практике, использоваться npm. Причём, это справедливо даже для тех случаев, когда npm использует yarn.lock в качестве источника метаданных. В то время как npm использует yarn.lock как надёжный источник информации, npm не рассматривает этот файл в роли авторитетного источника сведений об ограничениях, накладываемых на версии зависимостей.
В некоторых случаях Yarn формирует дерево зависимостей с очень высоким уровнем дублирования пакетов, а нам это ни к чему. В результате оказывается, что точное следование алгоритму Yarn в подобных случаях — это далеко не идеальное решение.
Рассмотрим следующий граф зависимостей:
На основе этих сведений npm формирует следующее дерево зависимостей:
Так как файл yarn.lock фиксирует лишь порядок разрешения зависимостей, а не результирующее дерево пакетов, Yarn сформирует такое дерево зависимостей:
Все три получившихся дерева зависимостей можно признать корректными в том смысле, что каждый пакет получит те версии зависимостей, которые соответствуют заявленным требованиям. Но нам не хотелось бы создавать деревья пакетов, в которых слишком много дубликатов. Подумайте о том, что будет, если x — это большой пакет, у которого есть много собственных зависимостей!
Фиксация результатов реализации намерений пользователя
Если используется этот флаг, то итоговое дерево для вышеприведённого примера будет выглядеть так:
Вот ещё несколько примеров того, как дополнительные настройки npm способны приводить к созданию отличающихся друг от друга деревьев зависимостей:
Фиксация же структуры готового дерева зависимостей позволяет нам давать в распоряжение пользователей подобные возможности и при этом не нарушать процесс построения детерминированных и воспроизводимых деревьев зависимостей.
Производительность и полнота данных
В npm 7 файл package-lock.json содержит всё, что нужно npm для полного построения дерева зависимостей проекта. В npm 6 эти данные хранятся не так удобно, поэтому, когда мы сталкиваемся со старым lock-файлом, нам приходится нагружать систему дополнительной работой, но это делается, для одного проекта, лишь один раз.
В результате, даже если в yarn.lock и были записаны сведения о структуре дерева зависимостей, нам приходится использовать другой файл для хранения дополнительных метаданных.
Будущие возможности
То, о чём мы тут говорили, может серьёзно измениться, если учитывать различные новые подходы к размещению зависимостей на дисках. Это — pnpm, yarn 2/berry и PnP Yarn.
Мы, работая над npm 8, собираемся исследовать подход к формированию деревьев зависимостей, основанный на виртуальной файловой системе. Эта идея смоделирована в Tink, работоспособность концепции подтверждена в 2019 году. Мы, кроме того, обсуждаем идею перехода на что-то вроде структуры, используемой pnpm, хотя это, в некотором смысле, даже более масштабное кардинальное изменение, чем использование виртуальной файловой системы.
Это — не статья, которую можно было бы назвать «О вреде yarn.lock»
Мне хотелось бы особо отметить то, что, судя по тому, что я знаю, Yarn надёжно создаёт корректные деревья зависимостей проектов. И, для определённой версии Yarn (на момент написания материала это относится ко всем свежим версиям Yarn), эти деревья являются, как и при использовании npm, полностью детерминированными.
Файла yarn.lock достаточно для создания детерминированных деревьев зависимостей с использованием одной и той же версии Yarn. Но мы не можем полагаться на механизмы, зависящие от реализации менеджера пакетов, учитывая использование подобных механизмов во многих инструментах. Это ещё более справедливо, если учесть то, что реализация формата файла yarn.lock нигде формально не документирована. (Это — не проблема, уникальная для Yarn, в npm сложилась такая же ситуация. Документирование форматов файлов — это довольно серьёзная работа.)
Лучший способ обеспечения надёжности построения строго детерминированных деревьев зависимостей, это, в долгосрочной перспективе, фиксация результатов разрешения зависимостей. При этом не стоит полагаться на веру в то, что будущие реализации менеджера пакетов будут, при разрешении зависимостей, идти тем же путём, что и предыдущие реализации. Подобный подход ограничивает наши возможности по конструированию оптимизированных деревьев зависимостей.
Отклонения от изначально зафиксированной структуры дерева зависимостей должны быть результатом явно выраженного желания пользователя. Такие отклонения должны сами себя документировать, внося изменения в зафиксированные ранее данные о структуре дерева зависимостей.
Каким менеджером пакетов вы пользуетесь в своих JavaScript-проектах?
Добро пожаловать в ад…зависимостей JavaScript
Начало любого JavaScript проекта сопровождается амбициозным намерением— использовать как можно меньше npm пакетов в процессе разработки. Но сколько бы усилий мы не предпринимали, рано или поздно пакеты начинают накапливаться. Со временем строк в package.json становится всё больше, а благодаря package-lock.json пул реквесты приобретают все более устрашающий вид со всеми своими дополнениями или удалениями в процессе добавления зависимостей.
“И нормально”, — скажет лидер команды разработчиков, а все остальные только кивнут в ответ. А что еще остается делать в такой ситуации? Ведь у нас есть счастливая возможность наблюдать, как оживает и процветает экосистема JavaScript. Нам не нужно каждый раз изобретать колесо и ломать голову над вопросами, которые уже давно решены сообществом открытого ПО.
Хорошая новость: вышла первая версия AppSignal для Node.js. Это приложение предполагает интеграцию с Express и включает интерфейс для автоматических модулей Node.js.
Предположим, вы захотели создать блог и выбрали для этого Gatsby.js. Попробуйте установить и сохранить его в число ваших зависимостей. Поздравляю! Вместе с этим фреймворком вы только что получили 19000 дополнительных зависимостей. Как вам такой подарок? До какой же степени может разрастаться дерево зависимостей JavaScript? Как же мы оказываемся в аду зависимостей? Давайте копнем поглубже и выясним.
Что же такое пакет JavaScript?
npm, менеджер пакетов, входящий в состав Node.js, содержит самый полный реестр пакетов JavaScript в мире! Он больше, чем RubyGems, PyPi и Maven вместе взятые! Данные приведены согласно исследованиям веб-сайта Module Counts, который отслеживает количество пакетов самых популярных реестров.
Что такое package.json?
Согласно определению package.json:
Пока звучит немного хаотично. Представьте себе бесконечную череду пакетов, зависящих друг от друга. Вот почему при установке одного пакета Gatsby вы получили 19 тысяч дополнительных зависимостей.
Типы зависимостей в package.json
Чтобы прояснить вопрос накопления зависимостей с течением времени, рассмотрим разные типы зависимостей проекта. В пакете package.json встречаются несколько из них:
Назначение package-lock.json
Всем известен тот самый файл, который получает много дополнений и удалений в пул реквестах, и это принимается как должное. package-lock.json автоматически создается каждый раз при изменении файла package.json или директории node_modules. Он сохраняет в неизменном виде дерево зависимостей, созданное при установке, чтобы все последующие зависимости могли создавать идентичное дерево. Это решает проблему, при которой у меня одна зависимость, а у вас другая.
package-lock.json является длинным списком зависимостей в проекте. Он указывает их версию, положение модуля (URI), хэш, отображающий взаимодействие модулей и необходимых для них пакетов. Продолжив чтение списка, вы найдете каждую запись для каждого пакета, необходимого для React и т.д. Вот тут-то и находится настоящий ад зависимостей. Он определяет все, что нужно проекту.
Разбираемся с зависимостями Gatsby.js
Итак, как же нам выйти из ситуации, в которой при установке одной зависимости мы получили в нагрузку 19 000? Ответ — зависимости зависимостей. Вот что происходит при установке Gatsby.js:
В package.json можно увидеть только одну зависимость. Но присмотревшись к package-lock.json, нельзя не заметить новорожденного монстра, раскинувшего свои 14 тысяч строк. Более детальную информацию можно получить в package.json, расположенном в GitHub репозитории Gatbsy.js. По подсчетам npm число прямых зависимостей составляет 136. А теперь представьте, что каждая из этих зависимостей имеет еще одну зависимость, и в итоге вы получаете 272 зависимости. И это я еще преуменьшил! В действительности у каждой зависимости может быть больше одной зависимости, так что их список продолжит пополняться.
200 мегабайт, как я уже говорил, совсем неплохой результат. Бывали случаи, когда размер директории мог легко перевалить за 700 мегабайт. Если вам интересно, какие модули занимают большую часть памяти, можете выполнить следующую команду:
Ага, rxjs, ну и хитрая же ты штучка. Есть одна простая команда, которая поможет вам с размером node_modules и уменьшением дублирования зависимостей — npm dedup :
Визуализация зависимостей
Если вам интересно, как выглядят зависимости вашего проекта, можете воспользоваться парочкой инструментов. В моем арсенале есть несколько таких, которые показывают зависимости совсем иначе.
npm.anvaka.com
На изображении можно увидеть взаимодействие пакетов друг с другом, и в целом оно напоминает гигантскую паутину. Такое большое количество зависимостей Gatsby.js почти обрушило мой браузер. Здесь вы увидите, как взаимодействуют зависимости Gatsby.js. Там же можно увидеть их в 3D режиме.
npm.broofa.com
Данный способ изображения зависимостей напоминает блок-схему. В случае с Gatsby.js он быстро оказался довольно замысловатым, но если любопытно, то смотрите здесь. На npms.io можно поставить оценку каждой зависимости по нескольким критериям, и, согласно полученным результатам, они будут выделены разными цветами. Вы можете также загрузить туда свой package.json и получить его визуальное отображение.
Package Phobia
Чем больше сила, тем больше ответственность
Подводя итоги, без преувеличения скажу, что JavaScript и npm просто супер, а возможность гибкого подхода при выборе из океана зависимостей — еще лучше. Сущий пустяк — выполнить npm install для сохранения пары строк кода, но иногда мы почему-то забываем, что скрывается за этим действием.
Теперь, прочитав всю статью, вы сможете лучше разбираться в дереве зависимостей JavaScript. Устанавливаете ли вы слишком большую библиотеку или просто выясняете насколько сложные зависимости у проекта, моя статья станет вашим руководством по анализу зависимостей разной степени сложности.
Node.js-проекты, в которых лучше не использовать lock-файлы
Автор материала, перевод которого мы сегодня публикуем, говорит, что одна из проблем, с которыми приходится сталкиваться программистам, заключается в том, что у них их код работает, а у кого-то другого выдаёт ошибки. Эта проблема, возможно, одна из самых распространённых, возникает из-за того, что в системах создателя и пользователя программы установлены разные зависимости, которые использует программа. Для борьбы с этим явлением в менеджерах пакетов yarn и npm существуют так называемые lock-файлы. Они содержат сведения о точных версиях зависимостей. Механизм это полезный, но если некто занимается разработкой пакета, который планируется опубликовать в npm, lock-файлы ему лучше не использовать. Этот материал посвящён рассказу о том, почему это так.
Самое главное в двух словах
Lock-файлы крайне полезны при разработке Node.js-приложений вроде веб-серверов. Однако если речь идёт о создании библиотеки или инструмента командной строки с прицелом на публикацию в npm, то нужно знать о том, что lock-файлы в npm не публикуются. Это означает, что если при разработке применяются эти файлы, то у создателя npm-пакета, и у тех, кто этот пакет использует, будут задействованы разные версии зависимостей.
Что такое lock-файл?
Оба эти файла содержат некоторые крайне важные сведения о зависимостях:
Сравнение package.json и lock-файлов
Цель поля dependencies файла package.json заключается в том, чтобы показать зависимости проекта, которые должны быть установлены для его правильной работы. Но сюда не входят сведения о зависимостях этих зависимостей. В сведения о зависимостях могут входить точные версии пакетов или некий диапазон версий, указанный в соответствии с правилами семантического версионирования. При использовании диапазона npm или yarn выбирают наиболее подходящую версию пакета.
Если посмотреть документацию npm по семантическому версионированию, то можно узнать, что значок ^ указывает на то, что подходящей является любая версия пакета, номер которой больше или равен 3.30.3 и меньше 4.0.0. В результате, если в проекте нет lock-файла и выйдет новая версия пакета, то команда npm install или yarn install автоматически установит эту новую версию пакета. Сведения в package.json при этом обновляться не будут. При использовании lock-файлов всё выглядит иначе.
Это крайне полезно в том случае, если вы занимаетесь разработкой проекта наподобие веб-приложения или сервера, так как в CI-окружении нужно сымитировать поведение пользователя. В результате, если мы будем включать lock-файл в репозиторий проекта (например, созданный средствами git), мы можем быть уверенными в том, что каждый разработчик, каждый сервер, каждая система сборки кода и каждое CI-окружение используют одни и те же версии зависимостей.
Почему бы не сделать то же самое при публикации библиотек или других программных инструментов в реестре npm? Нам, прежде чем ответить на этот вопрос, нужно поговорить о том, как устроен процесс публикации пакетов.
Процесс публикации пакетов
В результате получается, что если кто-нибудь устанавливает чей-нибудь пакет, файл package-lock.json в этом участвовать не будет. То, что имеется в этом файле, который есть у разработчика пакета, не будет учитываться при установке пакета кем-то другим.
Это может, по несчастливой случайности, привести к проблеме, о которой мы говорили в самом начале. В системе разработчика код работает нормально, а в других системах выдаёт ошибки. А дело тут в том, что разработчик проекта и те, кто проектом пользуются, применяют разные версии пакетов. Как это исправить?
Отказ от lock-файлов и использование технологии shrinkwrap
Для того чтобы автоматизировать эту операцию, команду npm shrinkwrap можно добавить в раздел описания скриптов файла package.json в виде prepack-скрипта. Того же эффекта можно добиться, используя хук git commit. В результате вы сможете быть уверены в том, что в вашем окружении разработки, в вашей CI-системе, и у пользователей вашего проекта используются одни и те же зависимости.
Стоит отметить, что этой методикой рекомендуется пользоваться ответственно. Создавая shrinkwrap-файлы, вы фиксируете конкретные версии зависимостей. С одной стороны это полезно для обеспечения стабильной работы проекта, с другой — это может помешать пользователям в установке критически важных патчей, что, в противном случае, делалось бы автоматически. На самом деле, npm настоятельно рекомендует не использовать shrinkwrap-файлы при разработке библиотек, ограничив их применение чем-то вроде CI-систем.
Выяснение сведений о пакетах и зависимостях
Вот несколько подобных команд:
Итоги
Многое из того, о чём мы тут говорили, полагается на особенности выполнения различных операций средствами npm. Речь идёт об упаковке, публикации, установке пакетов, о работе с зависимостями. А если учесть то, что npm постоянно развивается, можно сказать, что всё это в будущем может измениться. Кроме того, возможность практического применения приведённых здесь рекомендаций зависит от того, как разработчик пакета воспринимает проблему использования различных версий зависимостей в разных средах.
Зачем нужен package lock json и package json
В данной статье мы хотим познакомить вас с package lock и package json файлами. Разберемся, для чего необходимы lock файлы, при работе с npm.
Что такое пакет в JavaScript?
Пакетом называется один или несколько файлов в JS, в виде инструмента или библиотеки. Npm хранит в себе самый большой набор пакетов. Npm необходим для скачивания пакетов и загрузки их, благодаря этому можно хорошо ускорить своё написание кода.
Что такое package.json?
Типы зависимостей в package.json
Давайте разберем несколько основных зависимостей проекта, чтобы лучше понимать что в него входит и что можно редактировать.
• dependencies — главные зависимости которые находятся в вашем проекте. Их можно применять и запускать в коде.
• devDependencies — взаимосвязи разработки.
• peerDependencies — равные взаимосвязи, при добавлении которых, мы даем понять какую версию для взаимосвязи следует установить
• optionalDependencies — второстепенные зависимости. Если при установке произойдет сбой, на основную сборку это не повлияет.
• bundledDependencies — в нём содержится массив пакетов. Данный массив нужен, если вам требуется добавить новую зависимость, которой нет в npm.
Назначение package-lock.json
package-lock.json если коротко, то предназначен для блокировки зависимостей от определенного номера версии. В package-lock.json файле перечислены зависимости вашего приложения и зависимости всех его зависимостей. Другими словами, он описывает, какую версию каждого отдельного пакета вы установили. Вот почему это намного дольше, чем package.json. Когда вы используете package-lock.json для установки зависимостей, вы получаете точно такие же пакеты, неважно, устанавливаете ли вы их сейчас или через несколько лет, когда мы, надеюсь, больше не будем использовать клавиатуры.
Чтобы установить зависимости на основе текущего package-lock.json файла, вы должны использовать npm ci вместо npm install.
Используя, npm ci вы сможете избежать проблем, которые возникают, когда приложение работает на вашем компьютере, но не работает на чужом, потому что они в конечном итоге загрузили различные зависимости из-за использования npm install.
Вот почему при запуске ваших сборок на сервере непрерывной интеграции вам следует устанавливать зависимости, используя npm ci вместо npm install. Это приведет к тому, что сборка CI-сервера будет работать так же, как на вашем компьютере.
Назначение package.json
Package специализирован не только лишь на взаимосвязях, но и для определения свойств проекта:
Чтоб отключить автоматическое создания файла следует написать в npmrc package-lock=false. Наличие package-lock.json в проекте необязательно.
Разбивка параметров
Менеджеры версий
Что из себя представляет расширение JSON
Как создать package.json?
Из-за того, что package.json довольно глобальный и состоит из множества свойств, то в ручную его писать трудно и очень долго. Для быстроты решения задачи, npm сделали команду init. Откройте консоль в области текущей папки и напишите команду: npm init. Данная команда позволяет создать файл package.json. После этого вы получаете вот такой ответ:
Наш package.json создан!
Установка модулей
Для начала в своём проекте в консоли напишите команду
npm install
Если вам нужны еще библиотеки просто перечисляете их, отделяя отступом. Но не забывайте добавлять аргумент —save, для сохранения библиотеки как зависимость самого проекта.
По итогу у нас получились созданные файлы: package.json, package-lock.json, node_modules.
Сгенерированная папка node_modules хранит в себе все модули вашего проекта. Данную папку в Git репозиторий мы не добавляем! Так как в ней хранится множество зависимостей и они будут только добавляться, вы будете очень долго ждать загрузки. Загружать нужно только 2 файла package.json, package-lock.json, даже после того, как другой разработчик сделает копию вашего проекта, он сможет установить нужные зависимости сохраненные в package.json.
Не забудьте добавить файл node_modules в gitignore.
Заключение
По итогу, в данной статье мы разобрали базу package и package lock, рассказали о самых распространенных и часто встречающихся ошибках, которые следует избегать.
Углубились в структуру файлов. Показали как установить node_modules, а также научились устанавливать дополнительные библиотеки.
В конечном итоге помните, что на git node_modules лучше не добавлять. И теперь любой скопированный проект вы сможете настроить сами, так, чтобы он работал.
Lock-файлы npm
Всем привет! В прошлом посте мы рассмотрели экосистему npm в качестве источника хаоса в нашем проекте, и научились с умом подходить к выбору зависимостей, чтобы минимизировать наши риски. Сегодня мы пойдем дальше и рассмотрим lock-файлы npm, которые помогают повысить стабильность проекта в процессе работы над ним.
Когда манифеста мало
Также разные версии npm могут иметь различные алгоритмы установки зависимостей, и структура файлов будет отличаться.
Вы помните, что список зависимостей в манифесте проекта содержит диапазон версий semver, что позволяет обновлять зависимости? Получается, что установка зависимостей в разное время будет приводить к разным результатам, потому что содержимое npm registry постоянно меняется, регулярно выходят новые пакеты. Кроме того, поскольку мы имеем дело с деревом зависимостей, то транзитивные зависимости (зависимости ваших зависимостей) тоже будут меняться во времени.
А еще может возникнуть ситуация, когда содержимое пакета, лежащего в npm registry, было заменено без обновления версии. Это называется мутацией пакетов и запрещено в официальном npm registry, однако в частных реестрах вполне возможно. А что, если содержимое пакета было заменено злоумышленником, чтобы внести в код какие-то закладки?
Учитывая все эти факторы, становится очевидно, что структура данных в директории node_modules очень нестабильна и может меняться во времени, даже если ваш манифест при этом остается нетронутым.
Наивно было бы попытаться зафиксировать зависимости, прописывая строгие версии в манифесте проекта (вместо диапазонов semver): как мы рассмотрели выше, это не даст существенных результатов, потому что транзитивные зависимости всё равно будут обновляться. Да и другие факторы не перестанут влиять на установку зависимостей. Кроме того, если вы заморозите ваши прямые зависимости, то получится ситуация, когда более старые версии будут работать с более свежими версиями транзитивных зависимостей, и потенциально это повышает вероятность проблем с интеграцией.
А теперь представьте, что у нас в проекте есть конвейер CI/CD и специальный сервер, который собирает, тестирует и выкатывает приложения в разные среды выполнения. Как правило, такие решения привязываются к ID коммита в Git (или к Git-тегам), и на каждый коммит система генерирует готовый к выкатке артефакт (архив с готовыми для выполнения файлами). Таким образом, на вход конвейера поступает код из Git-репозитория, версионированный через ID коммита, а на выходе вы получаете протестированный и готовый к выкатке артефакт. В идеале, это должно работать как чистая функция (pure function): если вы пересоберёте коммит, созданный несколько месяцев назад, то должны получить на выходе тот же самый артефакт. Однако мы не можем хранить содержимое node_modules в Git, и получается, что после клонирования репозитория нам необходимо вызывать установку зависимостей из реестра npm. А, как мы уже выяснили, этот процесс довольно нестабилен и привязан к глобальному состоянию экосистемы (содержимому npm registry, версиям npm и т. д.). Получается, что npm вносит хаос в наш конвейер CI/CD и мы уже не можем получить одинаковую сборку по ID коммита.
Lock-файлы приходят на помощь
Чтобы использовать преимущества lock-файла, его необходимо добавить в систему контроля версий. Таким образом, вы строго привяжете полное дерево зависимостей к коммитам в Git. Это будет гарантировать стабильное воспроизводство сборок в вашей системе CI/CD и позволит надежно «путешествовать во времени».
Кроме того, каждый разработчик, который склонирует Git-репозиторий к себе на машину, получит точно такое же дерево зависимостей, как и у вас. Это устранит известную проблему из разряда «странно, а у меня всё работает» (“it works on my machine”).
Структура package-lock.json
Npm генерирует lock-файл полностью автоматически на основе данных из манифеста проекта, глобального состояния npm registry и алгоритма установки зависимостей npm. Однако содержимое файла вполне читаемо человеком и может быть использовано даже на этапе code review. Diff lock-файла покажет, какие зависимости в дереве были обновлены, какие были удалены, а какие добавлены. Наверное, нет смысла изучать изменения этого файла при каждом обновлении, но при обнаружении каких-то деградаций это может сильно помочь в поиске виновного пакета и сэкономить вам кучу времени. Но чтобы это работал эффективнее и размер изменений был минимальным, я рекомендую обновлять зависимости как можно чаще (гораздо проще выявить проблему, если у вас обновилось три пакета в дереве зависимостей, а не сотня).
Оригинальный файл содержит почти 400 строк, но чтобы пример получился достаточно читабельным и наглядным, я показал только часть дерева зависимостей.
package-lock.json
Итак, давайте разбираться. Начнем с основных корневых свойств:
Дескриптор каждой отдельно взятой зависимости выглядит следующим образом:
Дублирующиеся зависимости
Подробнее про дублирование зависимостей мы поговорим в будущих статьях.
Ручные правки
Хотя структура lock-файла хорошо читается и довольно понятна, нельзя забывать, что этот файл генерируется автоматически. Не пытайтесь вносить в него правки, их будет невозможно сохранить. После очередного обновления lock-файла они будут потеряны.
Конфликт в lock-файлах npm
Если несколько разработчиков трудятся в одной ветке и используют lock-файлы, то в какой-то момент может возникнуть merge-конфликт в Git. В этом случае достаточно просто устранить конфликты в файле манифеста (если они есть), а потом выполнить npm install : менеджер пакетов автоматически исправит конфликты в lock-файле.
Установить merge-драйвер для npm можно следующим образом:
При возникновении конфликта при вызове команд Git в консоли будет выведено:
Обновление lock-файла
Установка зависимостей в CI/CD
Как я сказал выше, если npm обнаружит отставание lock-файла от манифеста, то это приведет к обновлению lock-файла и установке зависимостей из манифеста. Такое поведение очень удобно при разработке, но совершенно непригодно, и даже опасно в контексте конвейера CI/CD, потому что может привести к неожиданным результатам из-за слетевшей блокировки зависимостей.
По этой причине никогда не следует использовать команду npm install в рамках конвейера CI/CD, обязательно используйте npm ci вместо нее. Идите и проверьте это прямо сейчас! (я подожду).
Разные типы проектов
Давайте теперь поговорим про особенности использования lock-файлов в проектах разных типов. Первое, о чём стоит сказать: файл package-lock.json не публикуется в npm registry. Это означает, что если вы публикуете свой пакет в реестр npm (библиотека), то содержимое вашего lock-файла не будет оказывать влияния на дерево зависимостей при установке вашего пакета в чей-то проект. В этом случае играет роль только содержимое вашего манифеста. Это и хорошо: если бы каждая библиотека замораживала свои зависимости, то дерево зависимостей в конечном проекте было бы ещё больше (куда уж больше?) и содержало огромное количество дублей. Адекватно управлять зависимостями стало бы невозможно.
Shrinkwrap
Тестирование пакета-библиотеки
По этой причине вы не можете гарантировать среду, однако можете протестировать работу библиотеки со свежими версиями всех зависимостей, чтобы убедиться, что в новых и свежих проектах ничего не сломается. Однако, если вы будете использовать lock-файл в вашем проекте, то он будет постоянно оттягивать версии ваших зависимостей назад, не давая вам полноценно тестировать совместимость с самыми свежими версиями всех зависимостей (которые наверняка будут у ваших пользователей). Либо вам придется постоянно вызывать глубокий npm update перед каждым тестом.
Руководствуясь этим, некоторые разработчики советует вообще не использовать lock-файлы для проектов библиотек. Однако, я считаю это слишком радикальным советом. Дело в том, что помимо продуктовых runtime-зависимостей вашего пакета существуют еще и dev-зависимости. Если вы откажетесь от lock-файла, то ваши dev-зависимости выйдут из-под контроля, то есть вы потеряете некий островок стабильности.
Более подходящим решением, на мой взгляд, была бы реорганизация конвейера CI/CD таким образом, чтобы код библиотеки тестировался в проекте без использования lock-файла, путем установки самых свежих доступных зависимостей. Собирать же пакет (если требуется) можно и с участием lock-файла (для этого можно использовать два разных этапа в вашем CI/CD конвейере).
С глаз долой…
Надеюсь, теперь, лучше понимая, как работают эти механизмы, вы сможете эффективнее наладить управление зависимостями в вашем проекте и повысить его надежность и безопасность.
Обновляйтесь чаще!
Помните, задача lock-файлов заключается не в том, чтобы навсегда заблокировать все зависимости и больше никогда их не обновлять, а в том, чтобы обеспечить повторяемость их установки и прозрачность их обновления.
Залог высокого качества, поддерживаемости и удобства разработки вашего проекта заключается в частом обновлении зависимостей. Согласитесь, гораздо проще обновлять зависимости маленькими порциями по мере их выхода. Diff lock-файла всегда покажет, что именно обновилось. Если он будет небольшим, то вы легко сможете его прочитать. Если же после обновления возникнет проблема, то, скорее всего, она будет одна, и её будет несложно обнаружить и изолировать.
С другой стороны, если вы не будете полгода обновлять зависимости, то потом сделать это будет очень сложно, потому что крупное обновление очень сложно разделить на маленькие части. Вы получите огромный ворох изменений разной степени тяжести, а в случае возникновения проблемы (а она, скорее всего, придет не одна) выявить точное место будет гораздо сложнее (diff здесь уже будет бесполезен в силу его гигантского размера).
Поэтому не запускайте ваши зависимости, обновляйтесь регулярно, возьмите это в привычку, тогда издержки на поддержку кодовой базы будут минимальны. Переход же на новые мажорные версии библиотек будет более планомерным: гораздо проще обновиться на одну мажорную версию библиотеки, чем на несколько сразу.
Продолжение следует
Мы рассмотрели столь важный инструмент повышения надежности и безопасности управления зависимостями, как lock-файлы npm. Использование этого механизма позволит вам существенно повысить стабильность работы вашего проекта и улучшить качество и удобство разработки.
В следующем посте я еще дальше углублюсь в вопросы безопасности npm.
Если вам понравился материал, то, пожалуйста, ставьте лайки, подписывайтесь на наш блог и делитесь ссылками с коллегами. Так мы будем понимать, что наша работа востребована, и будем продолжать радовать вас новыми полезными материалами.
Если у вас есть вопросы или желание что-то добавить по теме, то не бойтесь оставлять комментарии, я с радостью приму участие в обсуждении и учту ваши пожелания в следующих постах.