paint-brush
Почему вам не нужны PNPM и YARNby@bormando

Почему вам не нужны PNPM и YARN

Dmitrii Bormotov9m2024/07/23
Read on Terminal Reader

npm — это менеджер пакетов по умолчанию для экосистемы **Node.js**. Он поставляется с установочным пакетом, поэтому он практически готов к использованию при установке **Node.js** на свой компьютер (или в любом поставщике **CI**, если вы там настроили **Node.js**). Он стабилен и его скорость сравнима с другими менеджерами пакетов.
featured image - Почему вам не нужны PNPM и YARN
Dmitrii Bormotov HackerNoon profile picture
0-item

Всем привет!


Я уверен, что вы видели проекты Node.js, использующие разные менеджеры пакетов, например:



Я видел это сам и работал со всем вышеперечисленным, но у меня всегда был вопрос: что заставляет людей/команды использовать Yarn или pnpm вместо npm ? Каковы плюсы? Есть ли минусы?


Что ж… Давайте узнаем!

Правила сравнения производительности

Я решил сравнить npm , Yarn и pnpm с точки зрения их «скорости»…


Ниже вы увидите 3 меры:


  1. Создайте файл блокировки без кэша.


  2. Установите зависимости из существующих файлов блокировки без кэша.


  3. Установите зависимости из существующих файлов блокировки с глобальным кешем.


Существует два типа кэша:


  1. Глобальный.

    Обычно хранится в домашнем каталоге пользователя (fe, ~/.yarn/berry/cache ).


  2. Местный.

    Хранится в каталоге проекта (fe, <project-dir>/.yarn ).


Хотя, по моему опыту, наиболее распространенными вариантами использования являются № 2 и № 3 , на всякий случай я также выбрал № 1 (хотя это очень редкий случай).


В качестве примера для тестов я использовал пример проекта из create-react-app .

НПМ

Это менеджер пакетов по умолчанию для экосистемы Node.js — что еще сказать? Он поставляется с установочным пакетом, поэтому он практически готов к использованию при установке Node.js на свой компьютер (или в любом поставщике CI , если вы там настроили Node.js ).


На мой взгляд, это огромный плюс – вам не нужно устанавливать его отдельно!


Ничего выдающегося, просто… работает! И за прошедшие годы я не заметил каких-либо серьезных ошибок — он кажется довольно стабильным и выполняет свою работу.


Возможности npm, которые я использовал до сих пор:


  1. Управление зависимостями (установка, удаление, обновление)
  2. Публикация пакетов (частных, общедоступных)
  3. Ссылка на локальные пакеты
  4. Управляйте рабочими пространствами.

Управление зависимостями

npm хранит зависимости в папке node_modules в корне вашего проекта. Довольно просто.


ℹ️ package-lock.json хранит информацию о реестрах для перечисленных пакетов — это ОЧЕНЬ удобно, если у вас есть пакеты из одной области, т.е. @example-company в разных реестрах (например — npm & GitHub Packages ):


запись package-lock.json


Теперь давайте посмотрим, как он работает с точки зрения скорости установки…

Создать package-lock.json без кеша

Создайте package-lock.json и установите зависимости без кеша.


Потребовалось 1 минута чтобы npm сгенерировал package-lock.json и установил зависимости без кеша.


Используемая команда:

 npm i

Установите зависимости из package-lock.json без кеша

Установите зависимости из package-lock.json без кеша.


Потребовалось 18 секунд для npm для установки зависимостей из package-lock.json без кеша.


Используемая команда:

 npm ci

Установите зависимости из package-lock.json с глобальным кешем

Установите зависимости из package-lock.json с глобальным кешем.


Потребовалось 8 секунд для npm для установки зависимостей из package-lock.json с глобальным кешем.


Используемая команда:

 npm ci

Управление рабочими пространствами

Мне удалось создать рабочее пространство и управлять зависимостями для всего рабочего пространства сразу и для конкретных проектов отдельно.


Другими словами, он выполняет свою работу без каких-либо ошибок/проблем, а официальная документация довольно проста.


Функции рабочей области, которые я использовал до сих пор:


  1. Установите зависимости для всех проектов в рабочей области.
  2. Установите зависимости для одного конкретного проекта.
  3. Рекурсивно запускайте один скрипт для всех проектов одновременно.

пряжа

Честно говоря, некоторые особенности пряжи я особо не пробовала. Я имею в виду, что я много использовал его в плане «установки зависимостей» при работе над некоторыми проектами, и все.


В комплект поставки Yarn не входит установщик Node.js , поэтому вам придется установить его отдельно. Это означает, что в ваших конвейерах CI будет дополнительный шаг — вам придется настроить пряжу перед установкой зависимостей проекта.

