Příze:

V komunitě JavaScriptových inženýrů sdílíme statisíce kusů kódu, abychom se vyhnuli přepisování základních komponent, knihoven nebo vlastních frameworků. Každý kus kódu může zase záviset na jiných kusech kódu a tyto závislosti spravují správci balíčků. Nejoblíbenějším správcem balíčků v jazyce JavaScript je klient npm, který poskytuje přístup k více než 300 000 balíčkům v registru npm. Registr npm používá více než 5 milionů inženýrů, kteří každý měsíc zaznamenají až 5 miliard stažení.

Klienta npm jsme ve společnosti Facebook úspěšně používali řadu let, ale s rostoucí velikostí naší kódové základny a počtem inženýrů jsme naráželi na problémy s konzistencí, zabezpečením a výkonem. Poté, co jsme se snažili vyřešit každý problém tak, jak se objevil, jsme se rozhodli vytvořit nové řešení, které by nám pomohlo spolehlivěji spravovat naše závislosti. Výsledkem této práce je Yarn – rychlá, spolehlivá a bezpečná alternativa klienta npm.

Jsme rádi, že můžeme oznámit vydání open source řešení Yarn, které vzniklo ve spolupráci se společnostmi Exponent, Google a Tilde. Díky Yarnu mají inženýři stále přístup k registru npm, ale mohou rychleji instalovat balíčky a konzistentně spravovat závislosti na různých počítačích nebo v bezpečných offline prostředích. Yarn umožňuje inženýrům postupovat rychleji a s jistotou při používání sdíleného kódu, takže se mohou soustředit na to, co je důležité – vytváření nových produktů a funkcí.

Vývoj správy balíčků JavaScriptu ve společnosti Facebook

V dobách před správci balíčků se inženýři JavaScriptu běžně spoléhali na malý počet závislostí uložených přímo v jejich projektech nebo obsluhovaných sítí CDN. První významný správce balíčků pro JavaScript, npm, vznikl krátce po uvedení Node.js a rychle se stal jedním z nejoblíbenějších správců balíčků na světě. Vznikly tisíce nových open source projektů a inženýři sdíleli více kódu než kdy dříve.

Mnoho našich projektů ve společnosti Facebook, například React, závisí na kódu v registru npm. Při interním škálování jsme se však potýkali s problémy s konzistencí při instalaci závislostí na různých počítačích a u různých uživatelů, s množstvím času potřebného k natažení závislostí a měli jsme určité obavy o bezpečnost v souvislosti se způsobem, jakým klient npm automaticky spouští kód z některých těchto závislostí. Pokusili jsme se tyto problémy obejít, ale často samy vyvolávaly nové problémy.

Pokusy o škálování klienta npm

Zpočátku jsme podle předepsaných osvědčených postupů pouze zkontrolovali package.json a požádali inženýry o ruční spuštění npm install. Pro inženýry to fungovalo dostatečně dobře, ale v našich prostředích kontinuální integrace, která musí být z bezpečnostních a spolehlivostních důvodů odříznuta od internetu, to selhalo.

Dalším řešením, které jsme zavedli, bylo zkontrolovat všechny node_modules do úložiště. To sice fungovalo, ale poměrně to ztěžovalo některé jednoduché operace. Například aktualizace minoritní verze programu babel vygenerovala revizi o 800 000 řádcích, která se obtížně přistávala a spouštěla pravidla lint pro neplatné posloupnosti bajtů utf8, konce řádků v oknech, obrázky nepomačkané v png a další. Slučování změn node_modules by inženýrům často zabralo celý den. Náš tým pro kontrolu zdrojů také upozornil, že naše zkontrolovaná složka node_modules je zodpovědná za obrovské množství metadat. V adresáři React Native package.json je aktuálně uvedeno pouhých 68 závislostí, ale po spuštění npm install adresář node_modules obsahuje 121 358 souborů.

