Einführung in NPM-Skripte

NPM-Skripte gehören zu meinen Lieblingsfunktionen von NPM. Sie sind einfach. Sie reduzieren den Bedarf an Werkzeugen. Daher reduzieren sie die Anzahl der Konfigurationsdateien und anderer Dinge, die Sie im Auge behalten müssen. Und sie sind sehr vielseitig. Mit ihnen können Sie auch viele gängige Aufgaben automatisieren. Einige davon sind gegen Ende des Artikels aufgeführt.

Lassen Sie uns ohne weiteres in NPM-Skripte eintauchen!

Was sind NPM-Skripte?

NPM-Skripte sind Skripte. Wir verwenden Skripte, um sich wiederholende Aufgaben zu automatisieren. Erstellen Sie beispielsweise Ihr Projekt und minimieren Sie CSS- (Cascading Style Sheets) und JS-Dateien (JavaScript). Skripte werden auch zum Löschen temporärer Dateien und Ordner usw. verwendet. Es gibt viele Möglichkeiten, dies zu erreichen - Sie können Bash- / Batch-Skripte schreiben oder einen Task-Runner wie Gulp oder Grunt verwenden. Viele Leute wechseln jedoch aufgrund ihrer Einfachheit und Vielseitigkeit zu NPM-Skripten. Sie bieten auch die Möglichkeit, weniger Tools zum Lernen, Verwenden und Verfolgen zu haben.

Nachdem wir (einige) eine Vorstellung davon haben, was NPM-Skripte sind und was sie für uns tun können, schreiben wir einige!

Das Skriptobjekt in package.json

Der größte Teil unserer Arbeit wird in der Datei package.json stattfinden, die NPM als eine Art Manifest verwendet. Dies ist die Datei, die beim Ausführen erstellt wirdnpm init.

Hier ist eine Beispieldatei package.json:

{ "name": "super-cool-package", "version": "1.0.0", "scripts": { ... }, "dependencies": { ... } "devDependencies": { ... } }

Wenn Sie mit NodeJS und NPM gearbeitet haben, sind Sie mit der Datei package.json vertraut. Beachten Sie das scriptsObjekt in der Datei. Hier werden unsere NPM-Skripte abgelegt. NPM-Skripte werden wie gewohnt JSON-Schlüssel-Wert-Paare geschrieben, wobei der Schlüssel der Name des Skripts ist und der Wert das Skript enthält, das Sie ausführen möchten.

Hier ist vielleicht das beliebteste NPM-Skript (und es ist auch eine spezielle Art von Skript):

"scripts": { "start": "node index.js", ...}

Sie haben dies wahrscheinlich unzählige Male in Ihren package.json-Dateien gesehen. Und Sie wissen wahrscheinlich, dass Sie eingeben können npm start, um das Skript auszuführen. Dieses Beispiel zeigt jedoch den ersten wichtigen Aspekt von NPM-Skripten - es handelt sich lediglich um Terminalbefehle. Sie werden in der Shell des Betriebssystems ausgeführt, auf dem sie ausgeführt werden. Es könnte also Bash für Linux und cmd.exe für Windows sein.

An diesem Punkt könnten Sie ziemlich unbeeindruckt sein. Aber lesen Sie weiter, um zu sehen, wie leistungsfähig NPM-Skripte wirklich sind.

Benutzerdefinierte Skripte

Das Skript, das wir gerade gesehen haben, ist eines der „speziellen“ NPM-Skripte. Sie können es ausführen, indem Sie einfach eingeben npm start. Dies sind Skripte mit Namen, die NPM erkennt und denen eine besondere Bedeutung beimisst. Sie können beispielsweise ein Skript mit dem Namen schreiben prepublish. NPM führt das Skript aus, bevor Ihr Paket gepackt und veröffentlicht wird, und auch, wenn Sie npm installlokal ohne Argumente ausgeführt werden. Mehr zu solchen Skripten hier.

Mit NPM können Sie aber auch Ihre eigenen benutzerdefinierten Skripte definieren. Hier zeigt sich die Leistungsfähigkeit von NPM-Skripten.

