Hallo zusammen!
Sie haben sicher schon Node.js-Projekte gesehen, die unterschiedliche Paketmanager verwenden, beispielsweise:
Ich habe das selbst gesehen und mit all dem oben genannten gearbeitet, aber ich hatte immer eine Frage im Kopf – was bewegt Leute/Teams dazu, yarn oder pnpm statt npm zu verwenden? Was sind die Vorteile? Gibt es irgendwelche Nachteile?
Nun... finden wir es heraus!
Ich habe beschlossen, npm , yarn und pnpm hinsichtlich ihrer „Geschwindigkeit“ zu vergleichen …
Nachfolgend sehen Sie 3 Maßnahmen:
Erstellen Sie eine Sperrdatei ohne Cache.
Installieren Sie Abhängigkeiten von vorhandenen Sperrdateien ohne Cache.
Installieren Sie Abhängigkeiten von vorhandenen Sperrdateien mit globalem Cache.
Es gibt zwei Arten von Cache:
Weltweit.
Normalerweise im Home-Verzeichnis des Benutzers gespeichert (zB ~/.yarn/berry/cache
).
Lokal.
Wird im Projektverzeichnis gespeichert (zB <project-dir>/.yarn
).
Während Nr. 2 und Nr. 3 meiner Erfahrung nach die häufigsten Anwendungsfälle sind, habe ich vorsichtshalber auch Nr. 1 genommen (obwohl das ein seeehr seltener Fall ist).
Als Beispiel für Benchmarks habe ich ein Beispielprojekt von create-react-app verwendet.
Es handelt sich um einen Standardpaketmanager für das Node.js- Ökosystem – was soll man sonst noch dazu sagen? Er wird mit dem Installationspaket geliefert und ist daher grundsätzlich einsatzbereit, wenn Sie Node.js auf Ihrem Computer installieren (oder in einem beliebigen CI- Anbieter, wenn Sie Node.js dort einrichten).
Das ist meiner Meinung nach ein großes „Pro“ – Sie müssen es nicht separat installieren!
Nichts Besonderes – es funktioniert einfach! Und ich habe im Laufe der Jahre keine größeren Fehler gesehen – es scheint ziemlich stabil zu sein und erledigt die Arbeit.
Die Funktionen von npm, die ich bisher verwendet habe:
npm speichert Abhängigkeiten im Ordner node_modules
Ihres Projektstamms. Ziemlich unkompliziert.
ℹ️ package-lock.json
speichert Informationen zu Registern für die aufgelisteten Pakete – das ist SEHR praktisch, wenn Sie Pakete aus einem einzigen Bereich haben, d. h. @example-company
in verschiedenen Registern (z. B. npm- und GitHub-Pakete ):
Sehen wir uns nun an, wie die Installationsgeschwindigkeit aussieht …
Es dauertepackage-lock.json
generiert und Abhängigkeiten ohne Cache installiert.
Verwendeter Befehl:
npm i
Es dauertepackage-lock.json
ohne Cache installiert.
Verwendeter Befehl:
npm ci
Es dauertepackage-lock.json
mit globalem Cache installiert.
Verwendeter Befehl:
npm ci
Ich konnte einen Arbeitsbereich erstellen und Abhängigkeiten für den gesamten Arbeitsbereich auf einmal und für bestimmte Projekte separat verwalten.
Mit anderen Worten: Es erledigt die Arbeit ohne Fehler/Probleme und die offizielle Dokumentation ist ziemlich unkompliziert.
Arbeitsbereichsfunktionen, die ich bisher verwendet habe:
Ehrlich gesagt habe ich einige der Yarn- Funktionen noch nicht oft ausprobiert. Ich meine, ich habe sie bei der Arbeit an einigen Projekten häufig zum „Installieren von Abhängigkeiten“ verwendet, und das war’s auch schon.
yarn wird nicht mit einem Node.js- Installationsprogramm geliefert, Sie müssen es also separat installieren. Das bedeutet, dass in Ihren CI- Pipelines ein zusätzlicher Schritt erforderlich ist – Sie müssen yarn einrichten, bevor Sie Ihre Projektabhängigkeiten installieren.
Yarn bietet zwei Ansätze zum Installieren von Abhängigkeiten:
„ Zero Installs “ (Standard) – erstellt einen .yarn
Ordner und listet Pakete in den Dateien yarn.lock
und .pnp.cjs
auf.
Eine normale Variante – ähnlich wie npm – speichert Abhängigkeiten in node_modules
und listet sie in der Datei yarn.lock
auf.
ℹ️ Yarn -Lock-Dateien speichern NUR Informationen zu Registrierungen für alle aufgelisteten Pakete, wenn Sie den alten (regulären) Installationsansatz verwenden.
⚠️ Bedenken Sie, dass „ Zero Installs “ Pakete im lokalen Cache zu speichern scheint und Links zu Ihren Sperrdateien bereitstellt:
Dies kann für Sie wichtig sein, wenn Sie über eine Docker-Datei oder CI- Pipeline verfügen, in der Sie Abhängigkeiten in einer sauberen Umgebung installieren und diese dann in eine andere verschieben möchten (Sie müssen sowohl den .yarn
Ordner als auch den lokalen Cache kopieren).
Da der Standardansatz für Yarn jetzt „ Null Installationen “ ist und eine bessere Leistung als der alte Ansatz bietet, werden wir Benchmarks nur mit diesem Ansatz aufzeichnen.
Es dauerteyarn.lock
Datei generiert und Abhängigkeiten ohne Cache installiert.
Verwendeter Befehl:
yarn install
Es dauerte
Verwendeter Befehl:
yarn install --frozen-lockfile
Es dauerte
Verwendeter Befehl:
yarn install --frozen-lockfile
Ich konnte einen Arbeitsbereich erstellen und Abhängigkeiten für alle Projekte gleichzeitig und für bestimmte Projekte separat verwalten.
Arbeitsbereichsfunktionen, die ich bisher verwendet habe:
Die Dokumentation ist in Ordnung, aber Befehlsnamen und Flags sind etwas verwirrend.
Beispielsweise muss ich dies ausführen, um test
im Stammverzeichnis ( . ) und im verschachtelten b2b
Projekt auszuführen:
yarn workspaces foreach -A --include '{.,b2b}' run test
Im Vergleich mit npm :
npm run test --workspace=b2b --include-workspace-root
pnpm ist derzeit ein Hype – viele Unternehmen und Open-Source-Projekte verwenden es .
Genau wie Yarn wird pnpm nicht mit einem Node.js- Installationsprogramm geliefert, Sie müssen es also separat installieren. Das bedeutet, dass in Ihren CI- Pipelines ein zusätzlicher Schritt erforderlich ist: Sie müssen pnpm einrichten, bevor Sie Ihre Projektabhängigkeiten installieren.
pnpm gilt als „ schneller, speicherplatzsparender Paketmanager “ …
Tatsächlich stimme ich der Aussage „Speicherplatzeffizienz“ im Hinblick auf die lokale Verwaltung von Abhängigkeiten zu.
Standardmäßig entfernt pnpm Duplikate gemeinsam genutzter Abhängigkeiten. pnpm erstellt symbolische Links für die Pakete, die in mehreren Abhängigkeiten verwendet werden. Wenn beispielsweise die Pakete a
und b
Paket c
als Abhängigkeit verwenden, speichert pnpm Paket c
als einzelne Kopie und erstellt symbolische Links für die Pakete a
und b
. Auf diese Weise erstellt der Paketmanager keine Hardcopys und spart Speicher auf Ihrer SSD/HDD.
ℹ️ pnpm-lock.yaml
speichert keine Informationen zu Registrierungen für die aufgelisteten Pakete.
⚠️ Denken Sie daran, dass pnpm Abhängigkeiten manchmal im globalen Cache speichert, anstatt sie als Projekt zu behalten.
Es dauertepnpm-lock.yaml
generiert und Abhängigkeiten ohne Cache installiert.
Verwendeter Befehl:
pnpm install
Es dauertepnpm-lock.yaml
ohne Cache installiert.
Verwendeter Befehl:
pnpm i --frozen-lockfile
Es dauertepnpm-lock.yaml
mit globalem Cache installiert.
Verwendeter Befehl:
pnpm i --frozen-lockfile
Jetzt wird es wirklich interessant …
pnpm hat viele Konfigurationsoptionen, aber einige Kernfunktionen funktionieren einfach nicht!
Sehen wir uns ein paar Fehler an, mit denen ich konfrontiert war:
Es ist wichtig, Abhängigkeiten nur für bestimmte Projekte installieren zu können. Dies ist bei Monorepos sehr nützlich, wenn Sie Pipelines erstellen, die sich auf bestimmte Projekte innerhalb des Arbeitsbereichs beziehen.
Stellen Sie sich beispielsweise vor, Sie hätten in Ihrem Arbeitsbereich:
Dies sind alles separate npm- Projekte, aber sie sind Teil desselben Repos ☝️
Nun möchten Sie, dass eine Pipeline nur End-to-End-Tests ausführt. Sie benötigen also nur End-to-End-Testabhängigkeiten, richtig?
Nun, das werden Sie nicht tun können – pnpm zwingt Sie, Abhängigkeiten für den gesamten Arbeitsbereich zu installieren!
pnpm install --filter <project-name>
sollte nur Abhängigkeiten für ausgewählte Projekte installieren, funktioniert aber nicht.
pnpm installiert standardmäßig Abhängigkeiten für den gesamten Arbeitsbereich (alle Projekte), wenn Sie pnpm install
ausführen
Sie können dieses Verhalten ändern, indem Sie in .npmrc
in Ihrem Arbeitsbereichsstamm recursive-install=false
festlegen.
ABER es führt einen weiteren Fehler ein, der schon fast 2 Jahre alt ist .
pnpm speichert die Abhängigkeitsliste standardmäßig in einer einzigen Sperrdatei (wie npm und yarn ).
Sie können dieses Verhalten auch ändern, wenn Sie in .npmrc
in Ihrem Arbeitsbereichsstamm shared-workspace-lockfile=false
festlegen.
Dadurch könnten wir die Arbeitsbereichsfunktion beibehalten und das Flag --ignore-workspace
verwenden, um Abhängigkeiten für ein bestimmtes Projekt zu installieren.
Diese Einstellung bringt jedoch einige weitere Probleme mit sich:
eslint
und tsc --noEmit
werfen in meinen GitHub Actions -Pipelines einen „JavaScript-Heap nicht genügend Arbeitsspeicher“ -Fehler aus.
Einige der Abhängigkeiten werden im globalen Cache gespeichert und in node_modules/.pnpm
symbolisch verknüpft.
# | npm | Garn | pnpm |
---|---|---|---|
Generieren einer Sperrdatei | 60 Sek. | 16,5 Sek. | 31 Sek. |
Installieren Sie Abhängigkeiten ohne Cache | 18 Sek. | 11 Sek. | 8 Sek. |
Installieren Sie Abhängigkeiten mit globalem Cache | 8 Sek. | 8 Sek. | 5 Sek. |
Laut dem obigen Benchmark ist npm der langsamste Paketmanager ☝️
Lassen Sie uns diese Ergebnisse jedenfalls interpretieren …
Dies ist ein seltener Fall. Normalerweise wird bei der Projektinitialisierung eine Sperrdatei erstellt und dann erweitert, wenn Sie Pakete installieren/aktualisieren.
In Anbetracht dessen scheint es kein besonders wichtiger Faktor zu sein, auf den Sie sich bei der Auswahl eines Paketmanagers verlassen sollten.
In den meisten Fällen enthalten Ihre Projekte eine bestimmte Liste von Abhängigkeiten und Sie fügen selten etwas hinzu bzw. entfernen es.
Höchstwahrscheinlich werden Sie von Zeit zu Zeit Versionen Ihrer Pakete aktualisieren. Diese Änderungen sind geringfügig und Sie werden die restlichen Pakete aus dem Cache wiederverwenden.
Mit anderen Worten: Der übliche Anwendungsfall ist: Neue Pakete aus der Paketregistrierung abrufen und den Rest aus dem Cache holen.
pnpm (5–8 Sek.) ist fast doppelt so schnell wie npm (8–18 Sek.) mit yarn (8–11 Sek.) in der Mitte.
Ich denke, dass pnpm die beste Arbeit leistet, wenn Ihre Anforderung an den Paketmanager so einfach ist wie „nur Abhängigkeiten installieren“.
Obwohl pnpm nicht mit einem vorinstallierten Node.js- Installationsprogramm ausgeliefert wird, lässt es sich mit Corepack oder einer vorhandenen Aktion problemlos in CI-Pipelines einrichten.
Ich bevorzuge npm , weil:
package-lock.json
sodass Sie Abhängigkeiten mit einem einzigen Umfang aus verschiedenen Registrierungen installieren können.
Diese Vorteile überwiegen die Sekunden an Geschwindigkeit und Speicherplatz, die ich mit yarn oder pnpm sparen würde.
Nach welchen Kriterien wählen Sie einen Paketmanager aus? Seien Sie nicht schüchtern und teilen Sie mir Ihre Meinung im Kommentarbereich unten mit! 👇😊