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 !
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.
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 :
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…
Ça a prispackage-lock.json
et installe les dépendances sans aucun cache.
Commande utilisée :
npm i
Ça a prispackage-lock.json
sans aucun cache.
Commande utilisée :
npm ci
Ça a prispackage-lock.json
avec le cache global.
Commande utilisée :
npm ci
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 :
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.
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 fichiers yarn.lock
et .pnp.cjs
.
Un standard - similaire à npm , stocke les dépendances dans node_modules
et les répertorie dans le fichier yarn.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.
Ça a prisyarn.lock
et installe les dépendances sans cache.
Commande utilisée :
yarn install
Ça a pris
Commande utilisée :
yarn install --frozen-lockfile
Ça a pris
Commande utilisée :
yarn install --frozen-lockfile
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 :
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 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.
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.
Ça a prispnpm-lock.yaml
et installe les dépendances sans aucun cache.
Commande utilisée :
pnpm install
Ça a prispnpm-lock.yaml
sans cache.
Commande utilisée :
pnpm i --frozen-lockfile
Ça a prispnpm-lock.yaml
avec le cache global.
Commande utilisée :
pnpm i --frozen-lockfile
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 :
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 :
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.
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 .
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
et tsc --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
.
# | 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…
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.
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.
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 :
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 ! 👇😊