Schauen wir uns ein super einfaches benutzerdefiniertes NPM-Skript an, das "Hallo Welt" an die Konsole ausgibt. Fügen Sie dies dem Skriptobjekt Ihrer Datei package.json hinzu:

"say-hello": "echo 'Hello World'"

Das Skriptobjekt in Ihrer package.json-Datei sollte folgendermaßen aussehen:

..."scripts": { "start": "node index.js", "say-hello": "echo 'Hello World!'"}

Versuchen Sie jetzt zu laufen npm say-hello. Funktioniert nicht Dies liegt daran, dass benutzerdefinierten NPM-Skripten entweder run-scriptoder vorangestellt werden muss, damit runsie korrekt ausgeführt werden. Versuchen Sie es mit npm run-script say-hellooder npm run say-hello. Die Konsole sagt "Hallo Welt!"! Wir haben unser erstes NPM-Skript geschrieben!

Hier ist ein kurzer Tipp: Um zu verhindern, dass die Standard-NPM-Protokolle beim Ausführen eines Skripts an die Konsole ausgegeben werden, fügen Sie das --silentFlag hinzu. So würde Ihr Befehl aussehen:

npm run --silent say-hello

Aufrufen von NPM-Skripten in anderen NPM-Skripten

Ein Nachteil der Verwendung von NPM-Skripten zeigt sich, wenn Ihr Skript ziemlich komplex (und lang) ist. Dieses Problem wird durch die Tatsache verschärft, dass die JSON-Spezifikation keine Kommentare unterstützt. Es gibt einige Möglichkeiten, um dieses Problem zu umgehen. Eine Möglichkeit besteht darin, Ihr Skript in kleine Einzweck-Skripte zu unterteilen und diese dann in anderen NPM-Skripten aufzurufen. Das Aufrufen eines NPM-Skripts in einem anderen ist unkompliziert. Ändern Sie Ihr scriptsObjekt so, dass es so aussieht:

"scripts": { "say-hello": "echo 'Hello World'", "awesome-npm": "npm run say-hello && echo 'echo NPM is awesome!'"}

Da NPM-Skripte in der Shell ausgeführt werden, ist das Aufrufen npm run say-helloin einem anderen NPM-Skript fast intuitiv.

Für diejenigen unter Ihnen, die mit Terminalbefehlen nicht sehr vertraut sind, wird &&das Skript verwendet, um zwei Befehle abzugrenzen. Somit wird der zweite Befehl nach der erfolgreichen Ausführung des ersten Befehls ausgeführt.

Wenn Sie jetzt npm run awesome-npmausführen, wird das Say-Hello-Skript zuerst ausgeführt und gibt "Hello World" an die Konsole aus, gefolgt von dem Teil des Skripts nach dem &&, der "NPM is awesome!" Ausgibt.

Hier ist ein Anwendungsfall, in dem dies nützlich sein könnte. Angenommen, Sie automatisieren den Erstellungsprozess Ihrer Anwendung. Angenommen, Sie verwenden Webpack als Bundler und Ihr Distributionscode wird in ein Verzeichnis namens "dist" verschoben.

Sie können mit der Bereinigung des Verzeichnisses beginnen. Dies kann entweder durch Löschen des Inhalts oder durch Löschen des Verzeichnisses selbst und erneutes Erstellen erfolgen. Gehen wir zum letzteren Ansatz. Ihr Befehl könnte ungefähr so ​​aussehen:

rm -r dist && mkdir dist
Beachten Sie, dass hierfür Bash-Befehle verwendet werden. In diesem Artikel erfahren Sie später, wie Sie plattformübergreifende NPM-Skripte schreiben.

Danach können Sie den Bundler aufrufen, indem Sie den webpackBefehl ausführen .

Sie können diese Befehle nacheinander mit dem &&Operator ausführen . Lassen Sie uns dies jedoch aus Gründen der Demonstration und Modularität in zwei NPM-Skripte aufteilen, die sich gegenseitig aufrufen.

