Bonjour à tous!
Je suis sûr que vous avez vu des projets Node.js utiliser différents gestionnaires de packages, c'est-à-dire :
J'ai vu cela moi-même et j'ai travaillé avec tout ce qui précède, mais j'ai toujours eu une question en tête : qu'est-ce qui pousse les personnes/équipes à utiliser fil ou pnpm au lieu de npm ? Quels sont les avantages ? Y a-t-il des inconvénients ?
Eh bien… Découvrons-le !
Règles de comparaison des performances
J'ai décidé de comparer npm , fil et pnpm en termes de leur « vitesse »…
Vous verrez 3 mesures ci-dessous :
Générez un fichier de verrouillage sans aucun cache.
Installez les dépendances à partir des fichiers de verrouillage existants sans aucun cache.
Installez les dépendances des fichiers de verrouillage existants avec le cache global.
Il existe deux types de cache :
Mondial.
Généralement stocké dans le répertoire personnel de l'utilisateur (fe,
~/.yarn/berry/cache
).
Locale.
Stocké dans le répertoire du projet (par exemple,
<project-dir>/.yarn
).
Bien que les cas d'utilisation n°2 et n°3 soient les cas d'utilisation les plus courants d'après mon expérience, j'ai également pris le n°1 juste au cas où (bien que ce soit un cas très rare).
J'ai utilisé un exemple de projet de create-react-app comme exemple de benchmark.
npm
C'est un gestionnaire de packages par défaut pour l'écosystème Node.js - que dire d'autre ? Il est livré avec le package d'installation, il est donc fondamentalement prêt à être utilisé lorsque vous installez Node.js sur votre machine (ou dans n'importe quel fournisseur CI si vous y configurez Node.js ).
C'est un énorme « avantage » à mon avis : vous n'avez pas besoin de l'installer séparément !
Rien d'exceptionnel là-bas - ça marche juste ! Et je n'ai vu aucun bug majeur au fil des ans - il semble assez stable et fait le travail.
Les fonctionnalités de npm que j'ai utilisées jusqu'à présent :
- Gérer les dépendances (installer, supprimer, mettre à jour)
- Publier des packages (privés, publics)
- Forfaits lien-local
- Gérer les espaces de travail.
Gérer les dépendances
npm stocke les dépendances dans le dossier node_modules
de la racine de votre projet. Assez simple.
ℹ️ package-lock.json
stocke des informations sur les registres pour les packages répertoriés - cela s'avère TRÈS pratique si vous avez des packages d'une seule portée, c'est-à-dire @example-company
dans différents registres (par exemple - npm & GitHub Packages ) :
Voyons maintenant comment il se comporte en termes de vitesse d'installation…
Générer package-lock.json sans aucun cache
Ça a prispackage-lock.json
et installe les dépendances sans aucun cache.
Commande utilisée :
npm i
Installer les dépendances à partir de package-lock.json sans aucun cache
Ça a prispackage-lock.json
sans aucun cache.
Commande utilisée :
npm ci
Installer les dépendances à partir de package-lock.json avec le cache global
Ça a prispackage-lock.json
avec le cache global.
Commande utilisée :
npm ci
Gérer les espaces de travail
J'ai pu créer un espace de travail et gérer les dépendances pour l'ensemble de l'espace de travail à la fois et pour des projets spécifiques séparément.
En d’autres termes, le travail est effectué sans aucun bug/problème, et la documentation officielle est assez simple.
Fonctionnalités de Workspace que j'ai utilisées jusqu'à présent :
- Installez les dépendances pour tous les projets dans l'espace de travail.
- Installez les dépendances pour un seul projet spécifique.
- Exécutez un seul script pour tous les projets à la fois et de manière récursive.
fil
Honnêtement, je n’ai pas beaucoup essayé certaines fonctionnalités du fil . Je veux dire, je l'ai beaucoup utilisé pour « installer des dépendances » en travaillant sur certains projets, et c'est tout à fait ça.
Yarn n'est pas fourni avec un programme d'installation Node.js , vous devrez donc l'installer séparément. Cela signifie qu'il y aurait une étape supplémentaire dans vos pipelines CI : vous devrez configurer Yarn avant d'installer les dépendances de votre projet.
Gérer les dépendances
Yarn a deux approches pour installer les dépendances :
« Zéro installation » (par défaut) - crée le dossier
.yarn
et répertorie les packages dans les fichiersyarn.lock
et.pnp.cjs
.
Un standard - similaire à npm , stocke les dépendances dans
node_modules
et les répertorie dans le fichieryarn.lock
.
ℹ️ Les fichiers Yarn Lock stockent des informations sur les registres pour tous les packages répertoriés UNIQUEMENT si vous utilisez l'ancienne approche d'installation (normale).
⚠️ Gardez à l'esprit que « Zéro installation » semble stocker les packages dans le cache local et fournir des liens vers vos fichiers de verrouillage :
Cela peut être important pour vous si vous disposez d'un pipeline Dockerfile ou CI dans lequel vous installez des dépendances dans un environnement propre et que vous souhaitez ensuite les déplacer vers un autre (vous devrez copier à la fois le dossier .yarn
et le cache local).
Étant donné que l'approche par défaut pour le fil est désormais « Zéro installation » et offre de meilleures performances que l'ancienne approche, nous allons enregistrer des benchmarks avec cette approche uniquement.
Générer des fichiers de verrouillage sans aucun cache
Ça a prisyarn.lock
et installe les dépendances sans cache.
Commande utilisée :
yarn install
Installer les dépendances à partir de fichiers de verrouillage existants sans aucun cache
Ça a pris
Commande utilisée :
yarn install --frozen-lockfile
Installer les dépendances à partir de fichiers de verrouillage existants avec le cache global
Ça a pris
Commande utilisée :
yarn install --frozen-lockfile
Gérer les espaces de travail
J'ai pu créer un espace de travail et gérer les dépendances pour tous les projets à la fois et pour des projets spécifiques séparément.
Fonctionnalités de Workspace que j'ai utilisées jusqu'à présent :
- Installez les dépendances pour tous les projets dans l'espace de travail.
- Installez les dépendances pour un seul projet spécifique.
- Exécutez un seul script pour tous les projets à la fois et de manière récursive.
La documentation est bonne, mais les noms de commandes et les indicateurs prêtent quelque peu à confusion.
Par exemple, je dois exécuter ceci pour exécuter le script test
dans la racine ( . ) et le projet b2b
imbriqué :
yarn workspaces foreach -A --include '{.,b2b}' run test
En comparaison avec npm :
npm run test --workspace=b2b --include-workspace-root
pnpm
pnpm est actuellement à la mode - de nombreuses entreprises et projets open source l'utilisent .
Tout comme Yarn , pnpm n'est pas fourni avec un programme d'installation Node.js , vous devrez donc l'installer séparément. Cela signifie qu'il y aura une étape supplémentaire dans vos pipelines CI : vous devrez configurer pnpm avant d'installer les dépendances de votre projet.
Gérer les dépendances
pnpm est considéré comme « Gestionnaire de paquets rapide et efficace en termes d'espace disque » …
En effet, je suis d'accord avec l'affirmation « efficacité de l'espace disque » en termes de gestion locale des dépendances.
Par défaut, pnpm déduplique les dépendances partagées. pnpm crée des liens symboliques pour les packages utilisés dans plusieurs dépendances. c'est-à-dire que si les packages a
et b
utilisent le package c
comme dépendance, pnpm va stocker le package c
en une seule copie et créer des liens symboliques pour les packages a
et b
. De cette façon, le gestionnaire de packages ne crée pas de copies papier et économise de la mémoire sur votre SSD/HDD.
ℹ️ pnpm-lock.yaml
ne stocke pas d'informations sur les registres pour les packages répertoriés.
⚠️ Gardez à l'esprit que pnpm stocke parfois les dépendances dans le cache global, au lieu d'en faire un projet.
Générez pnpm-lock.yaml sans aucun cache
Ça a prispnpm-lock.yaml
et installe les dépendances sans aucun cache.
Commande utilisée :
pnpm install
Installer les dépendances à partir de pnpm-lock.yaml sans cache global
Ça a prispnpm-lock.yaml
sans cache.
Commande utilisée :
pnpm i --frozen-lockfile
Installer les dépendances à partir d'un fichier de verrouillage existant avec le cache global
Ça a prispnpm-lock.yaml
avec le cache global.
Commande utilisée :
pnpm i --frozen-lockfile
Gérer les espaces de travail
Maintenant, c'est là que les choses deviennent vraiment intéressantes…
pnpm a de nombreuses options de configuration, mais certaines fonctionnalités de base ne fonctionnent tout simplement pas !
Passons en revue quelques bugs que j'ai rencontrés :
pnpm installer --filtre
Il est important de pouvoir installer des dépendances pour des projets spécifiques uniquement - c'est très utile pour les monorepos lorsque vous créez des pipelines liés à des projets spécifiques dans l'espace de travail.
c'est-à-dire, imaginez que vous avez dans votre espace de travail :
- une application web,
- serveur principal,
- projet de test (tests de bout en bout).
Ce sont tous des projets npm distincts, mais ils font partie du même dépôt ☝️
Désormais, vous souhaitez qu’un pipeline exécute uniquement des tests de bout en bout. Donc, vous n’avez besoin que de dépendances de test de bout en bout, n’est-ce pas ?
Eh bien, vous ne pourrez pas faire ça - pnpm vous oblige à installer des dépendances pour l'ensemble de l'espace de travail !
pnpm install --filter <project-name>
était censé installer les dépendances pour les projets sélectionnés uniquement, mais cela ne fonctionne pas.
Il y a un bug vieux d'un an et il a été récemment fermé avec un correctif qui ne fonctionne pas.
installation récursive = false
pnpm installe par défaut les dépendances pour l'ensemble de l'espace de travail (tous les projets) lorsque vous exécutez pnpm install
Vous pouvez alterner ce comportement si vous définissez recursive-install=false
dans .npmrc
à la racine de votre espace de travail.
MAIS cela introduit un autre bug qui date déjà de presque 2 ans .
partage-workspace-lockfile=false
pnpm stocke par défaut la liste des dépendances dans un seul fichier de verrouillage (identique à npm et Yarn ).
Vous pouvez également alterner ce comportement si vous définissez shared-workspace-lockfile=false
dans .npmrc
à la racine de votre espace de travail.
Cela nous permettrait de conserver la fonctionnalité d'espace de travail et d'utiliser l'indicateur --ignore-workspace
pour installer des dépendances pour un projet spécifique.
Quoi qu'il en soit, ce paramètre introduit quelques problèmes supplémentaires :
eslint
ettsc --noEmit
génèrent une erreur « Heap JavaScript Out of Memory » dans mes pipelines GitHub Actions .
Certaines dépendances sont stockées dans le cache global et liées par un lien symbolique dans
node_modules/.pnpm
.
Résultats de comparaison des performances
# | npm | fil | pnpm |
---|---|---|---|
Générer un fichier de verrouillage | 60 secondes | 16,5 secondes | 31 secondes |
Installer les dépendances sans aucun cache | 18 secondes | 11 secondes | 8 secondes |
Installer les dépendances avec le cache global | 8 secondes | 8 secondes | 5 secondes |
Selon le benchmark ci-dessus, npm est le gestionnaire de paquets le plus lent ☝️
Quoi qu’il en soit, interprétons ces résultats…
Générer un fichier de verrouillage
C'est un cas rare. Habituellement, un fichier de verrouillage est créé lors de l'initialisation du projet, puis se développe lorsque vous installez/mettez à jour des packages.
Dans cet esprit, il ne semble pas être une chose très importante sur laquelle s'appuyer lorsque vous choisissez un gestionnaire de packages.
Installer les dépendances
Dans la plupart des cas, vos projets conservent une liste spécifique de dépendances et vous ajoutez/supprimez rarement quelque chose.
Très probablement, vous modifierez les versions de vos packages de temps en temps - ces modifications sont minimes et vous réutiliserez le reste des packages du cache.
En d’autres termes, le cas d’utilisation courant est le suivant : récupérer de nouveaux packages dans le registre des packages et récupérer le reste dans le cache.
pnpm (5-8 sec) est presque deux fois plus rapide que npm (8-18 sec) avec du fil (8-11 sec) au milieu.
Conclusion
Faits
- pnpm est en effet un gestionnaire de paquets « rapide et efficace sur le disque » - c'est assez clair dans la revue actuelle !
- La fonctionnalité d'espace de travail pnpm est boguée et certains bogues ne sont pas résolus depuis des années.
- pnpm et Yarn nécessitent une configuration supplémentaire dans les pipelines CI, contrairement à npm .
- pnpm et Yarn ne stockent pas les informations de registre des packages dans leurs fichiers de verrouillage, contrairement à npm .
Pensées de l'auteur
Je pense que pnpm fait le meilleur travail si vos exigences en matière de gestionnaire de paquets sont aussi simples que « installer uniquement les dépendances ».
Même si pnpm n'est pas fourni avec un programme d'installation Node.js prêt à l'emploi, il est facile à configurer dans les pipelines CI avec un corepack ou une action existante .
Je préfère npm , parce que :
- c'est stable (surtout les espaces de travail),
- est livré avec Node.js et ne nécessite pas de configuration supplémentaire dans le pipeline CI,
- stocke les registres de packages dans
package-lock.json
afin que vous puissiez installer des dépendances avec une seule portée à partir de différents registres.
Ces avantages l'emportent sur les secondes de vitesse et d'espace disque que j'économiserais avec fil ou pnpm .
Quels sont vos critères de choix d’un gestionnaire de packages ? Ne soyez pas timide et faites-moi part de vos commentaires dans la section commentaires ci-dessous ! 👇😊