Очень хочется пошутить про пакет с пакетами. Но нет. Статья про другое. Для начала давайте разберемся, почему я ее написал, и кому она может быть полезна:
Таким как мне, фронтендам, которые всегда использовали стандартный менеджер и не интересовались другими. А потом внезапно захотелось чего-то новенького, и пришлось прочитать не одну статью, чтобы собрать воедино информацию и выбрать подходящий вариант.
Бэкендам, которые переходят на Node.js.
Джунам, которые про пакеты только в шутках и слышали.
А зачем я вообще полез в пакеты?
Я верю, что если разработчик совсем далек от бизнесовых задач, толку от него будет немного. Он должен понимать, как выбирать технологии, строить архитектуру, чтобы продукт в конечном итоге работал наилучшим образом. Например, если вместо реактивного фреймворка вы используете нативный JS, логично предположить, что скорость разработки будет ниже, а значит, конечный продукт — сильно дороже.
Как еще можно принести пользу бизнесу таким небольшим изменением? Допустим, вы из крупной аутсорс компании, назовем ее «Малабар». В «Малабаре» все замечательно: много клиентов, много разработчиков, большой стэк. Но все сотрудники привыкли юзать разные технологии. Кому-то нравится синтаксис npm, кому-то по душе yarn, а третий вообще на pnpm молится.
И вот этого третьего из «Малабара» отправляют в отпуск. Он летит поглядеть на Дубай. Но проект-то не может его ждать, кому-то придется заменить счастливчика. На проект переводят другого разработчика, который всегда использовал NPM. Он натыкается на новую для себя технологию, с которой раньше не работал. И начинается самое интересное.
Проблемы могут всплыть еще на моменте установки зависимостей:
Что делать? Заменить существующую технологию на другую? Ну такой себе выход – проект то чужой. Что в итоге? Разработчику приходится тратить дополнительное время на изучение новой технологии, чтобы приступить к задачам.
И речь ведь не только о менеджерах пакетов, речь в целом про унификацию различных технологий в рамках компании. Если на всех проектах используются идентичные основные технологии, процесс онбординга будет сокращен до минимума. А это, кстати, тоже плюсик для бизнеса.
О каких пакетах я столько говорю?
В Node.js экосистеме есть множество инструментов для управления зависимостями, такие как PAK, YUM, RPM и другие. Наиболее популярные – NPM, YARN и PNPM. Но сначала пройдемся по базовым вещам: что вообще такое пакет, менеджер пакетов и так далее. Те, кто все знают, могут скипать и переходить к сравнению.
В проектах разработчики не всегда используют собственный код. На самом деле они вообще редко используют собственный код, особенно при написании сложной логики. Существует множество замечательных готовых решений, над которыми трудились другие разработчики и всемирно-известные организации. И эти решения доступны всем.
Пакет (зависимость) — это один или несколько файлов, аккуратно объединенных вместе, которые можно загрузить из реестра пакетов. И таких пакетов в одном проекте может быть использовано очень много. Грубо говоря, пакет – это кусок кода, загруженный в интернет другими разработчиками.
И каждый пакет может включать в себя еще пакеты – транзитивные. Это пакеты, от которых зависят другие пакеты. На изображении они находятся снизу, от основного пакета.
Зачем пакетам менеджеры и в чем между ними разница?
Первым менеджером стал NPM. Он появился в январе 2010 года и был доступен всем разработчикам.
До выпуска NPM, установка зависимостей была не автоматизирована. Приходилось загружать библиотеки из репозиториев и копировать файлы в проект вручную. Тем, кто не пробовал, скажу – это достаточно трудоемкий процесс, который занимает много времени. Особенно, если работаешь на проекте со множеством зависимостей. NPM значительно упростил жизнь разработчиков.
Соответственно, менеджер пакетов – это инструмент, который помогает нам устанавливать зависимости в проект и автоматизирует этот процесс.
NPM менеджер
NPM – это официальный менеджер пакетов Node.js, который поставляется вместе с нодой и устанавливается по умолчанию. Он использует централизованный реестр для хранения и управления зависимостями.
Он также поддерживает локальную и глобальную установку пакетов. Однако, если в проекте есть большое количество зависимостей, NPM будет занимать очень много места на диске и медленно устанавливать пакеты. NPM создает папку node_modules для каждого вашего проекта. В них он загружает из интернета и сохраняет на диске каждый пакет из всей иерархии зависимостей.
Если у вас 50 проектов с одними и теми же зависимостями, то NPM 50 раз загрузит из реестра необходимые зависимости и сохранит на диске 50 отдельных копий одних и тех же пакетов. Более того, раньше этот процесс не был вообще оптимизирован. Если наши пакеты имели одинаковые транзитивные зависимости, они скачивались для каждого своего пакета и хранились в его папке. В таких случаях node_modules мог достигать невероятно огромных размеров.
Хотя эта папка и сейчас является очень тяжелой при использовании NPM или YARN. Видели же такой мем?
Получается, что мы впустую тратим место на жестком диске. И это не есть круто, особенно, когда вы задействованы в разных проектах, но при этом жесткий диск у вас – 256 Гб. Если говорить про старые версии NPM, стоит упомянуть, что он устанавливал пакеты последовательно. Он ждал полной установки пакета, прежде чем переходил к следующему. Изначально у NPM даже не было возможности кэширования пакетов.
Конечно, по началу эти функции вряд ли входили в перечень необходимых. Уже просто сам факт появления NPM был ярким событием, потому что закончилась эпоха ручной установки. Однако появление YARN в 2016 году, который был во всем лучше и из коробки имел локальное кэширование пакетов, дало разработчикам NPM мотивацию к развитию.
Функция кэширования пакетов была добавлена в NPM в пятой версии, выпущенной в мае 2017 года. Это было крупное обновление, в котором улучшили механизм обработки зависимостей, сделали более надежную установку пакетов и стали выводить подробную информацию о процессе. А скорость установки пакетов увеличилась, по информации некоторых источников, примерно в 5 раз. Кэширование позволяет NPM хранить загруженные пакеты локально, чтобы повторно использовать при последующих установках, а не загружать их каждый раз из Интернета. Это позволило значительно ускорить процесс установки и сократить количество трафика, необходимого для загрузки пакетов.
YARN менеджер
Как я уже упомянул, в 2016 году вышел YARN. Это менеджер пакетов, разработанный Facebook. В отличие от NPM его нужно устанавливать вручную.
Какие есть фишки у YARN?
Workspaces: установка и объединение зависимостей для нескольких проектов
Сейчас достаточно популярны монорепозитории. Они приглянулись Google, Facebook, Twitter. Но иногда монорепозиторий – это не дань моде, а необходимость. Что это такое? Представьте, приложение состоит из нескольких подпроектов. Они с большего используют одинаковые зависимости. Поэтому, чтобы не устанавливать зависимость отдельно для каждого проекта, мы используем один Lock файл для всех и храним его в общей папке. Соответственно из этой папки, одной единственной командой можно устанавливать зависимости для всех подпроектов.
Автоматическое разрешение конфликтов при слиянии yarn.lock файлов
Что такое LOCK-файлы? Они содержат точное описание зависимостей пакета и их версий, которые использовались во время последней установки или обновления проекта, включая транзитивные пакеты. Это позволяет убедиться, что при следующей установке зависимости будут установлены те же версии, что и раньше и не возникнет несовместимостей.
Довольно редко, но все же встречаются ситуации, когда мы получаем конфликты при слияние веток в lock-файлах. Как правило, это боль, с которой очень тяжело разобраться. В обычной жизни мы просто запускаем команду установки пакетов и конфликты решаются автоматически.
Selective dependency resolutions
Или по-другому – возможность определить версию для транзитивной зависимости. Иногда случаются ситуации, когда в транзитивный пакет вашей любимой библиотеки попал баг, в таком случае вы понижаете версию данного пакета до более стабильной. Вот что написано в официальной документации YARN:
Yarn upgrade-interactive
Частенько нам приходится обновлять какие-либо пакеты. Обычно для этого надо либо изменить версии в package.json файле, либо использовать специальные команды в консоли и перечислить необходимые пакеты. Yarn предлагает более современный и удобный способ обновления зависимостей – с помощью команды yarn upgrade-interactive, которая позволяет взаимодействовать с интерактивным интерфейсом для обновления зависимостей в проекте:
Возможность работы с плагинами
YARN имеет систему плагинов, которая позволяет расширять функциональность, добавляя новые команды и возможности. В 2021 году вышла вторая версия YARN. Теперь все новые функции будут разрабатываться исключительно для нее. Но YARN 2 использует другие концепции: он полностью избавился от папки node_modules и работает на основе неких плагинов. Да и в целом пока еще не до конца стабилен, поэтому сегодня мы его рассматривать не будем.
PNPM (PERFORMANT NPM) менеджер
В Марте 2016 года Zoltan Kochan представил первую версию PNPM. Этот менеджер пакетов решил проблему с объемом занимаемого дискового пространства и недоступностью зависимостей. Это в свою очередь подтолкнуло разработчиков YARN к созданию Yarn Plug'n'Play (Yarn PnP). Он по умолчанию будет добавлен во вторую версию.
PNPM выполняет все операции с пакетами атомарно. Это гарантирует, что все изменения зависимостей будут отменены, если какая-то операция завершится неудачно. Так мы можем избежать проблем с несовместимостью зависимостей и ряд других.
Разработчики PNPM создали свой собственный подход к установке зависимостей. Изначально фокусировались на полной совместимости с NPM. У них были почти идентичные cli команды и для перехода с NPM на PNPM не было необходимости переучиваться. Просто добавляете букву «p» в начале и все работает. Однако сейчас NPM и PNPM не являются идентичными в использовании. Например, добавление пакетов в PNPM теперь как в YARN: pnpm add название пакета
Какие особенности есть у PNPM?
Скорость работы с пакетами. (Hard links)
PNPM использует специальную технологию для установки зависимостей — «hard links». Она позволяет избежать копирования дублирующихся файлов между пакетами. А значит, уменьшает объем занимаемого дискового пространства и ускоряет процесс установки.
PNPM создает на компьютере единый репозиторий npm-пакетов с контентно-адресуемой файловой системой, подобной Git. Каждый файл в этой системе получает хэш от своего содержимого, и файлы с одинаковым содержанием не повторяются. В папке node_modules создаются символические ссылки на эти файлы, вместо того чтобы их каждый раз копировать.
То есть, если у вас есть 50 проектов с одинаковыми зависимостями, PNPM сохранит пакеты на диске только один раз и создаст символические ссылки для остальных 49 проектов. PNPM работает в несколько раз быстрее, чем NPM и YARN, потребляет меньше интернет-трафика. Также он более надежен, так как проверяет валидность пакетов через хэши.
Произвольные имена пакетов
В PNPM реализована возможность устанавливать пакеты с произвольными именами. Например: .pnpm add lodash@npm:awesome-lodash
Возможность автозаполнения при работе с зависимостями
Например, мы можем увидеть список всех зависимостей, которые доступны для удаления. Если хотите узнать про PNPM еще больше, почитайте статью его создателя.
Но есть и минусы:
— Возможные проблемы с кроссплатформенностью, так как хардлинки работают по-разному на разных операционных системах.
— Неподдерживаемые пакеты: некоторые пакеты могут не работать должным образом с PNPM, потому что не поддерживают символические ссылки, которые использует PNPM.
— Меньшая поддержка сообществом: PNPM не настолько популярен, как NPM или YARN, поэтому сообщество, которое может помочь с возникающими проблемами, пока еще небольшое.
Для любителей табличек. Сравниваем менеджеры
Это сравнительная таблица самых популярных менеджеров из официальной документации PNPM.
А это рейтинг менеджеров, опубликованный на платформе State of JS. Онсоставлен на основе статистики по соотношению удержания, интереса, использования и осведомленности пользователями. Здесь, кстати, видно что PNPM в последнее время стал пользоваться большей популярностью.
В статье мы сравнивали три технологии: NPM, YARN, PNPM. Теперь на реальном проекте установили пакеты с помощью каждой из них. Теперь видно наглядно, что, например, PNPM сделал все за 5 секунд, в то время как NPM – за одну минуту. Устанавливали по два раза, один раз без lock файла, второй раз с lock файлом.
Подведем итоги
NPM – менеджер по-умолчанию. И хоть он старается изо всех сил наступать на пятки своим конкурентам, до сих пор считается наиболее медленным в сравнении с остальными. Самым оптимальным менеджером в данный момент является YARN. У него неплохие оптимизация и скорость установки зависимостей. Он более стабилен, чем PNPM. А еще аудитория у YARN гораздо больше. PNPM cчитается самым современным и наиболее быстрым из всех менеджеров, однако имеет свои минусы, пока что менее стабилен в сравнении с другими менеджерами.
Если вы не гонитесь за скоростью и не желаете использовать современные возможности, такие как workspaces, добавление плагинов и многие другие, – смело используйте NPM. Если вы – активный разработчик, которому нравится пробовать все новое и, возможно, даже вносить свою лепту в мир аутсорса, – добро пожаловать в мир PNPM. Ну а лично мне нравится использовать YARN, сегодня это золотая середина между скоростью и стабильностью.