So würde das Skriptobjekt in diesem Anwendungsfall aussehen:

"scripts": { ... "clean": "rm -r dist && mkdir dist", "build": "npm run clean && webpack"}

Hier hast du es! So teilen Sie eine komplexere Aufgabe in kleinere NPM-Skripte auf.

Shell- und Node-Skripte aufrufen

Manchmal müssen Sie möglicherweise Skripte schreiben, die weitaus komplexer sind als diejenigen, die mit 2 bis 3 Befehlen erreicht werden können. In diesem Fall besteht eine Lösung darin, Bash- oder JS-Skripte (oder Skripte in einer beliebigen Skriptsprache) zu schreiben und sie aus NPM-Skripten aufzurufen.

Lassen Sie uns schnell ein Bash-Skript schreiben, das Sie begrüßt. Erstellen Sie eine Datei mit dem Namen hello.shin Ihrem Stammverzeichnis und fügen Sie diesen Code ein:

#!/usr/bin/env bash
# filename: hello.shecho "What's your name?"read nameecho "Hello there, $name!"

Es ist ein einfaches Skript, das Ihren Namen an Sie zurückgibt. Ändern Sie nun die package.jsonDatei so, dass das scriptsObjekt diese Codezeile hat:

"bash-hello": "bash hello.sh"

Wenn Sie jetzt rennen npm run bash-hello, werden Sie nach Ihrem Namen gefragt und dann begrüßt Sie! Brillant.

Sie können dasselbe mit JS-Skripten tun, die mit node ausgeführt werden. Ein Vorteil dieses Ansatzes besteht darin, dass dieses Skript plattformunabhängig ist, da es zum Ausführen einen Knoten verwendet. Hier ist ein etwas komplexeres JS-Skript zum Hinzufügen von zwei Ganzzahlen, die als Befehlszeilenargumente empfangen wurden (fügen Sie dies in eine Datei mit dem Namen add.js ein):

// add.js// adds two integers received as command line arguments
function add(a, b) { return parseInt(a)+parseInt(b);}
if(!process.argv[2] || !process.argv[3]) { console.log('Insufficient number of arguments! Give two numbers please!');}
else { console.log('The sum of', process.argv[2], 'and', process.argv[3], 'is', add(process.argv[2], process.argv[3]));}
Das process.argv-Objekt enthält die Befehlszeilenargumente, die dem Skript gegeben wurden. Die ersten beiden Elemente process.argv[0]und process.argv[1]sind nach Knoten reserviert. So process.argv[2]und process.argv[3]lassen Sie die Befehlszeilenargumente zuzugreifen.

Now add this line to the scripts object of the package.json file:

"js-add": "node add.js"

Finally, run the script as an npm script by giving it two numbers as command line arguments:

npm run js-add 2 3

And viola! The output is

The sum of 2 and 3 is 5

Brilliant! Now we’re capable of writing much more powerful scripts and leveraging the power of other scripting languages.

Pre and Post Hooks

Remember how we talked about a special npm script called prepublish that runs before you publish your package? Such a functionality can be achieved with custom scripts too. We’ve discussed one way to do this in the previous section. We can chain commands using the &&operator, so if you wanted to run script-1 before script-2, you would write:

"script-2": "npm run script-1 && echo 'I am script-2'"

However, this makes our scripts a little dirty. This is because the core functionality of the script is reflected only in the second part of the command (after the && ). One way to write clean scripts is to use pre and post hooks.

Pre and post hooks are exactly what they sound like — they let you execute scripts before and after you call a particular script. All you have to do is define new scripts with the same name as your main script. Yet these are prefixed with “pre” or “post” depending on whether the script is executed before the main script or after it.

Let’s look at our say-hello script again. Say we want to execute the command echo 'I run before say-hello' before say-hello and echo 'I run after say-hello' after say-hello. This is what your scripts object would look like:

"scripts": { "say-hello": "echo 'Hello World'", "presay-hello": "echo 'I run before say-hello'", "postsay-hello": "echo 'I run after say-hello'" }

