borekb / blog

Viz issues
https://github.com/borekb/blog/issues
11 stars 0 forks source link

Yarn vs. npm vs. pnpm #3

Open borekb opened 3 years ago

borekb commented 3 years ago

Yarn vs. npm vs. pnpm

Inspirován zápiskem https://orta.io/notes/js/yarn-vs-npm, rád bych si taky poznamenal, jak se v roce 2021 dívám na situaci kolem JS package managerů.

Úvodem

JavaScript vypadá jako většina C-čkových jazyků, ale na rozdíl od těch klasických (Java / C# / PHP / ...) je hodně o konkrétních objektech namísto globálních jmen. Obecně tak není problém mít v projektu víc věcí jmenujících se stejně, resp. jednu knihovnu ve více verzích:

JS deps

Ne každý to považuje za dobrou věc, ale já si moc dobře vzpomínám, jak jsme půl roku nemohli updatovat na novější PhpUnit, protože ten začal záviset na novější verzi knihovny X, kterou ještě jiný balíček nestihnul aktualizovat, a ještě horší to je u systémů, které člověk nemá plně pod kontrolou – VersionPress chtěl záviset na knihovnách typu Guzzle nebo Symfony FileSystem, ale nikdy jsme nemohli vědět, jestli výsledný WordPress web nebude používat další pluginy s nekompatibilními verzemi téhož. Zlé...

JavaScript tenhle problém nemá, ale to neznamená, že jsou věci jednoduché.

Věci jsou poměrně jednoduché v moderních prostředích typu ESM v browseru nebo Deno, kde se používají konkrétní importy z konkrétních cest, např.:

import { add } from 'https://x.nest.land/ramda@0.27.0/source/index.js';

Ale převážná realita v Node.js je pořád něco jako:

import { add } from 'ramda';

(Technicky require, ale to je detail.)

A tam je otázka, co ta "ramda" je. Na odpovědi spolupracují dvě věci:

  1. Node.js module resolution algoritmus
  2. Package manager (připravuje soubory na disku tak, aby Node.js načetl správné moduly)

Jednička je daná, ale pro bod 2 existují různé softwary dělající různé kompromisy. A o nich je tenhle blog post.

npm

npm je klasika. Dlouhé roky jsme s ním žili a vlastně to bylo docela OK. Z dnešního pohledu mi sice připadá šílené, že každé npm install mohlo vést k drobně jiné instalaci node_modules, ale asi naše aplikace byly jednodušší, repozitáře menší atd. 😄

Když pak v roce 2016 přišel Yarn, nebylo co řešit – daleko rychlejší, konečně lockfiles, lepší command-line UX, workspaces atd.

npm jsem ale nepřestal sledovat, hlavně kvůli verzi 7, která měla v mnoha ohledech dohnat Yarn. Bohužel se někdy kolem let 2018/19 začalo npm Inc. dostávat do velkých problémů – startupu docházely peníze, řada lidí uvnitř byla toxických, nebyla radost to sledovat a npm si prošlo poměrně temným obdobím. Záchrana nakonec přišla ze strany GitHubu / Microsoftu – bylo to o fous, ale vlastně to líp dopadnout nemohlo.

Co se mi na npm líbí:

Co se mi na npm nelíbí:

Celkově bych si npm 7 asi už celkem v pohodě vybral na jednodušší JS projekt, možná to je i nejlepší volba. U složitějšího projektu (např. company monorepo) jsou ale limity node_modules podstatné a nějaká alternativa je skoro "nutností".

Yarn

Yarn má za sebou dvě životní etapy:

  1. Yarn 1
  2. Yarn 2+, vydaný na začátku roku 2020

Yarn 1 byl miláček – používali ho "všichni" a dal JS světu mnoho dobrého – reproducible installs, rychlost, workspaces atd.

Yarn 2 ("Berry") vykročil tak trochu za hranice běžného package manageru – vedle instalace balíčků se snaží pomoct s DX v monorepu, s release workflows, ale taky má některé silné názory na to, jak by měl spolehlivý vývoj vypadat obecně – PnP, Zero-Installs atd.

Asi největší kontroverze je právě kolem PnP (Plug'n'Play) – tato instalační strategie existovala už za časů Yarnu 1 (a nikomu nevadila, protože byla volitelná a "schovaná"), ale Yarn 2 se rozhodl z ní udělat default. To byla za mě chyba, dejte si třeba tvíty z ledna 2020 nebo https://github.com/yarnpkg/berry/issues/766. Pořád to neutichlo, tohle je čerstvý příklad:

Screen Shot 2021-05-01 at 13 49 23-shadow

Je to škoda, protože Yarn 2 lze během dvou minut nakonfigurat tak, aby fungoval "postaru", ale nechme historie a pojďme k technickým věcem.

Co se mi na Yarnu líbí:

Co se mi na Yarnu nelíbí:

Celkově je Yarn pokročilý package manager, který i z velké části dokáže nahradit Lernu, build tool, monorepo managera atd. (což je za mě super, např. Lerna mě svého času vyloženě štvala; čím míň softwaru, tím líp). Hodí se nám dvě různé instalační strategie, různé stupně striktnosti, občas si do Yarnu napíšeme vlastní plugin, zkrátka pokročilý parťák.

pnpm

S pnpm nemáme moc reálných zkušeností, ale už dlouho po něm pokukujeme, protože jeho instalační strategie vypadá naprosto skvěle (zdroj):

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
    ├── bar@1.0.0
    │   └── node_modules
    │       ├── bar -> <store>/bar
    │       └── qar -> ../../qar@2.0.0/node_modules/qar
    ├── foo@1.0.0
    │   └── node_modules
    │       ├── foo -> <store>/foo
    │       ├── bar -> ../../bar@1.0.0/node_modules/bar
    │       └── qar -> ../../qar@2.0.0/node_modules/qar
    └── qar@2.0.0
        └── node_modules
            └── qar -> <store>/qar

Trochu to připomíná PnP, ale zůstává u prostých složek namísto ZIP souborů, což je v mnoha ohledech praktičtější.

Zde se nehodlám pustit do většího hodnocení, protože mi chybí zkušenosti, ale určité dojmy jsou:

pnpm dále sledujeme, nebo by mi vlastně stačilo, kdyby se pnpm instalační strategie dostala do Yarnu jako plugin (https://github.com/yarnpkg/berry/issues/1845) 😎.


Asi se mi úplně nepovedlo udělat si pár krátkých poznámek 😄.

Package manager je pro nás super-důležitou věcí – už třeba instalace devDependencies v repo rootu do běžných node_modules není ve větším repu moc dobrý nápad, a vůbec s rostoucí komplexitou / množstvím balíčků je PM čím dál důležitější.

Já momentálně za "nejlepší" package manager považuju Yarn, ale vybrat si není jednoduché – tolik různých možností, tolik nuancí...


Opravy:

arcanis commented 3 years ago

Nice article! (I had to read it through Google Translate so pray forgive if I misunderstood something 😄) Two little notes:

Pak ale přišel Yarn 2 a ten udělal jedno ~vysoce kontroverzní~ špatné rozhodnutí: instalační strategii PnP (Plug'n'Play), která existovala už za časů Yarnu 1, udělal jedinou možnou. Z Yarnu se tak dočasně stal JS package manager, který neuměl nainstalovat závislosti do node_modules, resp. idea byla, že kdo chce node_modules, má používat Yarn 1 – no zkrátka chyba.

No version of Yarn 2.x shipped without node_modules support. It's been there from the very first stable release. I think some large accounts relayed incorrect information at the start (and we could have highlighted it a bit more, admittedly), but we specifically waited for it to be ready before getting out of beta.

Yarn 2 není veřejně vydanou binárkou, např. npm i -g yarn nebo brew install yarn vždy nainstaluje verzi 1.22, Yarn 2 se pak instaluje jako .cjs soubor do konkrétního projektu. Na jednu stranu je dobré, že různé části většího monorepa můžou používat svou specifickou verzi Yarnu, a taky je filosoficky pěkné, že package manager je u projektu commitnutý v přesně dané verzi, na druhou stranu my obecně do Gitu binárky necommitujeme, takže nám to vytváří drobné dilema. (Zmínka bokem: y2.)

Node just voted this week to include Corepack in future releases, so there's reasonable hope that the install experience will improve significantly during the next few months!

zkochan commented 3 years ago

Děkuji za dobré slova!

What also makes pnpm unique is that it uses a content-addressable store and files are hard-linked from it. So you end up using less disk space for your dependencies. And it probably contributes to faster installation times as well.

borekb commented 3 years ago

@arcanis You're right, I was probably thinking about the pre-release period in 2019 where we were evaluating Yarn 2 (beta) and PnP was the only linker back then. I'll update the blog post, thanks for catching this.

What's your account of why there was a such a strong backlash against Yarn 2 then? Was it only because of the changed defaults? Would be great to know how you remember that...

borekb commented 3 years ago

@zkochan That is a great point, I'll add it to the lists of pnpm advantages. Thanks!

belaczek commented 1 year ago

Díky za pěkné shrnutí. U nás dlouhodobě řešíme, na co zmigrovat naše NX monorepo z yarn classic. Největší bolístkou je rychlost (pomalost) předávání node_modules artefaktů v rámci Gitlab CI jobů. V tomhle ohledu zatím jasně vítězí Yarn pnp, jelikož upload/download několika zip souborů je řádově rychlejší (5s vs 1m:20s), než udělat to samé s node_modules složkou. Bohužel se nám zatím v pnp módu nepodařilo dosáhnout funkčního stavu.

borekb commented 1 year ago

@belaczek Většinou se "cachuje cache" neboli (globální) Yarn cache. Dělá to tak i actions/cache, viz zde.

belaczek commented 1 year ago

@borekb Jojo, tady jde ale o předávání node_modules atrefaktů mezi jednotlivými joby v CI. GitLab to má tak, že každý job se spouští na čistém podu a je tak potřeba pokažde stáhnout a extrahovat už předtím nainstalované artefakty. A tohle stahování a extrahování docela trvá (alespoň na nešem železe). Alternativou by bylo instalovat node modules v každém jobu zvlášť, ale to by bylo ještě pomalejší.