pnpm – czyli dlaczego warto przestać marnować miejsce na dysku

Jeśli pracujecie z JavaScript od jakiegoś czasu, na pewno macie zainstalowane npm – bo jest domyślnie z Node.js i trudno go uniknąć. Być może używacie też yarna, bo w 2016 roku był naprawdę szybszy od npm i jako pierwszy wprowadził lockfile. Ale pnpm? Przez długi czas był niszowy, a dziś trudno otworzyć dokumentację jakiegokolwiek nowoczesnego narzędzia JS i go nie zobaczyć. Myślę, że warto wyjaśnić skąd ta popularność i czy jest uzasadniona.

Zacznijmy od pnpm

pnpm (skrót od performant npm) rozwiązuje problem, który przez lata był traktowany jako normalny – czyli to, że przy każdym projekcie Node.js na dysku lądują gigabajty tych samych paczek.

Macie 10 projektów, każdy używa Reacta? Bez pnpm na dysku macie 10 kopii Reacta. Przy pnpm – tylko jedną.

Działa to tak, że pnpm utrzymuje jeden globalny store na dysku (~/.pnpm-store), a w node_modules każdego projektu trafiają jedynie dowiązania (symlinki i hard linki) do tego wspólnego miejsca. Efekt jest taki, że instalacja kolejnego projektu, który używa tych samych zależności, jest błyskawiczna – bo pliki już są na dysku, trzeba tylko stworzyć linki.

globalny store (jeden na cały komputer)
    └── pliki wszystkich paczek

projekt-A/node_modules/ ← linki do store
projekt-B/node_modules/ ← te same linki, zero duplikacji

Ale to nie jedyna zaleta. pnpm chroni też przed tzw. phantom dependencies — czyli sytuacją, w której używacie w kodzie paczki, której sami nigdy nie zainstalowaliście.

Jak to możliwe? npm i yarn spłaszczają strukturę node_modules — jeśli Wasza zależność A wewnętrznie używa lodasha, to lodash ląduje bezpośrednio w node_modules i nic nie stoi na przeszkodzie żebyście sami go zaimportowali, nawet jeśli nie ma go w Waszym package.json. Działa? Działa. Problem pojawia się gdy aktualizujecie zależność A i ona przy okazji przestaje używać lodasha — Wasz kod przestaje działać, a przyczyna jest zupełnie nieoczywista.

pnpm tego nie dopuszcza. W node_modules widzicie tylko to co sami zadeklarowaliście.

A npm i yarn?

Żeby było jasne jak pnpm się wyróżnia – warto zobaczyć skąd w ogóle pochodzi ta trójka.

npm

npm jest od zawsze. Lata temu miał poważne problemy – był wolny, nie miał domyślnego lockfile’a, a struktura node_modules była płaska i chaotyczna. Z czasem te rzeczy poprawiono (package-lock.json pojawił się w wersji 5), ale główny problem pozostał: każdy projekt dostaje swoje własne kopie wszystkich paczek. Na większym monorepo potrafi to być kilkanaście GB śmieci.

yarn

Yarn stworzył Facebook w 2016 roku, żeby poprawić to co w npm nie działało. I w swoim czasie był znaczącym krokiem naprzód – równoległe pobieranie, cache, yarn.lock zanim npm miał swój lockfile.

Yarn Berry (czyli v2 i wyżej) poszedł jednak w dość radykalną stronę – Plug’n’Play, które całkowicie pozbywa się node_modules na rzecz jednego pliku .pnp.cjs. Idea fajna, ale w praktyce wiele narzędzi miało z tym problemy i migracja bywała uciążliwa. Część społeczności po prostu odpuściła i… przeszła do pnpm.

Porównanie w pigułce

npmyarnpnpm
🚀 Szybkość instalacjiśredniadobranajlepsza
💾 Miejsce na dyskudużodużomało
👻 Phantom dependenciestaktaknie
🏗️ Monorepo (workspaces)OKOKświetne
🌍 Ekosystemnajwiększydużyrosnący
🔒 Lockfilepackage-lock.jsonyarn.lockpnpm-lock.yaml

Dlaczego pnpm nagle jest wszędzie?

Kilka rzeczy złożyło się na to jednocześnie.

Po pierwsze – monorepo stały się standardem. Przy dziesiątkach pakietów w jednym repo, oszczędności miejsca i czasu instalacji są naprawdę odczuwalne. pnpm ma wsparcie dla workspaces, które działa po prostu dobrze.

Po drugie – Vite, Astro, SolidJS i inne popularne narzędzia albo domyślnie polecają pnpm, albo same go używają. Jak zaczynasz nowy projekt z Vite i patrzysz na dokumentację, widzisz pnpm create vite. I tak to się kręci.

Po trzecie – Yarn Berry się nie przyjął. Nie wszystkim odpowiadała migracja do PnP i część deweloperów po prostu skończyła z pnpm jako alternatywą, która nie wymaga tak dużego przestawienia myślenia.

I po czwarte – CI/CD. Każdy menedżer paczek można cache’ować w pipeline’ach i każdy daje jakiś zysk. Ale pnpm ma tu naturalną przewagę szczególnie w monorepo — zamiast utrzymywać wiele kopii tych samych paczek, wszystkie pakiety współdzielą jeden store. Wystarczy go raz przywrócić z cache’a, a pnpm install sprowadza się do błyskawicznego tworzenia linków, bez pobierania czegokolwiek z sieci.

Jak zacząć?

Instalacja jest prosta:

npm install -g pnpm

Albo przez corepack (wbudowany w Node.js):

corepack enable
corepack prepare pnpm@latest --activate

A potem zamiast npm install po prostu: pnpm install

Podsumowanie

Jeśli zaczynasz nowy projekt – pnpm to aktualnie bardzo dobry wybór. Jeśli masz stary projekt i zastanawiasz się czy warto migrować – lockfile można wygenerować od nowa, a sama migracja to w większości przypadków zmiana jednego polecenia w skryptach.

Jedyne kiedy zostałabym przy npm to projekt z bardzo specyficznymi wymaganiami lub sytuacja, gdzie część teamu po prostu nie chce zmieniać przyzwyczajeń. Ale to już bardziej problem ludzki niż techniczny 😄

You might also like