Управление зависимостями

В Yarn есть два подхода к установке зависимостей:


  1. « Нулевые установки » (по умолчанию) — создает папку .yarn и перечисляет пакеты в файлах yarn.lock и .pnp.cjs .


  2. Обычный, аналогичный npm , сохраняет зависимости в node_modules и перечисляет их в файле yarn.lock .


ℹ️ файлы блокировки пряжи хранят информацию о реестрах для всех перечисленных пакетов ТОЛЬКО если вы используете старый (обычный) подход к установке.


⚠️ Имейте в виду, что « Нулевые установки », похоже, хранят пакеты в локальном кеше и предоставляют ссылки на ваши файлы блокировки:


Ссылки на пакеты

Это может быть важно для вас, если у вас есть Dockerfile или CI -конвейер, в котором вы устанавливаете зависимости в одну чистую среду, а затем хотите переместить их в другую (вам придется скопировать и папку .yarn , и локальный кеш).


Поскольку подход по умолчанию для Yarn сейчас — « Нулевые установки » и имеет лучшую производительность, чем старый подход — мы собираемся записывать тесты только с этим подходом.

Генерировать файлы блокировки без кэша

Сгенерируйте файлы блокировки с помощью Yarn и установите зависимости.


Потребовалось 16,5 секунд чтобы Yarn сгенерировал файл yarn.lock и установил зависимости без кеша.


Используемая команда:

 yarn install

Установите зависимости из существующих файлов блокировки без кэша

Установите зависимости с помощью подхода «Нулевая установка» и без кэша.


Потребовалось 11 секунд для Yarn для установки зависимостей с использованием подхода «Zero Install» и без какого-либо кеша.


Используемая команда:

 yarn install --frozen-lockfile

Установите зависимости из существующих файлов блокировки с помощью глобального кэша


Установите зависимости с помощью подхода «нулевой установки» и глобального кеша.


Потребовалось 8 секунд для Yarn для установки зависимостей с использованием подхода «Zero Install» и глобального кеша.


Используемая команда:

 yarn install --frozen-lockfile

Управление рабочими пространствами

Мне удалось создать рабочее пространство и управлять зависимостями для всех проектов сразу и для конкретных проектов отдельно.


Функции рабочей области, которые я использовал до сих пор:


  1. Установите зависимости для всех проектов в рабочей области.
  2. Установите зависимости для одного конкретного проекта.
  3. Рекурсивно запускайте один скрипт для всех проектов одновременно.


Документация хорошая, но имена и флаги команд несколько сбивают с толку.


Например, мне нужно выполнить это, чтобы запустить test скрипт в корневом ( . ) и вложенном проекте b2b :


 yarn workspaces foreach -A --include '{.,b2b}' run test


По сравнению с npm :


 npm run test --workspace=b2b --include-workspace-root

пнпм

pnpm сейчас на хайпе — его используют множество компаний и проектов с открытым исходным кодом .


Как и в случае с Yarn , pnpm не поставляется с установщиком Node.js , поэтому его придется устанавливать отдельно. Это означает, что в ваших конвейерах CI будет дополнительный шаг — вам придется настроить pnpm перед установкой зависимостей проекта.

Управление зависимостями

pnpm считается « быстрым менеджером пакетов, эффективно использующим дисковое пространство »


Действительно, я согласен с утверждением об «эффективном дисковом пространстве» с точки зрения локального управления зависимостями.


По умолчанию pnpm устраняет дубликаты общих зависимостей. pnpm создает символические ссылки для пакетов, которые используются в нескольких зависимостях. т. е. если пакеты a и b используют пакет c в качестве зависимости, pnpm сохранит пакет c как одну копию и создаст символические ссылки для пакетов a и b . Таким образом, менеджер пакетов не создает бумажные копии и экономит память на вашем SSD/HDD.


ℹ️ pnpm-lock.yaml не хранит информацию о реестрах для перечисленных пакетов.


⚠️ Имейте в виду, что pnpm иногда хранит зависимости в глобальном кеше, а не как проект.

Создать pnpm-lock.yaml без кеша

Создать pnpm-lock.yaml


Потребовалось 31 секунда чтобы pnpm сгенерировал pnpm-lock.yaml и установил зависимости без кэша.


Используемая команда:

 pnpm install

Установите зависимости из pnpm-lock.yaml без глобального кэша

Установите зависимости из pnpm-lock.yaml без глобального кеша.


Потребовалось 16 секунд для pnpm для установки зависимостей из pnpm-lock.yaml без кеша.


Используемая команда:

 pnpm i --frozen-lockfile