Provedli jsme poslední pokus o škálování klienta npm, aby vyhovoval počtu inženýrů ve společnosti Facebook a množství kódu, který potřebujeme nainstalovat. Rozhodli jsme se celý adresář node_modules zazipovat a nahrát do interní sítě CDN, aby inženýři i naše systémy průběžné integrace mohli soubory stahovat a rozbalovat konzistentně. To nám umožnilo odstranit stovky tisíc souborů ze správy zdrojových kódů, ale způsobilo to, že inženýři potřebovali přístup k internetu nejen ke stažení nového kódu, ale také k jeho sestavení.

Museli jsme také obejít problémy s funkcí npm shrinkwrap, kterou jsme používali k uzamčení verzí závislostí. Soubory shrinkwrap se ve výchozím nastavení negenerují a vypadnou ze synchronizace, pokud je inženýři zapomenou vygenerovat, takže jsme napsali nástroj, který ověřuje, zda obsah souboru shrinkwrap odpovídá tomu, co je v node_modules. Tyto soubory jsou však obrovské bloby JSON s neuspořádanými klíči, takže jejich změny by generovaly obrovské, obtížně kontrolovatelné revize. Abychom to zmírnili, museli jsme přidat další skript, který všechny záznamy roztřídí.

Nakonec, aktualizace jedné závislosti pomocí npm aktualizuje i mnoho nesouvisejících závislostí na základě sémantických pravidel verzování. Díky tomu je každá změna mnohem větší, než se předpokládalo, a nutnost provádět takové úkony, jako je odevzdání node_modules nebo nahrání do sítě CDN, způsobila, že tento proces nebyl pro inženýry ideální.

Vytvoření nového klienta

Namísto dalšího budování infrastruktury kolem klienta npm jsme se rozhodli zkusit se na problém podívat komplexněji. Co kdybychom se místo toho pokusili vytvořit nového klienta, který by řešil základní problémy, s nimiž jsme se potýkali? Sebastian McKenzie v naší londýnské kanceláři začal tuto myšlenku hackovat a my jsme se rychle nadchli pro její potenciál.

Když jsme na tom pracovali, začali jsme mluvit s inženýry z celého odvětví a zjistili jsme, že se potýkají s podobným souborem problémů a pokoušeli se o mnoho stejných řešení, často zaměřených na řešení jediného problému najednou. Bylo zřejmé, že spoluprací na celém souboru problémů, kterým komunita čelí, bychom mohli vyvinout řešení, které by fungovalo pro všechny. S pomocí inženýrů ze společností Exponent, Google a Tilde jsme vytvořili klienta Yarn a otestovali a ověřili jeho výkon na všech hlavních JS frameworcích a pro další případy použití mimo Facebook. Dnes se o něj s nadšením dělíme s komunitou.

Představujeme Yarn

Yarn je nový správce balíčků, který nahrazuje stávající pracovní postup pro klienta npm nebo jiné správce balíčků a zároveň zůstává kompatibilní s registrem npm. Má stejnou sadu funkcí jako stávající pracovní postupy, přičemž pracuje rychleji, bezpečněji a spolehlivěji.

Primární funkcí každého správce balíčků je nainstalovat nějaký balíček – kus kódu, který slouží určitému účelu – z globálního registru do lokálního prostředí inženýra. Každý balíček může, ale nemusí záviset na jiných balíčcích. Typický projekt může mít ve svém stromu závislostí desítky, stovky nebo dokonce tisíce balíčků.

Tyto závislosti jsou verzovány a instalovány na základě sémantického verzování (semver). Semver definuje schéma verzování, které odráží typy změn v každé nové verzi, tedy zda změna porušuje rozhraní API, přidává novou funkci nebo opravuje chybu. Semver však spoléhá na to, že vývojáři balíčků neudělají chybu – rozbíjející změny nebo nové chyby se mohou dostat do nainstalovaných závislostí, pokud nejsou závislosti uzamčeny.

Architektura

V ekosystému Node se závislosti umísťují do node_modules adresáře v projektu. Tato struktura souborů se však může lišit od skutečného stromu závislostí, protože duplicitní závislosti jsou sloučeny dohromady. Klient npm instaluje závislosti do adresáře node_modules nedeterministicky. To znamená, že na základě pořadí instalace závislostí se může struktura adresáře node_modules u jednotlivých osob lišit. Tyto rozdíly mohou způsobit chyby typu „funguje na mém počítači“, jejichž odhalení zabere hodně času.

