npm проти pnpm: порівняння зберігання, швидкості та практичних компромісів
Ця стаття порівнює, як npm та pnpm обробляють зберігання залежностей, швидкість встановлення та робочі процеси для монорепо, щоб допомогти вам обрати правильний інструмент для вашого проекту.
Якщо ви витрачали час на розробку за допомогою React, Next.js, Node.js чи будь-якої іншої сучасної бази коду на JavaScript, ймовірно, ви вводили цю команду більше разів, ніж можете порахувати:
npm install
Вона просто працює. Усі її розпізнають. Майже кожен онлайн-туторіал використовує її.
А потім, зрештою, хтось каже вам щось на кшталт:
"Чому ви все ще використовуєте npm? Просто використовуйте pnpm."
Тож ви пробуєте pnpm.
І незабаром починаєте запитувати себе:
Чи справді pnpm є покращенням, чи це просто ще одна з тих дискусій про інструменти JavaScript, які зникнуть через кілька місяців?
Це цілком закономірне запитання.
Npm жодним чином не є несправним. Він знайомий, надійний та постачається разом із Node.js. Щоб від нього відмовитися, потрібна справжня причина.
Як тільки ви детальніше розберетеся, як саме працює кожен інструмент, ви зрозумієте, що справжня проблема — це не просто npm versus pnpm.
Усе зводиться до того, як вони керують залежностями, скільки місця на диску вони займають, як відбувається встановлення за різних умов та який тип проекту ви створюєте.
І найважливіше запитання:
Який з них має сенс використовувати саме вам?
npm та pnpm вирішують одну й ту саму основну проблему
Почнемо з очевидного.
І npm, і pnpm — це менеджери пакетів, створені для середовища Node.js.
Обидва завантажують пакети з реєстру npm та використовують однакові стандарти package.json.
Припустимо, ваш проект потребує React. Ви можете встановити його за допомогою npm:
npm install react
Або ж можна скористатися pnpm замість цього:
pnpm add react
У будь-якому разі React все одно буде встановлений.
Ви не перейшли на зовсім інший екосистему JavaScript.
Насправді змінюється те, що відбувається всередині після встановлення та зберігання пакетів на вашому комп’ютері.
Саме тут дизайн pnpm починає вирізнятися.
Де вони справді розходяться: як зберігаються залежності
Кожен з них залежить від React.
За допомогою класичної налаштування npm кожен проект підтримує власну незалежну папку node_modules, де зберігаються необхідні пакети.
Якщо таке стосується багатьох проектів, це призводить до великої кількості дублюючихся файлів, які займають місце.
pnpm обирає інший підхід.
Він зберігає пакети в єдиному сховищі з адресним управлінням, а потім створює посилання з цього сховища до кожного проекту, який їх потребує.
Простіше кажучи, замість того щоб постійно копіювати однаковий пакет для кожного проекту, pnpm може використовувати вже наявну копію у своєму центральному сховищі.
Project A ──┐
Project B ──┤
Project C ──┼── Shared package store
Project D ──┤
Project E ──┘
Насправді механізм, який стоїть за цим, є складнішим, ніж показує ця проста схема, але саме основна ідея є ключовою тут.
pnpm розроблений для мінімізації зайвих копій.
Якщо ви одночасно працюєте над кількома проектами, такий підхід може суттєво зменшити використання диска.
Чи справді pnpm встановлює програми швидше?
Це зазвичай перше, що хочуть дізнатися розробники.
Чесна відповідь:
Часто — так, але не завжди.
Багато тестів показують, що pnpm значно швидший за npm у встановленні.
Проблема полягає у тому, що швидкість встановлення залежить від безлічі факторів.
Ваше інтернет-з’єднання також має значення.
Так само, як і апаратне забезпечення вашого диска.
Кількість пакетів, від яких залежить ваш проєкт, також має значення.
Те, чи знаходяться ці пакети вже у локальній кеш-пам’яті, також має вплив.
Розмір проєкту також є важливим фактором.
Навіть виконання нової установки порівняно з переустановкою чогось, що ви вже завантажували раніше, може дати зовсім інші результати.
Архітектура pnpm будується навколо ефективного завантаження та поєднання пакетів, і оскільки вона підтримує спільний сховище, пакети, які вже є у вас локально, можна просто повторно використати замість їхнього повторного завантаження.
Саме в таких ситуаціях його переваги найбільш помітні.
Холодна та тепла установки суттєво відрізняються
Це деталь, яку часто ігнорують під час порівняння менеджерів пакетів.
Припустимо, ви встановлюєте пакет уперше.
У вас немає іншого вибору, окрім як завантажити його з нуля.
Це, по суті, сценарій початку роботи з чистого аркуша.
Тепер уявіть, що точно такий самий пакет вже існує в іншому проекті на вашому комп’ютері.
Це зовсім інша вихідна точка.
Саме тут і проявляється користь спільного магазину pnpm.
Замість того, щоб розглядати кожен проект як повністю ізольовану одиницю, pnpm може використовувати пакети, які вже зберігаються локально.
Тож якщо ви регулярно створюєте нові проекти, видаляєте папки node_modules, часто перевстановлюєте залежності або перемикаєтесь між кількома репозиторіями, ефективність pnpm з часом стає ще більш помітною.
Але якщо ваша робоча процедура полягає лише у одному невеликому проекті, де залежності встановлюються лише один раз, різниця, ймовірно, не справить на вас сильного враження.
Ось чому я уникаю таких тверджень:
„pnpm завжди є швидшим варіантом.“
pnpm, як правило, є значно ефективнішим, особливо у робочих процесах, які ґрунтуються на багаторазових встановленнях чи складних деревах залежностей.
npm суттєво вдосконалився порівняно зі своєю колишньою репутацією
npm ci для забезпечення відтворюваних встановлень у CI-пайплайнах.
npm ci
Тож називати npm повільним, застарілим чи погано спроєктованим — це неправдиво.
Він залишається абсолютно надійним вибором для значної кількості проектів.
Те, що відрізняє pnpm, — це те, що він зробив конкретні рішення щодо оптимізації, і ці рішення стають все більш помітними у міру зростання проекту.
Ще одна відмінність, з якою стикаються розробники: ізоляція залежностей
Це не є очевидним відразу, особливо якщо ви новачок у цій екосистемі.
require чи import для B, і це буде працювати.
Деякий час здається, що все гаразд.
Тоді пакет A оновлюється та замінює свої залежності. B більше не знаходиться там, де ваш код очікує його присутності, і раптово ваше додаток викидає помилку, якої ви не очікували.
У цій ситуації є назва: фантомна залежність. Ви покладаєтесь на щось, від чого насправді не могли покладатися.
pnpm уникає цього завдяки своїй конструкції. Його стандартна структура значно суворіша щодо того, що пакет може бачити, що ускладнює вашому проекту використання чогось, що він ніколи не оголосив як залежність.
Це справді цінна гарантія. Вона змушує вас бути чесними щодо того, що насправді потрібно вашому додатку, замість того щоб користуватися випадковостями розташування файлів. Така точність зазвичай має більше значення у довгостроковій перспективі, ніж скорочення кількох секунд під час встановлення.
Сценарій, де pnpm справді проявляє себе: монорепозиторії
Це, мабуть, найсильніший аргумент на користь використання pnpm.
my-project/
│
├── apps/
│ ├── web/
│ └── admin/
│
├── packages/
│ ├── ui/
│ ├── utils/
│ └── config/
│
└── package.json
Є кілька додатків та кілька спільних внутрішніх пакетів, які всі знаходяться разом у одному репозиторії. Саме таку конфігурацію називають монорепо.
NPM дійсно підтримує робочі простори, тож створити монорепо за допомогою NPM цілком можливо. Однак pnpm доклав значно більше зусиль саме до інструментарію для монорепо. Він надає такі функції, як протокол робочого простору, прапорці фільтрації для виконання команд у конкретних пакетах та модель залежностей, розроблена з урахуванням багатопакетних репозиторіїв — усе це може значно полегшити роботу з великою кодовою базою.
Якщо ви підтримуєте невеликий особистий проект, усе це для вас насправді не має значення.
Але якщо ви підтримуєте репозиторій із кількома додатками та десятками внутрішніх спільних пакетів, ці інструменти стають значно кориснішими.
Перехід від npm до pnpm — це незначні зусилля
Поширеною причиною, чому розробники уникають використання pnpm, є припущення, що їм доведеться вивчати цілу нову низку команд.
Насправді це не так. Більшість повсякденних команд відповідають майже один-на-один.
Встановлення залежностей за допомогою npm виглядає так:
npm install
За допомогою pnpm це виглядає так:
pnpm install
Додавання пакета в npm:
npm install axios
у pnpm перетворюється на це:
pnpm add axios
Додавання dev-залежності в npm:
npm install -D typescript
перетворюється на:
pnpm add -D typescript
Видалення пакета в npm:
npm uninstall axios
перетворюється на:
pnpm remove axios
Запуск скрипта в npm:
npm run dev
можна скоротити до:
pnpm dev
І якщо ви вже знайомі з npx, у pnpm є свій еквівалент:
pnpm dlx
Тож крива навчання тут мінімальна.
Ситуації, коли npm все ще є найкращим вибором
Якщо ви вперше знайомите когось із JavaScript або Node.js, npm — це природний вибір для початку. Не тому, що він технічно кращий у всьому — а просто тому, що він є стандартним, а початківцям вже потрібно засвоїти багато чого, не додаючи ще й рішення щодо менеджера пакетів.
Якщо у навчальному посібнику пропонується виконати:
npm install express
ви повинні мати змогу просто ввести цей код та продовжити вивчення самої концепції, яку пояснюють.
NPM також є правильним вибором, коли ви працюєте з кодовою базою, яка вже побудована навколо нього. Немає сенсу наполягати на іншому:
«Команда завжди використовувала npm, але тут віддають перевагу pnpm, тож давайте конвертувати всю налаштовку».
Ситуації, коли pnpm стає більш доцільним
Ізоляція залежностей — ще одна причина обрати саме його: якщо суворі межі між тим, що оголошено, і тим, що можна використовувати, справді мають значення для вашого проекту, pnpm за замовчуванням це гарантує.
Простіше кажучи: чим більшою та хаотичнішою стає конфігурація JavaScript, тим привабливішим стає pnpm.
То хто перемагає у швидкості?
Якщо шукати одну конкретну відповідь, pnpm зазвичай має перевагу у ефективності встановлення, особливо коли його спільний магазин вже має пакети у локальній кеш-пам’яті.
Проте було б некоректно стверджувати щось на кшталт:
"pnpm працює рівно вдвічі швидше, ніж npm."
Такі твердження спрощують ситуацію. Результати тестування сильно варіюються залежно від умов. Запуск абсолютно нової інсталяції через швидке мережеве з’єднання не можна порівнювати з переінсталяцією пакетів на комп’ютері, де більшість з них вже зберігається локально у кеші. Крім того, середовище CI поводиться інакше, ніж локальний комп’ютер.
Тож, якщо єдиним підставою для розгляду зміни менеджерів пакетів є діаграма тестування, краще спочатку проаналізувати власний робочий процес, перш ніж приймати рішення.
Що б я обрав
Для невеликого проекту на React npm виконує свою роботу без проблем.
Те саме стосується проектів для навчання — npm підходить ідеально.
Якщо ви приєднуєтесь до існуючого кодового базису команди, використовуйте те, що вже стандартизовано командою.
Однак для великого монорепозиторію pnpm стає серйозним конкурентом.
Якщо ви працюєте на комп’ютері, де постійно перемикаєтесь між багатьма проектами на JavaScript, pnpm, як правило, є більш практичним вибором.
Саме тому тут немає єдиного універсального переможця.
Не змінюйте інструмент лише через те, що pnpm у тренді
Це, можливо, найважливіший момент у всьому цьому порівнянні.
Вам не потрібно мігрувати кожен існуючий проект з npm на pnpm лише тому, що ця тема постійно згадується у онлайн-дискусіях розробників.
І вам точно не потрібно змінювати інструмент через те, що хтось наполягає:
"npm мертвий."
Це не так. Обидва інструменти активно підтримуються, у обох є розвинені екосистеми, і обидва цілком здатні обробляти сучасні проекти на JavaScript.
Справжнє питання не в тому, „який менеджер пакетів об’єктивно найкращий“. Йдеться про те, „який менеджер пакетів підходить саме моєму способу роботи“.
Якщо ви створюєте невеликі додатки, вивчаєте мову програмування або працюєте в команді, яка вже використовує npm, то залишатися з npm — цілком розумний вибір.
Якщо ж ви керуєте великими проектами, кількома репозиторіями чи монорепозиторіями та хочете більш ефективного зберігання залежностей та швидшого їх встановлення, тоді варто спробувати pnpm.
Заключні думки
Перед порівнянням npm та pnpm здавалося, що буде чіткий та простий вердикт — npm є застарілою опцією, а pnpm — швидким оновленням.
Насправді все виявилося більш складним.
Основною сильною стороною npm є його простота та той факт, що майже всі вже з ним знайомі. Він є стандартною опцією не даремно.
Основні переваги pnpm — це його модель зберігання залежностей, ефективність під час встановлення та інструменти, які він пропонує для проектів більшого масштабу.
Тож якщо ви тільки починаєте працювати з JavaScript, не хвилюйтесь щодо вибору — просто використовуйте npm та починайте розробку.
Якщо ви вже добре розумієте Node.js та ваші проекти розвиваються, спробуйте pnpm та подивіться, чи покращить він ваш щоденний робочий процес.
Зрештою, саме менеджер пакетів, який ви оберете, не робить додаток хорошим.
Це робить ваш код.
Пов’язана література
- Довідник команд Node.js для локальної розробки та серверів у продакшені — це зручний для перегляду довідник, який охоплює керування версіями Node.js, менеджери пакетів, налаштування середовища, відлагодження, PM2 та розгортання в Linux без перерв.