The “pre” and “post” before the script names tell npm to execute these before and after the script called say-hello respectively.

Now, when you run npm run say-hello, the output of all three scripts shows up in order! How cool is that?

Since all three scripts output to the console and the NPM logs clutter the output, I prefer using the -silent flag while running these. So your command would look like this:

npm run --silent say-hello

And here’s the output:

I run before say-helloHello WorldI run after say-hello

There you have it!

Let’s apply this knowledge to our build script example. Modify your package.json file so that it looks like this:

"scripts": { ... "clean": "rm -r dist && mkdir dist", "prebuild": "npm run clean" "build": "webpack"}

Now our scripts look much cleaner. When you run npm run build, prebuildis called because of the “pre” hook, which calls clean, which cleans up our dist directory for us. Sweet!

Making Our Scripts Cross-Platform

There is one drawback of writing terminal/shell commands in our scripts. This is the fact that shell commands make our scripts platform dependently. This is perhaps what draws our attention to tools like Gulp and Grunt. If your script is written for Unix systems, chances are, it won’t work on Windows, and vice versa.

The first time I used NPM scripts, which called other bash/batch scripts, I thought of writing two scripts per task. One for Unix and one for the Windows command line. This approach may work in use cases where the scripts aren’t that complex and there aren’t many scripts. However, it quickly becomes clear that they are not a good solution to the problem. Some of the reasons behind this are:

  • You have another thing to keep track of that distracts you from your primary task of working on the application. Instead, you end up working in the development environment.
  • You’re writing redundant code — the scripts you write are very similar and accomplish the same task. You’re essentially rewriting code. This violates one of the fundamental principles of coding — DRY: Don’t Repeat Yourself.

So how do we get around this? There are three approaches that you may use:

  1. Use commands that run cross-platform: Many useful commands are common to Unix and Windows. If your scripts are simple, consider using those.
  2. Use node packages: You can use node packages like rimraf or cross-env instead of shell commands. And obviously, you can use these packages in JS files if your script is large and complex.
  3. ShellJS verwenden: ShellJS ist ein npm-Paket, das Unix-Befehle über Node ausführt. Auf diese Weise können Sie Unix-Befehle auf allen Plattformen ausführen, einschließlich Windows.
Die obigen Ansätze stammen aus diesem brillanten Artikel von Cory House darüber, warum er Grunt und Gulp für NPM-Skripte verlassen hat. Der Artikel beschreibt viele Dinge, die in dieser Reihe nicht behandelt werden, und schließt mit einer Liste hervorragender Ressourcen. Ich würde definitiv empfehlen, dass Sie es lesen, um Ihr Verständnis von NPM-Skripten zu verbessern.

Einige Anwendungsfälle für NPM-Skripte

Schließlich gibt es eine Menge, die Sie mit NPM-Skripten tun können. Einige Anwendungsfälle sind:

  • Minimierung / Uglifizierung von CSS / JavaScript
  • Automatisierung des Erstellungsprozesses
  • Flusen Sie Ihren Code
  • Bilder komprimieren
  • Automatisches Einfügen von Änderungen mit BrowserSync

And a lot more. To learn about how to automate the above-mentioned tasks using NPM scripts, check out this brilliant article on the topic.

Bonus: Commander for Creating CLI Applications Using NodeJS

While we’re discussing NPM scripts and the CLI, I’d like to quickly tell you about a really cool package called commander. Commander allows you to create your own CLI applications. This isn’t really related to NPM scripts, but it’s a cool piece of technology to know. Check out the commander docs here or try one of these tutorials:

  • Build An Interactive Command-Line Application with Node.js — Scotch.io
  • Writing Command Line Applications in NodeJS — freeCodeCamp

Concluding Words

That is all for this article on using NPM scripts. I hope you’ve gained some insight on how you can integrate these into your own projects. This article is by no means an in-depth tutorial on NPM scripts. Hence I’d recommend you learn further both from other resources and from actually using NPM scripts in your own projects.

Also, do connect with me on GitHub and LinkedIn.

Happy Coding! :)