Yarn řeší tyto problémy týkající se verzování a nedeterminismu pomocí zamykacích souborů a instalačního algoritmu, který je deterministický a spolehlivý. Tyto zámkové soubory uzamykají nainstalované závislosti na konkrétní verzi a zajišťují, že výsledkem každé instalace je přesně stejná struktura souborů v node_modules na všech počítačích. Zapsaný soubor zámku používá stručný formát s uspořádanými klíči, aby bylo zajištěno, že změny budou minimální a kontrola jednoduchá.

Proces instalace je rozdělen do tří kroků:

  1. Rozlišení: Yarn začne řešit závislosti tím, že provede požadavky na registr a rekurzivně vyhledá jednotlivé závislosti.
  2. Vyhledávání: Dále se Yarn podívá do globálního adresáře mezipaměti, zda již nebyl potřebný balíček stažen. Pokud ne, Yarn načte tarball balíčku a umístí jej do globální mezipaměti, aby mohl pracovat offline a nemusel stahovat závislosti více než jednou. Závislosti lze také umístit do správy zdrojů jako tarball pro úplnou offline instalaci.
  3. Propojení: Nakonec Yarn vše propojí zkopírováním všech potřebných souborů z globální mezipaměti do místního adresáře node_modules.

Díky čistému rozdělení těchto kroků a deterministickým výsledkům je Yarn schopen operace paralelizovat, což maximalizuje využití zdrojů a zrychluje proces instalace. U některých projektů Facebooku zkrátil Yarn proces instalace řádově z několika minut na pouhé sekundy. Yarn také používá mutex, který zajišťuje, že se více spuštěných instancí CLI navzájem nekoliduje a neznečišťuje.

Při celém tomto procesu Yarn ukládá přísné záruky kolem instalace balíčků. Máte kontrolu nad tím, které skripty životního cyklu se spustí pro které balíčky. Kontrolní součty balíčků jsou také uloženy v souboru zámku, aby bylo zajištěno, že pokaždé dostanete stejný balíček.

Funkce

Kromě toho, že instalace jsou mnohem rychlejší a spolehlivější, má Yarn další funkce, které dále zjednodušují pracovní postup správy závislostí.

  • Kompatibilita s pracovními postupy npm i bower a podpora míchání registrů.
  • Možnost omezit licence instalovaných modulů a prostředky pro výstup informací o licencích.
  • Vystavuje stabilní veřejné rozhraní JS API s abstrahovaným protokolováním pro použití prostřednictvím nástrojů pro sestavení.
  • Čitelný, minimální a pěkný výstup CLI.

Yarn ve výrobě

Ve společnosti Facebook již používáme Yarn ve výrobě a funguje nám velmi dobře. Zajišťuje správu závislostí a balíčků pro mnoho našich projektů v JavaScriptu. S každou migrací jsme inženýrům umožnili sestavovat offline a pomohli jsme jim zrychlit pracovní postupy. You can see how install times for Yarn and npm compare on React Native under different conditions, which you can find here.

Getting started

The easiest way to get started is to run:

npm install -g yarn

yarn

The yarn CLI replaces npm in your development workflow, either with a matching command or a new, similar command:

  • npm installyarn

    With no arguments, the yarn command will read your package.json, fetch packages from the npm registry, and populate your node_modules folder. It is equivalent to running npm install.

  • npm install --save <name>yarn add <name>

    We removed the „invisible dependency“ behavior of npm install <name> and split the command. Running yarn add <name> is equivalent to running npm install --save <name>.

Future

Many of us came together to build Yarn to solve common problems, and we knew that we wanted Yarn to be a true community project that everyone can use. Yarn is now available on GitHub and we’re ready for the Node community to do what it does best: Use Yarn, share ideas, write documentation, support each other, and help build a great community to care for it. We believe that Yarn is already off to a great start, and it can be even better with your help.