Установите зависимости из существующего файла блокировки с глобальным кешем

Установите зависимости из pnpm-lock-yaml с кешем


Потребовалось 5 секунд для pnpm для установки зависимостей из pnpm-lock.yaml с глобальным кешем.


Используемая команда:

 pnpm i --frozen-lockfile

Управление рабочими пространствами

Вот тут-то всё и становится по-настоящему интересным…


pnpm имеет множество опций конфигурации, но некоторые основные функции просто не работают!


Давайте рассмотрим пару ошибок, с которыми я столкнулся:

pnpm установить --фильтр

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


т. е. представьте, что в вашем рабочем пространстве есть:


  • веб-приложение,
  • внутренний сервер,
  • тестовый проект (сквозные тесты).


Все это отдельные проекты npm , но они являются частью одного репо ☝️


Теперь вам нужно, чтобы конвейер запускал только сквозные тесты. Итак, вам нужны только сквозные тестовые зависимости, верно?


Ну, вы не сможете этого сделать — pnpm заставляет вас устанавливать зависимости для всей рабочей области!


pnpm install --filter <project-name> должен был устанавливать зависимости только для выбранных проектов, но это не работает.


Это ошибка годичной давности, и недавно она была закрыта с нерабочим исправлением.

рекурсивная установка = false

pnpm по умолчанию устанавливает зависимости для всей рабочей области (всех проектов) при запуске pnpm install


Вы можете изменить это поведение, если установите recursive-install=false в .npmrc в корне вашего рабочего пространства.


НО это вводит еще одну ошибку, которой уже почти 2 года .

файл общей рабочей области-lockfile = false

pnpm по умолчанию хранит список зависимостей в одном файле блокировки (так же, как npm и Yarn ).


Вы также можете изменить это поведение, если shared-workspace-lockfile=false в .npmrc в корне вашего рабочего пространства.


Это позволило бы нам сохранить функцию рабочей области и использовать флаг --ignore-workspace для установки зависимостей для конкретного проекта.


В любом случае, этот параметр создает еще несколько проблем:


  1. eslint и tsc --noEmit выдают ошибку «JavaScript Heap Out of Memory» в моих конвейерах действий GitHub .


  2. Некоторые зависимости хранятся в глобальном кеше и имеют символические ссылки в node_modules/.pnpm .

Результаты сравнения производительности

#

НПМ

пряжа

пнпм

Создать файл блокировки

60 секунд

16,5 сек.

31 секунда

Установить зависимости без кеша

18 секунд

11 секунд

8 секунд

Установите зависимости с глобальным кешем

8 секунд

8 секунд

5 секунд


Согласно приведенному выше тесту, npm — самый медленный менеджер пакетов ☝️


В любом случае, давайте интерпретируем эти результаты…

Создать файл блокировки

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


Учитывая это, кажется, что при выборе менеджера пакетов не так уж важно полагаться на него.

Установить зависимости

В большинстве случаев ваши проекты хранят определенный список зависимостей, и вы редко что-то добавляете/удаляете.


Скорее всего, вы будете время от времени обновлять версии своих пакетов — эти изменения невелики, и вы будете повторно использовать остальные пакеты из кеша.


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


pnpm (5-8 сек) почти в два раза быстрее, чем npm (8-18 сек) с пряжей (8-11 сек) посередине.

Заключение

Факты

  • pnpm действительно является «быстрым и экономичным» менеджером пакетов — в текущем обзоре это совершенно ясно!


  • В функции рабочего пространства pnpm есть ошибки, и некоторые из них не устраняются уже много лет.


  • И pnpm , и Yarn требуют дополнительной настройки в конвейерах CI, а npm — нет.


  • И pnpm , и Yarn не хранят информацию о реестре пакетов в своих файлах блокировки, в то время как npm это делает.

Мысли автора

Я думаю, что pnpm лучше всего справляется со своей задачей, если ваши требования к менеджеру пакетов такие же простые, как «устанавливать только зависимости».


Несмотря на то, что pnpm не поставляется с готовым установщиком Node.js , его легко настроить в конвейерах CI с помощью Corepack или существующих действий .


Я предпочитаю npm , потому что:


  • он стабилен (особенно рабочие области),


  • поставляется с Node.js и не требует дополнительной настройки в конвейере CI,


  • хранит реестры пакетов в package-lock.json , поэтому вы можете устанавливать зависимости с одной областью из разных реестров.


Эти плюсы перевешивают секунды скорости и дискового пространства, которые я бы сэкономил с помощью Yarn или pnpm .


Каковы ваши критерии выбора пакетного менеджера? Не стесняйтесь и дайте мне знать свои мысли в разделе комментариев ниже! 👇😊