npm est un outil de gestion de packages largement utilisé par les développeurs front-end. Dans le projet, package.json est utilisé pour gérer la configuration des packages npm dont dépend le projet. package.json est un fichier json. En plus de décrire les dépendances des packages du projet, il nous permet également d'utiliser des « règles de version sémantique » pour indiquer les versions des packages dépendants de votre projet, permettant ainsi de mieux partager vos builds avec d'autres développeurs. réutiliser. Cet article part principalement de la pratique récente, combinée aux dernières versions de npm et de node, pour présenter certaines configurations courantes dans package.json et comment écrire un package.json standardisé.
Dans un projet nodejs, package.json est un fichier de configuration qui gère ses dépendances. Habituellement lorsque nous initialisons un projet nodejs, nous passerons :
npm init
puis 3 seront générés dans. votre répertoire. répertoires/fichiers, node_modules, package.json et package.lock.json. Le contenu de package.json est :
{ "name": "Nom de votre projet", "version": "1.0.0", "description": "Description de votre projet", "main": "app.js", "scripts": { "test": "echo "Erreur : aucun test spécifié" && exit 1", }, "author": "Nom de l'auteur", "licence": "ISC", "dépendances": { "dépendance1": "^1.4.0", "dépendance2": "^1.5.2" } }
Comme le montre ce qui précède, package.json contient les métadonnées du projet lui-même, ainsi que les informations sur les sous-dépendances du projet (telles que les dépendances, etc.).
Nous avons constaté que lors de l'initialisation de npm, non seulement le fichier package.json était généré, mais également le fichier package-lock.json. Alors pourquoi devons-nous encore générer le fichier package-lock.json lors de la suppression de package.json ? Essentiellement, le fichier package-lock.json sert à verrouiller la version. Le package sous-npm spécifié dans package.json est tel que : react: "^16.0.0". réagissez, package.json est satisfait des exigences. Cela signifie que selon le même fichier package.json, la cohérence des versions de sous-dépendances installées deux fois ne peut pas être garantie.
Le fichier package-lock est tel qu'indiqué ci-dessous et la sous-dépendance dependency1 spécifie sa version en détail. Joue le rôle de version de verrouillage.
{ "name": "Nom de votre projet", "version": "1.0.0", "lockfileVersion": 1, "exige": vrai, "dépendances": { "dépendance1": { "version": "1.4.0", "résolu": "https://registry.npmjs.org/dependency1/-/dependency1-1.4.0.tgz", "intégrité": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, "dépendance2": { "version": "1.5.2", "résolu": "https://registry.npmjs.org/dependency2/-/dependency2-1.5.2.tgz", "intégrité": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" } } }
Ce chapitre parlera des attributs de configuration couramment utilisés dans package.json. Les attributs tels que le nom, la version, etc. sont trop simples et ne seront pas présentés un par un. Ce chapitre présente principalement les propriétés du script, du bin et des espaces de travail.
utilise la balise script dans npm pour définir un script Chaque fois que npm run est spécifié, un script shell sera automatiquement créé. Ce qui doit être noté ici, c'est que le nouveau shell créé par npm run stockera node_modules/.bin dans le fichier. répertoire local. Ajoutez des sous-répertoires à la variable PATH.
Cela signifie que tous les scripts du sous-répertoire node_modules/.bin du répertoire actuel peuvent être appelés directement avec le nom du script sans ajouter de chemin. Par exemple, si les dépendances du projet actuel incluent esbuild, écrivez simplement esbuild xxx directement.
{ //... "scripts": { "build": "esbuild index.js", } }
{ //... "scripts": { "build": "./node_modules/.bin/esbuild index.js" } }
Les deux manières d'écrire ci-dessus sont équivalentes.
L'attribut bin est utilisé pour charger des fichiers exécutables dans l'environnement global Une fois le package npm avec le champ bin spécifié, il sera chargé dans l'environnement global et le fichier pourra être exécuté via un alias.
Par exemple, le package npm de @bytepack/cli :
"bin": { "bytepack": "./bin/index.js" },
Une fois @bytepack/cli installé globalement, vous pouvez directement exécuter la commande correspondante via bytepack, telle que
bytepack -v //Afficher 1.11.0.
S'il n'est pas installé globalement, il sera automatiquement connecté au répertoire node_module/.bin du projet. Conformément à ce qui a été dit dans la balise script introduite précédemment, elle peut être utilisée directement avec des alias.
Lorsque le projet est trop volumineux, le monorepo est devenu de plus en plus populaire ces derniers temps. En ce qui concerne le monorepo, nous ne regardons pas les espaces de travail. Au début, nous utilisions les espaces de travail Yarn. Désormais, NPM prend officiellement en charge les espaces de travail et résout le problème de la gestion de plusieurs sous-packages sous un package racine de niveau supérieur. dans le système de fichiers local. Dans le répertoire de déclaration des espaces de travail. Le package sera lié aux node_modules du package racine de niveau supérieur.
Illustrons directement avec un exemple tiré du site officiel :
{ "name": "mon-projet", "espaces de travail": [ "paquets/un" ] }
Dans un package npm nommé my-project, il existe un répertoire configuré par les espaces de travail.
. +-- package.json +-- index.js `-- paquets +-- un | `-- package.json
et le package racine de niveau supérieur nommé my-project ont un packages/un sous-package. À ce stade, si nous installons npm, alors le package npm a installé dans node_modules dans le package racine pointe vers le package local/a
. +-- node_modules `-- packages/a -> ../packages/a +-- package-lock.json +-- package.json `-- paquets +-- un | `-- package.json
ci-dessus--
packages/a -> ../packages/a
fait référence au lien logiciel de a dans node_modules vers le package npm local
Environnements communs avec les attributs liés à l'environnement package.json, essentiellement Le ci-dessus est divisé en deux catégories : navigateur et environnement de nœud. Examinons ensuite les propriétés de configuration liées à l'environnement dans package.json. La définition de l'environnement peut être simplement comprise comme suit :
js inclut les modules commonjs, CMD, UMD, AMD et ES. Au début, seul le champ commonjs était pris en charge dans le nœud. Cependant, à partir de node13.2.0, le nœud prend officiellement en charge la spécification du module ES. Le champ peut être utilisé dans package.json pour déclarer la spécification modulaire suivie par le package npm.
//paquet.json { nom : "un paquet", tapez : "module"||"commonjs" }
Il convient de noter que
lorsque le type n'est pas spécifié, la valeur par défaut de type est commonjs. Cependant, il est recommandé que tous les packages npm spécifient le type
lorsque le champ type spécifie la valeur en tant que module, la spécification ESModule est utilisée
. Le champ type est spécifié, tous les .js du répertoire seront utilisés. Les fichiers se terminant par le suffixe suivent la spécification de modularisation spécifiée par type.
En plus du type, qui peut spécifier la spécification de modularisation, la spécification de modularisation suivie du fichier est spécifiée via. le suffixe du fichier. Les fichiers se terminant par .mjs sont les spécifications ESModule utilisées. La terminaison .cjs suit la spécification commonjs
En plus du type, package.json comporte également trois champs : principal, module et navigateur. pour définir le fichier d'entrée du package npm.
un coup d'œil aux scénarios d'utilisation de ces trois champs et aux priorités lorsque ces trois champs existent en même temps. Supposons qu'il existe un package npm appelé demo1,
----- dist |-- index.browser.js |-- index.browser.mjs |-- index.js |--
Le package.json de index.mjs spécifie les trois champs main, module et navigateur en même temps,
"main": "dist/index.js", // main "module": "dist/index.mjs", // module // le navigateur peut être défini comme un objet de mappage correspondant au champ main/module, ou il peut être directement défini comme la chaîne "browser": { "./dist/index.js": "./dist/index.browser.js", // navigateur+cjs "./dist/index.mjs": "./dist/index.browser.mjs" // navigateur+mjs }, // "browser": "./dist/index.browser.js" // Le navigateur
est construit et utilisé par défaut. Par exemple, si nous référençons ce package npm dans le projet :
importer la démo depuis 'demo'
Après avoir construit ce qui précède. code via l'outil de construction, le module La séquence de chargement est :
navigateur+mjs > module > navigateur+cjs > main
Cette séquence de chargement est la séquence de chargement par défaut de la plupart des outils de construction, tels que webapck, esbuild, etc. Cet ordre de chargement peut être modifié via la configuration correspondante, mais dans la plupart des scénarios, nous suivrons toujours l'ordre de chargement par défaut.
Si le champ exports est défini dans package.json, alors le contenu défini dans ce champ est l'exportation réelle et complète du package npm, et la priorité sera supérieure aux champs main et file.
Par exemple:
{ "name": "paquet", "exportations": { ".": "./main.mjs", "./foo": "./foo.js" } }
import {quelque chose } from "pkg"; // depuis "pkg/main.mjs"
const {quelque chose } = require("pkg/foo"); // require("pkg/foo.js")
à partir de l'exemple ci-dessus Il semble que les exportations puissent définir des exportations avec des chemins différents. Si des exportations existent, le répertoire de fichiers précédemment valide sera invalide partout, comme require('pkg/package.json'), car il n'est pas spécifié dans les exportations, et une erreur sera signalée.
Une autre fonctionnalité importante des exportations est la référence conditionnelle. Par exemple, nous pouvons spécifier des packages npm pour référencer différents fichiers d'entrée en fonction de différentes méthodes de référence ou types modulaires.
// package.json { "nom": "pkg", "main": "./main-require.cjs", "exportations": { "import": "./main-module.js", "require": "./main-require.cjs" }, "type": "module" }
Dans l'exemple ci-dessus, si nous
faisons référence à "./main-require.cjs"
viaconst p = require('pkg').
Si vous transmettez :
import p from 'pkg',
la référence est "./main-module.js"
. La dernière chose à noter est : si l'attribut exports existe, l'attribut exports aura non seulement une priorité plus élevée que main, mais aussi plus élevé que les champs du module et du navigateur.
Les propriétés de configuration liées aux dépendances dans package.json incluent les dépendances, devDependencies, peerDependencies, peerDependenciesMeta, etc.
Les dépendances sont des dépendances de projet et les devDependencies sont des modules requis pour le développement, nous pouvons donc les installer selon nos besoins pendant le processus de développement pour améliorer notre efficacité de développement. Ce qu'il faut noter ici, c'est d'essayer de les utiliser de la manière la plus standard possible dans vos propres projets. Par exemple, webpack, babel, etc. sont des dépendances de développement, pas des dépendances du projet lui-même.
dépendances En plus des dépendances et devDependencies, cet article se concentre sur peerDependencies et peerDependenciesMeta.
Les peerDependencies sont des dépendances dans package.json, qui peuvent résoudre le problème du téléchargement multiple de la bibliothèque principale et unifier la version de la bibliothèque principale.
//paquet/pqt -----node_modules |-- npm-a -> Dépend de réagir, réagir-dom |-- npm-b -> Dépend de réagir, réagir-dom |-- index.js
Par exemple, dans l'exemple ci-dessus, si les packages sous-npm a et b proviennent tous deux de réagir et réagir-dom, alors si nous déclarons PeerDependicies dans le package.json des packages sous-npm a et b, les dépendances correspondantes ne seront pas réinstallées.
Il y a deux points à noter :
18
"peerDependencies": {. "réagir": "^16.8.3 || ^17 || ^18" }, "peerDependenciesMeta": { "réagir-dom": { "facultatif" : vrai }, "réagir natif": { "facultatif" : vrai } }
"react-dom" et "react-native" sont spécifiés ici dans peerDependenciesMeta et sont facultatifs, donc si "react-dom" et "react-native" ne sont pas installés dans le projet, aucune erreur ne sera signalée.
Il convient de noter que nous avons effectivement levé la restriction via peerDependenciesMeta, mais il existe souvent des scénarios où elle est soit A, soit B. Par exemple, dans l'exemple ci-dessus, nous avons besoin de "react-dom" et "react-native". et nous devons en installer un, mais en fait, nous ne pouvons pas obtenir cette invite via l'instruction ci-dessus.
Il existe également de nombreux attributs tiers dans package.json, tels que les types utilisés dans tsc, sideEffects utilisés dans les outils de construction, husky utilisé dans git et eslintIgnore utilisé dans eslint La configuration de ceux-ci. les extensions sont destinées à des outils de développement spécifiques et sont significatives et je ne donnerai pas d'exemples ici.