npm ist ein Paketverwaltungstool, das häufig von Front-End-Entwicklern verwendet wird. Im Projekt wird package.json verwendet, um die Konfiguration der npm-Pakete zu verwalten, von denen das Projekt abhängt. package.json ist eine JSON-Datei. Sie beschreibt nicht nur die Paketabhängigkeiten des Projekts, sondern ermöglicht uns auch die Verwendung von „semantischen Versionierungsregeln“, um die Versionen der abhängigen Pakete Ihres Projekts anzugeben, sodass Ihre Builds einfacher mit anderen Entwicklern geteilt werden können wiederverwenden. Dieser Artikel basiert hauptsächlich auf der jüngsten Praxis, kombiniert mit den neuesten npm- und Node-Versionen, um einige gängige Konfigurationen in package.json vorzustellen und zu zeigen, wie eine standardisierte package.json geschrieben wird
In einem NodeJS-Projekt ist Package.json eine Konfigurationsdatei, die seine Abhängigkeiten verwaltet. Wenn wir ein NodeJS-Projekt initialisieren, übergeben wir normalerweise:
npm init
und dann wird 3 generiert Ihr Verzeichnis. Verzeichnisse/Dateien, node_modules, package.json und package.lock.json. Der Inhalt von package.json ist:
{ „name“: „Ihr Projektname“, „Version“: „1.0.0“, „description“: „Ihre Projektbeschreibung“, „main“: „app.js“, "Skripte": { "test": "echo "Fehler: kein Test angegeben" && Exit 1", }, "author": "Name des Autors", „Lizenz“: „ISC“, "Abhängigkeiten": { "dependency1": "^1.4.0", „dependency2“: „^1.5.2“ } }
Wie oben zu sehen ist, enthält package.json die Metadaten des Projekts selbst sowie die Unterabhängigkeitsinformationen des Projekts (z. B. Abhängigkeiten usw.).
Wir haben festgestellt, dass während der npm-Init nicht nur die Datei package.json, sondern auch die Datei package-lock.json generiert wurde. Warum müssen wir also beim Löschen von package.json immer noch die Datei package-lock.json generieren? Im Wesentlichen dient die Datei „package-lock.json“ zum Sperren der Version. Das in package.json angegebene Sub-npm-Paket lautet wie folgt: „^16.0.0“ bei der tatsächlichen Installation, sofern die Version höher ist reagieren, package.json ist erfüllt. Dies bedeutet, dass laut derselben package.json-Datei die Konsistenz der zweimal installierten Unterabhängigkeitsversionen nicht garantiert werden kann.
Die Paketsperrdatei ist wie unten gezeigt, und die Unterabhängigkeit dependency1 gibt ihre Version im Detail an. Spielt die Rolle der Sperrversion.
{ „name“: „Ihr Projektname“, „Version“: „1.0.0“, „lockfileVersion“: 1, „erfordert“: wahr, "Abhängigkeiten": { "Abhängigkeit1": { „Version“: „1.4.0“, "gelöst": „https://registry.npmjs.org/dependency1/-/dependency1-1.4.0.tgz“, "Integrität": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, "Abhängigkeit2": { „Version“: „1.5.2“, "gelöst": „https://registry.npmjs.org/dependency2/-/dependency2-1.5.2.tgz“, "Integrität": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" } } }
In diesem Kapitel werden die häufig verwendeten Konfigurationsattribute in package.json erläutert. Attribute wie Name, Version usw. sind zu einfach und werden nicht einzeln vorgestellt. In diesem Kapitel werden hauptsächlich die Eigenschaften „script“, „bin“ und „workspaces“ vorgestellt.
verwendet das Skript-Tag in npm, um ein Skript zu definieren, wenn npm run angegeben wird. Hierbei ist zu beachten, dass die neue Shell, die von npm run erstellt wird, node_modules/.bin speichert Lokales Verzeichnis. Fügen Sie Unterverzeichnisse zur PATH-Variablen hinzu.
Dies bedeutet, dass alle Skripte im Unterverzeichnis node_modules/.bin des aktuellen Verzeichnisses direkt mit dem Skriptnamen aufgerufen werden können, ohne einen Pfad hinzuzufügen. Wenn beispielsweise die Abhängigkeiten des aktuellen Projekts „esbuild“ umfassen, schreiben Sie einfach „esbuild xxx“ direkt.
{ // ... "Skripte": { „build“: „esbuild index.js“, } }
{ // ... "Skripte": { „build“: „./node_modules/.bin/esbuild index.js“ } }
Die beiden oben genannten Schreibweisen sind gleichwertig.
Das bin-Attribut wird zum Laden ausführbarer Dateien in die globale Umgebung verwendet. Sobald das npm-Paket mit dem bin-Feld angegeben ist, wird es in die globale Umgebung geladen und die Datei kann über einen Alias ausgeführt werden.
Zum Beispiel das npm-Paket von @bytepack/cli:
„bin“: { „bytepack“: „./bin/index.js“ },
Sobald @bytepack/cli global installiert ist, können Sie den entsprechenden Befehl direkt über Bytepack ausführen, z. B.
bytepack -v //Zeige 1.11.0.
Wenn es nicht global installiert ist, wird es automatisch mit dem Verzeichnis node_module/.bin des Projekts verbunden. In Übereinstimmung mit dem, was im zuvor eingeführten Skript-Tag gesagt wurde, kann es direkt mit Aliasen verwendet werden.
Wenn das Projekt zu groß ist, erfreut sich Monorepo in letzter Zeit immer größerer Beliebtheit. Wenn es um Monorepo geht, schauen wir nicht auf Workspaces. Früher haben wir Yarn Workspaces verwendet. Jetzt unterstützt npm offiziell Workspaces, wie man mehrere Unterpakete unter einem Root-Paket verwaltet im lokalen Dateisystem. Im Workspaces-Deklarationsverzeichnis. Das Paket wird mit den node_modules des Root-Pakets der obersten Ebene verknüpft.
Lassen Sie uns dies direkt anhand eines Beispiels von der offiziellen Website veranschaulichen:
{ „name“: „mein-projekt“, „Arbeitsbereiche“: [ „Pakete/a“ ] }
In einem npm-Paket namens my-project gibt es ein von Arbeitsbereichen konfiguriertes Verzeichnis.
. +-- package.json +-- index.js `-- Pakete +-- a |. `-- package.json
und das Root-Paket der obersten Ebene mit dem Namen my-project hat ein Paket/ein Unterpaket. Wenn wir zu diesem Zeitpunkt npm installieren, verweist das in node_modules im Root-Paket installierte npm-Paket a auf das lokale Paket/a
. +-- node_modules |. `-- packets/a -> ../packages/a +-- package-lock.json +-- package.json `-- Pakete +-- a |. `-- package.json
oben --
packets/a -> ../packages/a
bezieht sich auf den Softlink von a in node_modules zum lokalen npm-Paket
Gemeinsame Umgebungen mit package.json-Umgebungsattributen, im Grunde die Das Obige ist in zwei Kategorien unterteilt: Browser- und Knotenumgebung. Schauen wir uns als Nächstes die Konfigurationseigenschaften an, die sich auf die Umgebung in package.json beziehen. Die Definition der Umgebung kann einfach wie folgt verstanden werden:
js umfasst die Module commonjs, CMD, AMD und ES. Ab node13.2.0 unterstützt node jedoch offiziell die Modulspezifikationen Das Feld kann in package.json verwendet werden, um die modulare Spezifikation zu deklarieren, der das npm-Paket folgt.
//package.json { Name: „irgendein Paket“, Typ: „Modul“||„commonjs“ }
Es ist zu beachten, dass
der Standardwert von type „commonjs“ ist. Es wird jedoch empfohlen, dass alle npm-Pakete den Typ „type
“
angeben
Wenn das Feld type angegeben ist, werden alle .js im Verzeichnis verwendet, die mit dem Suffix enden.
Zusätzlich zum Typ, der die Modularisierungsspezifikation angeben kann, wird die von der Datei gefolgte Modularisierungsspezifikation angegeben Das Suffix der Datei ist die verwendete ESModule-Spezifikation. Die Endung .cjs folgt der commonjs-Spezifikation
Zusätzlich zum Typ verfügt package.json über drei Felder: main, module und browser um die Eintragsdatei des npm-Pakets zu definieren.
Schauen wir uns die Verwendungsszenarien dieser drei Felder und die Prioritäten an, wenn diese drei Felder gleichzeitig vorhanden sind. Nehmen wir an, es gibt ein npm-Paket namens demo1,
----- dist |-- index.browser.js |-- index.browser.mjs |-- index.js |-- index.mjs
's package.json spezifiziert gleichzeitig die drei Felder main, module und browser,
"main": "dist/index.js", // main „module“: „dist/index.mjs“, // Modul // Browser kann als Zuordnungsobjekt definiert werden, das dem Haupt-/Modulfeld entspricht, oder er kann direkt als Zeichenfolge „Browser“ definiert werden: { "./dist/index.js": "./dist/index.browser.js", // browser+cjs "./dist/index.mjs": "./dist/index.browser.mjs" // browser+mjs }, // „browser“: „./dist/index.browser.js“ // Der Browser
wird standardmäßig erstellt und verwendet. Wenn wir beispielsweise auf dieses NPM-Paket im Projekt verweisen:
Importieren Sie die Demo aus „Demo“.
Nach dem Erstellen des oben Gesagten Code über das Build-Tool, das Modul Die Ladesequenz ist:
browser+mjs > module > browser+cjs > main
Diese Ladesequenz ist die Standard-Ladesequenz der meisten Build-Tools, wie z. B. webapck, esbuild usw. Diese Ladereihenfolge kann durch entsprechende Konfiguration geändert werden, aber in den meisten Szenarien werden wir weiterhin der Standard-Ladereihenfolge folgen.
Wenn das Exportfeld in package.json definiert ist, ist der in diesem Feld definierte Inhalt der tatsächliche und vollständige Export des npm-Pakets und die Priorität ist höher als die der Haupt- und Dateifelder.
Zum Beispiel:
{ „name“: „pkg“, "Exporte": { ".": "./main.mjs", "./foo": "./foo.js" } }
import { Something } from "pkg"; // from "pkg/main.mjs"
const { Something } = require("pkg/foo"); // require("pkg/foo.js")
aus dem obigen Beispiel Es scheint, dass Exporte Exporte mit unterschiedlichen Pfaden definieren können. Wenn Exporte vorhanden sind, ist das zuvor gültige Dateiverzeichnis überall ungültig, z. B. bei require('pkg/package.json'), da es in Exporten nicht angegeben ist, und es wird ein Fehler gemeldet.
Ein weiteres wichtiges Merkmal von Exporten ist die bedingte Referenz. Beispielsweise können wir npm-Pakete angeben, um auf der Grundlage verschiedener Referenzmethoden oder modularer Typen auf verschiedene Eintragsdateien zu verweisen.
// package.json { „name“: „pkg“, „main“: „./main-require.cjs“, "Exporte": { „import“: „./main-module.js“, „require“: „./main-require.cjs“ }, „Typ“: „Modul“ }
Wenn wir im obigen Beispiel
überconst p = require('pkg')
auf „./main-require.cjs“ verweisen
.Wenn Sie Folgendes übergeben:
import p from 'pkg',
lautet die Referenz „./main-module.js“
. Das Letzte, was Sie beachten sollten: Wenn das Exportattribut vorhanden ist, hat das Exportattribut nicht nur eine höhere Priorität als das Main-Attribut. aber auch höher als die Modul- und Browserfelder.
den abhängigen Konfigurationseigenschaften in package.json gehören Abhängigkeiten, devDependencies, peerDependencies, peerDependenciesMeta usw.
Abhängigkeiten sind Projektabhängigkeiten und devDependencies sind für die Entwicklung erforderliche Module, sodass wir sie bei Bedarf während des Entwicklungsprozesses installieren können, um unsere Entwicklungseffizienz zu verbessern. Hier ist zu beachten, dass Sie versuchen, sie so standardmäßig wie möglich in Ihren eigenen Projekten zu verwenden. Webpack, Babel usw. sind beispielsweise Entwicklungsabhängigkeiten, keine Abhängigkeiten des Projekts selbst.
Abhängigkeiten Zusätzlich zu Abhängigkeiten und devDependencies konzentriert sich dieser Artikel auf peerDependencies und peerDependenciesMeta.
peerDependencies sind Abhängigkeiten in package.json, die das Problem lösen können, dass die Kernbibliothek mehrmals heruntergeladen wird und die Kernbibliotheksversion vereinheitlicht wird.
//Paket/pkg -----node_modules |-- npm-a -> Hängt von React, React-Dom ab |-- npm-b -> Hängt von React, React-Dom ab |-- index.js
Wenn zum Beispiel im obigen Beispiel die Sub-npm-Pakete a und b beide von „react“ und „react-dom“ stammen, dann deklarieren wir PeerDependiciies in der package.json der sub-npm-Pakete a und b, die entsprechenden Abhängigkeiten werden nicht neu installiert.
Es sind zwei Punkte zu beachten:
18 nicht
„peerDependencies“: { „reagieren“: „^16.8.3 || ^17 || ^18“ }, „peerDependenciesMeta“: { „react-dom“: { „optional“: wahr }, „react-native“: { „optional“: wahr } }
„react-dom“ und „react-native“ werden hier in peerDependenciesMeta angegeben und sind optional. Wenn also „react-dom“ und „react-native“ nicht im Projekt installiert sind, wird kein Fehler gemeldet.
Es ist erwähnenswert, dass wir die Einschränkung tatsächlich durch peerDependenciesMeta aufgehoben haben, aber es gibt oft Szenarien, in denen es entweder A oder B ist. Im obigen Beispiel benötigen wir beispielsweise „react-dom“ und „react-native“. und wir müssen eine installieren, aber tatsächlich können wir diese Eingabeaufforderung nicht durch die obige Anweisung erreichen.
In package.json gibt es auch viele Dreiparteienattribute, z. B. die in tsc verwendeten Typen, die in Build-Tools verwendeten SideEffects, die in Git verwendeten Huskys und die in Eslint verwendeten eslintIgnore-Konfigurationen Erweiterungen sind für bestimmte Entwicklungstools von Bedeutung und ich werde hier keine Beispiele nennen.