npm install ausgeführt werdenpackage.json hat die Eigenschaft "scripts", mit der wir Paket-Skripte definieren können, kleine Shell-Skripte, die Paket-bezogene Aufgaben wie das Kompilieren von Artefakten oder das Ausführen von Tests durchführen. Dieses Kapitel erklärt sie und wie wir sie so schreiben können, dass sie sowohl unter Windows als auch unter Unix (macOS, Linux usw.) funktionieren.
npm-Paket-Skripte werden über die Eigenschaft "scripts" von package.json definiert.
{
···
"scripts": {
"tsc": "tsc",
"tscwatch": "tsc --watch",
"tscclean": "shx rm -rf ./dist/*"
},
···
}Der Wert von "scripts" ist ein Objekt, bei dem jede Eigenschaft ein Paket-Skript definiert.
Wenn wir eingeben
npm run <script-name>
dann führt npm das Skript mit dem Namen script-name in einer Shell aus. Zum Beispiel können wir verwenden
npm run tscwatch
um den folgenden Befehl in einer Shell auszuführen
tsc --watch
In diesem Kapitel werden wir gelegentlich die npm-Option -s verwenden, die eine Abkürzung für --silent ist und npm run anweist, weniger Ausgabe zu erzeugen.
npm -s run <script-name>
Diese Option wird im Abschnitt über die Protokollierung ausführlicher behandelt (siehe Abschnitt über die Protokollierung).
Einige Paket-Skripte können über kürzere npm-Befehle ausgeführt werden.
| Befehle | Äquivalent |
|---|---|
npm test, npm t |
npm run test |
npm start |
npm run start |
npm stop |
npm run stop |
npm restart |
npm run restart |
npm start: Wenn kein Paket-Skript "start" vorhanden ist, führt npm node server.js aus.npm restart: Wenn kein Paket-Skript "restart" vorhanden ist, führt npm "prerestart", "stop", "start", "postrestart" aus.Standardmäßig führt npm Paket-Skripte unter Windows über cmd.exe und unter Unix über /bin/sh aus. Dies kann über die npm-Konfigurationseinstellung script-shell geändert werden.
Dies ist jedoch selten eine gute Idee: Viele bestehende plattformübergreifende Skripte sind für sh und cmd.exe geschrieben und würden dann nicht mehr funktionieren.
Einige Skriptnamen sind für Lebenszyklus-Skripte reserviert, die npm ausführt, wann immer wir bestimmte npm-Befehle ausführen.
Zum Beispiel führt npm das Skript "postinstall" aus, wenn wir npm install (ohne Argumente) ausführen. Lebenszyklus-Skripte werden später ausführlicher behandelt.
Wenn die Konfigurationseinstellung ignore-scripts auf true gesetzt ist, führt npm niemals Skripte automatisch aus, sondern nur, wenn wir sie direkt aufrufen.
Unter Unix unterstützt npm die Tab-Vervollständigung für Befehle und Paket-Skriptnamen über npm completion. Wir können sie installieren, indem wir diese Zeile zu unserer .profile / .zprofile / .bash_profile / etc. hinzufügen.
. <(npm completion)Wenn Sie Tab-Vervollständigung für Nicht-Unix-Plattformen benötigen, suchen Sie im Web nach z. B. „npm tab completion PowerShell“.
npm run ohne Namen listet die verfügbaren Skripte auf. Wenn die folgenden Skripte vorhanden sind
"scripts": {
"tsc": "tsc",
"tscwatch": "tsc --watch",
"serve": "serve ./site/"
}Dann werden sie wie folgt aufgelistet
% npm run
Scripts available via `npm run-script`:
tsc
tsc
tscwatch
tsc --watch
serve
serve ./site/
Wenn es viele Paket-Skripte gibt, können wir Skriptnamen als Trennzeichen missbrauchen (das Skript "help" wird im nächsten Unterabschnitt erklärt)
"scripts": {
"help": "scripts-help -w 40",
"\n========== Building ==========": "",
"tsc": "tsc",
"tscwatch": "tsc --watch",
"\n========== Serving ==========": "",
"serve": "serve ./site/"
},Jetzt werden die Skripte wie folgt aufgelistet
% npm run
Scripts available via `npm run-script`:
help
scripts-help -w 40
========== Building ==========
tsc
tsc
tscwatch
tsc --watch
========== Serving ==========
serve
serve ./site/
Beachten Sie, dass der Trick, neue Zeilen (\n) voranzustellen, unter Unix und unter Windows funktioniert.
Das Paket-Skript "help" gibt Hilfeinformationen über das Bin-Skript scripts-help aus dem Paket @rauschma/scripts-help aus. Wir stellen Beschreibungen über die package.json-Eigenschaft "scripts-help" bereit (der Wert von "tscwatch" ist abgekürzt, damit er auf eine einzige Zeile passt)
"scripts-help": {
"tsc": "Compile the TypeScript to JavaScript.",
"tscwatch": "Watch the TypeScript source code [...]",
"serve": "Serve the generated website via a local server."
}So sehen die Hilfeinformationen aus
% npm -s run help
Package “demo”
╔══════╤══════════════════════════╗
║ help │ scripts-help -w 40 ║
╚══════╧══════════════════════════╝
Building
╔══════════╤══════════════════════════════════════════╗
║ tsc │ Compile the TypeScript to JavaScript. ║
╟──────────┼──────────────────────────────────────────╢
║ tscwatch │ Watch the TypeScript source code and ║
║ │ compile it incrementally when and if ║
║ │ there are changes. ║
╚══════════╧══════════════════════════════════════════╝
Serving
╔═══════╤══════════════════════════════════════════╗
║ serve │ Serve the generated website via a local ║
║ │ server. ║
╚═══════╧══════════════════════════════════════════╝
Wenn bestimmte Namen für Skripte verwendet werden, werden diese in einigen Situationen automatisch ausgeführt.
npm install durchführt.Alle anderen Skripte werden als direkt ausgeführte Skripte bezeichnet.
Immer wenn npm ein Paket-Skript PS ausführt, führt es automatisch die folgenden Skripte aus – falls vorhanden
prePS vorher (ein Pre-Skript)postPS danach (ein Post-Skript)Die folgenden Skripte enthalten das Pre-Skript prehello und das Post-Skript posthello.
"scripts": {
"hello": "echo hello",
"prehello": "echo BEFORE",
"posthello": "echo AFTER"
},Dies geschieht, wenn wir hello ausführen.
% npm -s run hello
BEFORE
hello
AFTER
npm führt Lebenszyklus-Skripte während npm-Befehlen wie diesen aus:
npm publish (lädt Pakete in das npm-Repository hoch)npm pack (erstellt Archive für Repository-Pakete, Paketverzeichnisse usw.)npm install (wird ohne Argumente verwendet, um Abhängigkeiten für Pakete zu installieren, die von anderen Quellen als dem npm-Repository heruntergeladen wurden)Wenn eines der Lebenszyklus-Skripte fehlschlägt, stoppt der gesamte Befehl sofort mit einem Fehler.
Was sind Anwendungsfälle für Lebenszyklus-Skripte?
TypeScript kompilieren: Wenn ein Paket TypeScript-Code enthält, kompilieren wir es normalerweise in JavaScript-Code, bevor wir es verwenden. Während der letztere Code oft nicht in die Versionskontrolle eingecheckt wird, muss er in das npm-Repository hochgeladen werden, damit das Paket aus JavaScript verwendet werden kann. Ein Lebenszyklus-Skript ermöglicht es uns, den TypeScript-Code zu kompilieren, bevor npm publish das Paket hochlädt. Das stellt sicher, dass im npm-Repository der JavaScript-Code immer mit unserem TypeScript-Code synchron ist. Es stellt auch sicher, dass unser TypeScript-Code keine statischen Typfehler aufweist, da die Kompilierung (und damit die Veröffentlichung) stoppt, wenn diese auftreten.
Tests ausführen: Wir können auch ein Lebenszyklus-Skript verwenden, um Tests auszuführen, bevor ein Paket veröffentlicht wird. Wenn die Tests fehlschlagen, wird das Paket nicht veröffentlicht.
Dies sind die wichtigsten Lebenszyklus-Skripte (für detaillierte Informationen zu allen Lebenszyklus-Skripten siehe die npm-Dokumentation)
"prepare":
.tgz-Datei) erstellt wirdnpm publishnpm packnpm install ohne Argumente verwendet wird oder wenn ein Paket global installiert wird."prepack" wird ausgeführt, bevor ein Paketarchiv (eine .tgz-Datei) erstellt wird.npm publishnpm pack"prepublishOnly" wird nur während npm publish ausgeführt."install" wird ausgeführt, wenn npm install ohne Argumente verwendet wird oder wenn ein Paket global installiert wird."preinstall" und/oder ein Post-Skript "postinstall" erstellen können. Ihre Namen machen deutlicher, wann npm sie ausführt.Die folgende Tabelle fasst zusammen, wann diese Lebenszyklus-Skripte ausgeführt werden:
prepublishOnly |
prepack |
prepare |
install |
|
|---|---|---|---|---|
npm publish |
✔ |
✔ |
✔ |
|
npm pack |
✔ |
✔ |
||
npm install |
✔ |
✔ |
||
| globale Installation | ✔ |
✔ |
||
| Installation über git, Pfad | ✔ |
Vorsicht: Automatische Ausführung ist immer etwas knifflig. Ich befolge normalerweise diese Regeln:
prepublishOnly).postinstall).In diesem Abschnitt werden wir gelegentlich verwenden:
node -p <expr>
was den JavaScript-Code in expr ausführt und das Ergebnis auf dem Terminal ausgibt – zum Beispiel:
% node -p "'hello everyone!'.toUpperCase()"
HELLO EVERYONE!
Wenn ein Paket-Skript ausgeführt wird, ist das aktuelle Verzeichnis immer das Paketverzeichnis, unabhängig davon, wo wir uns im Verzeichnisbaum befinden, dessen Wurzel es ist. Dies können wir bestätigen, indem wir das folgende Skript zu package.json hinzufügen:
"cwd": "node -p \"process.cwd()\""Versuchen wir cwd unter Unix:
% cd /Users/robin/new-package/src/util
% npm -s run cwd
/Users/robin/new-package
Das Ändern des aktuellen Verzeichnisses auf diese Weise hilft beim Schreiben von Paket-Skripten, da wir Pfade verwenden können, die relativ zum Paketverzeichnis sind.
Wenn ein Modul M aus einem Modul importiert, dessen Spezifizierer mit dem Namen eines Pakets P beginnt, durchsucht Node.js node_modules-Verzeichnisse, bis es das Verzeichnis von P findet.
node_modules im übergeordneten Verzeichnis von M (falls vorhanden).node_modules im Elternteil des Elternverzeichnisses von M (falls vorhanden).Das bedeutet, dass M die node_modules-Verzeichnisse seiner Vorfahren erbt.
Eine ähnliche Art von Vererbung tritt bei Bin-Skripten auf, die in node_modules/.bin gespeichert werden, wenn wir ein Paket installieren. npm run fügt dem Shell-PATH-Variablen ($PATH unter Unix, %Path% unter Windows) temporär Einträge hinzu.
node_modules/.bin im Paketverzeichnis.node_modules/.bin im übergeordneten Verzeichnis des Pakets.Um diese Ergänzungen zu sehen, können wir das folgende Paket-Skript verwenden:
"bin-dirs": "node -p \"JS\""JS steht für eine einzelne Zeile mit diesem JavaScript-Code:
(process.env.PATH ?? process.env.Path)
.split(path.delimiter)
.filter(p => p.includes('.bin'))Unter Unix erhalten wir die folgende Ausgabe, wenn wir bin-dirs ausführen:
% npm -s run bin-dirs
[
'/Users/robin/new-package/node_modules/.bin',
'/Users/robin/node_modules/.bin',
'/Users/node_modules/.bin',
'/node_modules/.bin'
]
Unter Windows erhalten wir:
>npm -s run bin-dirs
[
'C:\\Users\\charlie\\new-package\\node_modules\\.bin',
'C:\\Users\\charlie\\node_modules\\.bin',
'C:\\Users\\node_modules\\.bin',
'C:\\node_modules\\.bin'
]
In Task-Runnern wie Make, Grunt und Gulp sind Variablen wichtig, da sie helfen, Redundanz zu reduzieren. Leider haben Paket-Skripte keine eigenen Variablen, aber wir können diese Einschränkung umgehen, indem wir Umgebungsvariablen (die auch Shell-Variablen genannt werden) verwenden.
Wir können die folgenden Befehle verwenden, um plattformspezifische Umgebungsvariablen aufzulisten:
envSETnode -p process.envUnter macOS sieht das Ergebnis wie folgt aus:
TERM_PROGRAM=Apple_Terminal
SHELL=/bin/zsh
TMPDIR=/var/folders/ph/sz0384m11vxf5byk12fzjms40000gn/T/
USER=robin
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PWD=/Users/robin/new-package
HOME=/Users/robin
LOGNAME=robin
···
In der Windows-Kommandozeile sieht das Ergebnis wie folgt aus:
Path=C:\Windows;C:\Users\charlie\AppData\Roaming\npm;···
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROMPT=$P$G
TEMP=C:\Users\charlie\AppData\Local\Temp
TMP=C:\Users\charlie\AppData\Local\Temp
USERNAME=charlie
USERPROFILE=C:\Users\charlie
···
Zusätzlich fügt npm vor dem Ausführen eines Paket-Skripts temporär weitere Umgebungsvariablen hinzu. Um zu sehen, wie das Endergebnis aussieht, können wir den folgenden Befehl verwenden:
npm run env
Dieser Befehl ruft ein integriertes Paket-Skript auf. Probieren wir es für diese package.json aus:
{
"name": "@my-scope/new-package",
"version": "1.0.0",
"bin": {
"hello": "./hello.mjs"
},
"config": {
"stringProp": "yes",
"arrayProp": ["a", "b", "c"],
"objectProp": {
"one": 1,
"two": 2
}
}
}Die Namen aller temporären npm-Variablen beginnen mit npm_. Lassen Sie uns nur diese in alphabetischer Reihenfolge ausgeben:
npm run env | grep npm_ | sort
Die npm_-Variablen haben eine hierarchische Struktur. Unter npm_lifecycle_ finden wir den Namen und die Definition des aktuell ausgeführten Paket-Skripts.
npm_lifecycle_event: 'env',
npm_lifecycle_script: 'env',Unter Windows würde npm_lifecycle_script in diesem Fall SET lauten.
Unter dem Präfix npm_config_ können wir einige der npm-Konfigurationseinstellungen sehen (die in der npm-Dokumentation beschrieben sind). Hier einige Beispiele:
npm_config_cache: '/Users/robin/.npm',
npm_config_global_prefix: '/usr/local',
npm_config_globalconfig: '/usr/local/etc/npmrc',
npm_config_local_prefix: '/Users/robin/new-package',
npm_config_prefix: '/usr/local'
npm_config_user_agent: 'npm/8.15.0 node/v18.7.0 darwin arm64 workspaces/false',
npm_config_userconfig: '/Users/robin/.npmrc',
Das Präfix npm_package_ gibt uns Zugriff auf den Inhalt von package.json. Seine oberste Ebene sieht so aus:
npm_package_json: '/Users/robin/new-package/package.json',
npm_package_name: '@my-scope/new-package',
npm_package_version: '1.0.0',
Unter npm_package_bin_ finden wir die Eigenschaften der package.json-Eigenschaft "bin".
npm_package_bin_hello: 'hello.mjs',
Die Einträge npm_package_config_ geben uns Zugriff auf die Eigenschaften von "config".
npm_package_config_arrayProp: 'a\n\nb\n\nc',
npm_package_config_objectProp_one: '1',
npm_package_config_objectProp_two: '2',
npm_package_config_stringProp: 'yes',
Das bedeutet, dass "config" uns erlaubt, Variablen einzurichten, die wir in Paket-Skripten verwenden können. Der nächste Unterabschnitt befasst sich damit genauer.
Beachten Sie, dass das Objekt in „verschachtelte“ Einträge umgewandelt wurde (Zeile 2 und Zeile 3), während das Array (Zeile 1) und die Zahlen (Zeile 2 und Zeile 3) in Zeichenfolgen umgewandelt wurden.
Dies sind die verbleibenden npm_-Umgebungsvariablen:
npm_command: 'run-script',
npm_execpath: '/usr/local/lib/node_modules/npm/bin/npm-cli.js',
npm_node_execpath: '/usr/local/bin/node',
Die folgende package.json demonstriert, wie wir Variablen abrufen können, die über "config" in Paket-Skripten definiert wurden:
{
"scripts": {
"hi:unix": "echo $npm_package_config_hi",
"hi:windows": "echo %npm_package_config_hi%"
},
"config": {
"hi": "HELLO"
}
}Leider gibt es keine integrierte plattformübergreifende Methode, um von Paket-Skripten aus auf Umgebungsvariablen zuzugreifen.
Es gibt jedoch Pakete mit Bin-Skripten, die uns helfen können.
Das Paket env-var ermöglicht es uns, Umgebungsvariablen abzurufen.
"scripts": {
"hi": "env-var echo {{npm_package_config_hi}}"
}Das Paket cross-env ermöglicht es uns, Umgebungsvariablen zu setzen.
"scripts": {
"build": "cross-env FIRST=one SECOND=two node ./build.mjs"
}.env-Dateien einrichtenEs gibt auch Pakete, die es uns ermöglichen, Umgebungsvariablen über .env-Dateien einzurichten. Diese Dateien haben das folgende Format:
# Comment
SECRET_HOST="https://example.com"
SECRET_KEY="123456789" # another comment
Die Verwendung einer Datei, die von package.json getrennt ist, ermöglicht es uns, diese Daten aus der Versionskontrolle herauszuhalten.
Dies sind Pakete, die .env-Dateien unterstützen:
Das Paket dotenv unterstützt sie für JavaScript-Module. Wir können es vorladen:
node -r dotenv/config app.mjs
Und wir können es importieren:
import dotenv from 'dotenv';
dotenv.config();
console.log(process.env);Das Paket node-env-run ermöglicht es uns, .env-Dateien über einen Shell-Befehl zu verwenden.
# Loads `.env` and runs an arbitrary shell script.
# If there are CLI options, we need to use `--`.
nodenv --exec node -- -p process.env.SECRET
# Loads `.env` and uses `node` to run `script.mjs`.
nodenv script.mjsDas Paket env-cmd ist eine Alternative zum vorherigen Paket.
# Loads `.env` and runs an arbitrary shell script
env-cmd node -p process.env.SECRET
Das Paket hat weitere Funktionen: Umschalten zwischen variablen Sätzen, mehr Dateiformate usw.
Lassen Sie uns untersuchen, wie Argumente an Shell-Befehle übergeben werden, die wir über Paket-Skripte aufrufen. Wir verwenden die folgende package.json:
{
···
"scripts": {
"args": "log-args"
},
"dependencies": {
"log-args": "^1.0.0"
}
}Das Bin-Skript log-args sieht wie folgt aus:
for (const [key,value] of Object.entries(process.env)) {
if (key.startsWith('npm_config_arg')) {
console.log(`${key}=${JSON.stringify(value)}`);
}
}
console.log(process.argv.slice(2));Positionsargumente funktionieren wie erwartet.
% npm -s run args three positional arguments
[ 'three', 'positional', 'arguments' ]
npm run verbraucht Optionen und erstellt Umgebungsvariablen für sie. Sie werden nicht zu process.argv hinzugefügt.
% npm -s run args --arg1='first arg' --arg2='second arg'
npm_config_arg2="second arg"
npm_config_arg1="first arg"
[]
Wenn wir möchten, dass Optionen in process.argv erscheinen, müssen wir den Optionsbegrenzer -- verwenden. Dieser Begrenzer wird normalerweise nach dem Namen des Paket-Skripts eingefügt.
% npm -s run args -- --arg1='first arg' --arg2='second arg'
[ '--arg1=first arg', '--arg2=second arg' ]
Aber wir können ihn auch vor diesem Namen einfügen.
% npm -s run -- args --arg1='first arg' --arg2='second arg'
[ '--arg1=first arg', '--arg2=second arg' ]
npm unterstützt die folgenden Protokollierungspegel:
| Protokollierungspegel | npm-Option |
Aliase |
|---|---|---|
| silent | --loglevel silent |
-s --silent |
| error | --loglevel error |
|
| warn | --loglevel warn |
-q --quiet |
| notice | --loglevel notice |
|
| http | --loglevel http |
|
| timing | --loglevel timing |
|
| info | --loglevel info |
-d |
| verbose | --loglevel verbose |
-dd --verbose |
| silly | --loglevel silly |
-ddd |
Protokollierung bezieht sich auf zwei Arten von Aktivitäten:
Die folgenden Unterabschnitte beschreiben:
Wie Protokollierungspegel diese Aktivitäten beeinflussen. Grundsätzlich protokolliert silent am wenigsten, während silly am meisten protokolliert.
Wie die Protokollierung konfiguriert wird. Die vorherige Tabelle zeigt, wie der Protokollierungspegel vorübergehend über Befehlszeilenoptionen geändert werden kann, aber es gibt weitere Einstellungen. Und wir können sie entweder vorübergehend oder dauerhaft ändern.
Standardmäßig sind Paket-Skripte relativ gesprächig, was die Terminalausgabe angeht. Nehmen wir zum Beispiel die folgende package.json-Datei:
{
"name": "@my-scope/new-package",
"version": "1.0.0",
"scripts": {
"hello": "echo Hello",
"err": "more does-not-exist.txt"
},
···
}Dies geschieht, wenn der Protokollierungspegel höher als silent ist und das Paket-Skript ohne Fehler beendet wird:
% npm run hello
> @my-scope/new-package@1.0.0 hello
> echo Hello
Hello
Dies geschieht, wenn der Protokollierungspegel höher als silent ist und das Paket-Skript fehlschlägt:
% npm run err
> @my-scope/new-package@1.0.0 err
> more does-not-exist.txt
does-not-exist.txt: No such file or directory
Mit dem Protokollierungspegel silent wird die Ausgabe weniger überladen:
% npm -s run hello
Hello
% npm -s run err
does-not-exist.txt: No such file or directory
Einige Fehler werden von -s verschluckt.
% npm -s run abc
%
Wir benötigen mindestens den Protokollierungspegel error, um sie zu sehen.
% npm --loglevel error run abc
npm ERR! Missing script: "abc"
npm ERR!
npm ERR! To see a list of scripts, run:
npm ERR! npm run
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/robin/.npm/_logs/2072-08-30T14_59_40_474Z-debug-0.log
Leider unterdrückt der Protokollierungspegel silent auch die Ausgabe von npm run (ohne Argumente).
% npm -s run
%
Standardmäßig werden die Protokolle in das npm-Cache-Verzeichnis geschrieben, dessen Pfad wir über npm config abrufen können:
% npm config get cache
/Users/robin/.npm
Der Inhalt des Protokollverzeichnisses sieht wie folgt aus:
% ls -1 /Users/robin/.npm/_logs
2072-08-28T11_44_38_499Z-debug-0.log
2072-08-28T11_45_45_703Z-debug-0.log
2072-08-28T11_52_04_345Z-debug-0.log
Jede Zeile in einem Protokoll beginnt mit einem Zeilenindex und einem Protokollierungspegel. Dies ist ein Beispiel für ein Protokoll, das mit dem Protokollierungspegel notice geschrieben wurde. Interessanterweise erscheinen selbst Protokollierungspegel, die „gesprächiger“ als notice sind (wie silly), darin:
0 verbose cli /usr/local/bin/node /usr/local/bin/npm
1 info using npm@8.15.0
···
33 silly logfile done cleaning log files
34 timing command:run Completed in 9ms
···
Wenn npm run mit einem Fehler zurückkehrt, endet das entsprechende Protokoll wie folgt:
34 timing command:run Completed in 7ms
35 verbose exit 1
36 timing npm Completed in 28ms
37 verbose code 1
Wenn kein Fehler auftritt, endet das entsprechende Protokoll wie folgt:
34 timing command:run Completed in 7ms
35 verbose exit 0
36 timing npm Completed in 26ms
37 info ok
npm config list --long gibt Standardwerte für verschiedene Einstellungen aus. Dies sind die Standardwerte für Protokollierungs-bezogene Einstellungen:
% npm config list --long | grep log
loglevel = "notice"
logs-dir = null
logs-max = 10
Wenn der Wert von logs-dir null ist, verwendet npm das Verzeichnis _logs innerhalb des npm-Cache-Verzeichnisses (wie bereits erwähnt).
logs-dir erlaubt es uns, den Standard zu überschreiben, sodass npm seine Protokolle in ein Verzeichnis unserer Wahl schreibt.logs-max erlaubt es uns zu konfigurieren, wie viele Dateien in das Protokollverzeichnis geschrieben werden, bevor npm alte Dateien löscht. Wenn wir logs-max auf 0 setzen, werden niemals Protokolle geschrieben.loglevel erlaubt es uns, den npm-Protokollierungspegel zu konfigurieren.Um diese Einstellungen dauerhaft zu ändern, verwenden wir ebenfalls npm config – zum Beispiel:
Abrufen des aktuellen Protokollierungspegels
npm config get loglevelDauerhaftes Setzen des aktuellen Protokollierungspegels
npm config set loglevel silentDauerhaftes Zurücksetzen des Protokollierungspegels auf den integrierten Standardwert
npm config delete loglevelWir können Einstellungen auch vorübergehend über Befehlszeilenoptionen ändern – zum Beispiel:
npm --loglevel silent run build
Andere Möglichkeiten zur Änderung von Einstellungen (wie die Verwendung von Umgebungsvariablen) werden von der npm-Dokumentation erklärt.
npm install ausgeführt werdenDie Ausgabe von Lebenszyklus-Skripten, die während npm install (ohne Argumente) ausgeführt werden, ist verborgen. Wir können dies ändern, indem wir foreground-scripts (vorübergehend oder dauerhaft) auf true setzen.
silent schaltet zusätzliche Ausgaben bei Verwendung von npm run aus.Die beiden am häufigsten für Paket-Skripte verwendeten Shells sind:
sh unter Unixcmd.exe unter WindowsIn diesem Abschnitt untersuchen wir Konstrukte, die in beiden Shells funktionieren.
Tipps
Verwenden Sie relative Pfade, deren Segmente durch Schrägstriche getrennt sind: Windows akzeptiert Schrägstriche als Trennzeichen, obwohl Sie auf dieser Plattform normalerweise umgekehrte Schrägstriche verwenden würden.
Argumente in doppelte Anführungszeichen setzen: Während sh einfache Anführungszeichen unterstützt, tut dies die Windows-Kommandozeile nicht. Leider müssen wir doppelte Anführungszeichen maskieren, wenn wir sie in Paket-Skriptdefinitionen verwenden.
"dir": "mkdir \"\my dir""Es gibt zwei Möglichkeiten, Befehle zu verketten, die auf beiden Plattformen funktionieren:
&& wird nur ausgeführt, wenn der vorherige Befehl erfolgreich war (Exit-Code ist 0).|| wird nur ausgeführt, wenn der vorherige Befehl fehlgeschlagen ist (Exit-Code ist nicht 0).Das Verketten unter Ignorieren des Exit-Codes unterscheidet sich zwischen den Plattformen:
;&Die folgende Interaktion demonstriert, wie && und || unter Unix funktionieren (unter Windows würden wir dir anstelle von ls verwenden):
% ls unknown && echo "SUCCESS" || echo "FAILURE"
ls: unknown: No such file or directory
FAILURE
% ls package.json && echo "SUCCESS" || echo "FAILURE"
package.json
SUCCESS
Der Exit-Code kann über eine Shell-Variable abgerufen werden:
$?%errorlevel%npm run kehrt mit demselben Exit-Code zurück wie das zuletzt ausgeführte Shell-Skript.
{
···
"scripts": {
"hello": "echo Hello",
"err": "more does-not-exist.txt"
}
}Die folgende Interaktion findet unter Unix statt:
% npm -s run hello ; echo $?
Hello
0
% npm -s run err ; echo $?
does-not-exist.txt: No such file or directory
1
|cmd > stdout-saved-to-file.txtcmd < stdin-from-file.txtDie folgenden Befehle existieren auf beiden Plattformen (unterscheiden sich aber bei den Optionen):
cdecho. Vorsicht unter Windows: doppelte Anführungszeichen werden gedruckt, nicht ignoriert.exitmkdirmorermdirsortDie folgende package.json demonstriert drei Möglichkeiten, Bin-Skripte in Abhängigkeiten aufzurufen:
{
"scripts": {
"hi1": "./node_modules/.bin/cowsay Hello",
"hi2": "cowsay Hello",
"hi3": "npx cowsay Hello"
},
"dependencies": {
"cowsay": "^1.5.0"
}
}Erläuterungen
hi1: Bin-Skripte in Abhängigkeiten werden im Verzeichnis node_modules/.bin installiert.
hi2: Wie wir gesehen haben, fügt npm node_modules/.bin dem Shell-PATH hinzu, während es Paket-Skripte ausführt. Das bedeutet, dass wir lokale Bin-Skripte verwenden können, als ob sie global installiert wären.
hi3: Wenn npx ein Skript ausführt, fügt es ebenfalls node_modules/.bin zum Shell-PATH hinzu.
Unter Unix können wir paketlokale Skripte direkt aufrufen – wenn sie Hashbangs haben und ausführbar sind. Dies funktioniert jedoch nicht unter Windows, weshalb es besser ist, sie über node aufzurufen.
"build": "node ./build.mjs"node --eval und node --printWenn die Funktionalität eines Paket-Skripts zu komplex wird, ist es oft eine gute Idee, sie über ein Node.js-Modul zu implementieren – was die plattformübergreifende Codeerstellung erleichtert.
Wir können jedoch auch den node-Befehl verwenden, um kleine JavaScript-Snippets auszuführen, was nützlich ist, um kleine Aufgaben plattformübergreifend auszuführen. Die relevanten Optionen sind:
node --eval <expr> evaluiert den JavaScript-Ausdruck expr.node -enode --print <expr> evaluiert den JavaScript-Ausdruck expr und gibt das Ergebnis auf dem Terminal aus.node -pDie folgenden Befehle funktionieren sowohl unter Unix als auch unter Windows (nur die Kommentare sind Unix-spezifisch):
# Print a string to the terminal (cross-platform echo)
node -p "'How are you?'"
# Print the value of an environment variable
# (Alas, we can’t change variables via `process.env`)
node -p process.env.USER # only Unix
node -p process.env.USERNAME # only Windows
node -p "process.env.USER ?? process.env.USERNAME"
# Print all environment variables
node -p process.env
# Print the current working directory
node -p "process.cwd()"
# Print the path of the current home directory
node -p "os.homedir()"
# Print the path of the current temporary directory
node -p "os.tmpdir()"
# Print the contents of a text file
node -p "fs.readFileSync('package.json', 'utf-8')"
# Write a string to a file
node -e "fs.writeFileSync('file.txt', 'Text content', 'utf-8')"
Wenn wir plattformspezifische Zeilenabschlüsse benötigen, können wir os.EOL verwenden – zum Beispiel könnten wir 'Text content' im vorherigen Befehl ersetzen durch:
`line 1${os.EOL}line2${os.EOL}`Beobachtungen
os oder fs nicht importieren.fs unterstützt weitere Dateisystemoperationen. Diese sind in §8 „Arbeiten mit dem Dateisystem unter Node.js“ dokumentiert (§8 „Arbeiten mit dem Dateisystem unter Node.js“).npm-quick-run bietet ein Bin-Skript nr, mit dem wir Abkürzungen verwenden können, um Paket-Skripte auszuführen – zum Beispiel:
nr m -w führt "npm run mocha -- -w" aus (wenn "mocha" das erste Paket-Skript ist, dessen Name mit „m“ beginnt).nr c:o führt das Paket-Skript "cypress:open" aus.Shell-Skripte gleichzeitig ausführen
&startDie folgenden beiden Pakete bieten uns plattformübergreifende Optionen dafür und für verwandte Funktionalitäten:
concurrently führt mehrere Shell-Befehle gleichzeitig aus – zum Beispiel:
concurrently "npm run clean" "npm run build"npm-run-all bietet verschiedene Arten von Funktionalitäten – zum Beispiel:
Eine bequemere Art, Paket-Skripte nacheinander aufzurufen. Die folgenden beiden Befehle sind äquivalent:
npm-run-all clean lint build
npm run clean && npm run lint && npm run buildPaket-Skripte gleichzeitig ausführen.
npm-run-all --parallel lint buildVerwenden eines Wildcards zum Ausführen mehrerer Skripte – zum Beispiel steht watch:* für alle Paket-Skripte, deren Namen mit watch: beginnen (watch:html, watch:js usw.).
npm-run-all "watch:*"
npm-run-all --parallel "watch:*"Das Paket shx ermöglicht es uns, „Unix-Syntax“ zu verwenden, um verschiedene Dateisystemoperationen auszuführen. Alles, was es tut, funktioniert unter Unix und Windows.
Ein Verzeichnis erstellen
"create-asset-dir": "shx mkdir ./assets"Ein Verzeichnis löschen
"remove-asset-dir": "shx rm -rf ./assets"Ein Verzeichnis leeren (doppelte Anführungszeichen zur Sicherheit bezüglich des Wildcard-Symbols *).
"tscclean": "shx rm -rf \"./dist/*\""Eine Datei kopieren
"copy-index": "shx cp ./html/index.html ./out/index.html"Eine Datei löschen
"remove-index": "shx rm ./out/index.html"shx basiert auf der JavaScript-Bibliothek ShellJS, deren Repository alle unterstützten Befehle auflistet. Zusätzlich zu den bereits bekannten Unix-Befehlen emuliert es auch: cat, chmod, echo, find, grep, head, ln, ls, mv, pwd, sed, sort, tail, touch, uniq und andere.
Paket trash-cli funktioniert unter macOS (10.12+), Linux und Windows (8+). Es legt Dateien und Verzeichnisse in den Papierkorb und unterstützt Pfade und Glob-Muster. Dies sind Beispiele für die Verwendung
trash tmp-file.txt
trash tmp-dir
trash "*.jpg"
Paket copyfiles ermöglicht es uns, Dateistrukturen zu kopieren.
Der folgende Anwendungsfall beschreibt die Verwendung von copyfiles: In TypeScript können wir Nicht-Code-Assets wie CSS und Bilder importieren. Der TypeScript-Compiler kompiliert den Code in ein "dist" (Ausgabe)-Verzeichnis, ignoriert aber Nicht-Code-Assets. Dieser plattformübergreifende Shell-Befehl kopiert sie in das dist-Verzeichnis
copyfiles --up 1 "./ts/**/*.{css,png,svg,gif}" ./distTypeScript kompiliert
my-pkg/ts/client/picker.ts -> my-pkg/dist/client/picker.js
copy-assets kopiert
my-pkg/ts/client/picker.css -> my-pkg/dist/client/picker.css
my-pkg/ts/client/icon.svg -> my-pkg/dist/client/icon.svg
Paket onchange überwacht Dateien und führt bei jeder Änderung einen Shell-Befehl aus – zum Beispiel
onchange 'app/**/*.js' 'test/**/*.js' -- npm test
Eine gängige Alternative (unter vielen anderen)
Während der Entwicklung ist es oft nützlich, einen HTTP-Server zu haben. Die folgenden Pakete (unter vielen anderen) können dabei helfen
per-env: Umschalten zwischen Skripten, abhängig von $NODE_ENVDas Binärskript per-env ermöglicht uns, ein Paket-Skript SCRIPT auszuführen und automatisch zwischen (z. B.) SCRIPT:development, SCRIPT:staging und SCRIPT:production umzuschalten, abhängig vom Wert der Umgebungsvariable NODE_ENV
{
"scripts": {
// If NODE_ENV is missing, the default is "development"
"build": "per-env",
"build:development": "webpack -d --watch",
"build:staging": "webpack -p",
"build:production": "webpack -p"
},
// Processes spawned by `per-env` inherit environment-specific
// variables, if defined.
"per-env": {
"production": {
"DOCKER_USER": "my",
"DOCKER_REPO": "project"
}
}
}Das Binärskript cross-os schaltet zwischen Skripten um, abhängig vom aktuellen Betriebssystem.
{
"scripts": {
"user": "cross-os user"
},
"cross-os": {
"user": {
"darwin": "echo $USER",
"win32": "echo %USERNAME%",
"linux": "echo $USER"
}
},
···
}Unterstützte Eigenschaftswerte sind: darwin, freebsd, linux, sunos, win32.