Was ist npm? Ein Node Package Manager-Tutorial für Anfänger

Dieser Artikel sollte als All-in-One-Leitfaden für Node.js Lieblingskumpel dienen: npm.

Node.js erobert seit 2009 die Welt im Sturm. Hunderttausende von Systemen wurden mit Node.js erstellt, was die Entwicklergemeinde dazu veranlasste, zu behaupten, dass "JavaScript Software frisst".

Einer der Hauptfaktoren für den Erfolg von Node ist npm - sein beliebter Paketmanager, mit dem JavaScript-Entwickler nützliche Pakete wie lodash und moment schnell und einfach teilen können.

Ab dem Moment, in dem ich diesen Beitrag schreibe, hat npm die Veröffentlichung von über 1,3 Millionen Paketen mit einer wöchentlichen Download-Rate von über 16 Milliarden ermöglicht! Diese Zahlen sind für jedes Software-Tool fantastisch. Sprechen wir jetzt darüber, was genau npm ist.

Was ist NPM?

NPM - oder "Node Package Manager" - ist der Standardpaketmanager für die JavaScript-Laufzeit Node.js.

Es ist auch bekannt als "Ninja Pumpkin Mutants", "Nonprofit Pizza Makers" und eine Vielzahl anderer zufälliger Namen, die Sie bei npm-Erweiterungen erkunden und wahrscheinlich dazu beitragen können.

NPM besteht aus zwei Hauptteilen:

  • ein CLI-Tool (Command-Line Interface) zum Veröffentlichen und Herunterladen von Paketen und
  • Ein Online-Repository, das JavaScript-Pakete hostet

Für eine visuellere Erklärung können wir uns das Repository npmjs.com als ein Fulfillment-Center vorstellen, das Warenpakete von Verkäufern (Autoren von npm-Paketen) empfängt und diese Waren an Käufer (Benutzer von npm-Paketen) verteilt.

Um diesen Prozess zu vereinfachen, beschäftigt das Fulfillment-Center von npmjs.com eine Armee fleißiger Wombats (npm CLI), die jedem einzelnen Kunden von npmjs.com als persönliche Assistenten zugewiesen werden. Abhängigkeiten werden also wie folgt an JavaScript-Entwickler geliefert:

und der Prozess der Veröffentlichung eines Pakets für Ihre JS-Kollegen wäre ungefähr so:

Schauen wir uns an, wie diese Armee von Wombats Entwicklern hilft, die JavaScript-Pakete in ihren Projekten verwenden möchten. Wir werden auch sehen, wie sie Open-Source-Assistenten dabei helfen, ihre coolen Bibliotheken in die Welt zu bringen.

package.json

Jedes Projekt in JavaScript - ob es sich um Node.js oder eine Browseranwendung handelt - kann als npm-Paket mit eigenen Paketinformationen und seiner package.jsonAufgabe zur Beschreibung des Projekts definiert werden.

Wir können uns package.jsonals gestempelte Etiketten auf diesen npm-guten Kisten vorstellen, die unsere Armee von Wombats liefert.

package.jsonwird generiert, wenn npm inites ausgeführt wird, um ein JavaScript / Node.js-Projekt mit diesen grundlegenden Metadaten zu initialisieren, die von Entwicklern bereitgestellt werden:

  • name: Der Name Ihrer JavaScript-Bibliothek / Ihres JavaScript-Projekts
  • version: die Version Ihres Projekts. Bei der Anwendungsentwicklung wird dieses Feld häufig vernachlässigt, da die Versionierung von OpenSource-Bibliotheken offensichtlich nicht erforderlich ist. Dennoch kann es als Quelle für die Bereitstellungsversion nützlich sein.
  • description: die Projektbeschreibung
  • license: die Projektlizenz

npm-Skripte

package.jsonunterstützt auch eine scriptsEigenschaft, die definiert werden kann, um Befehlszeilentools auszuführen, die im lokalen Kontext des Projekts installiert sind. Der scriptsTeil eines npm-Projekts kann beispielsweise folgendermaßen aussehen:

{ "scripts": { "build": "tsc", "format": "prettier --write **/*.ts", "format-check": "prettier --check **/*.ts", "lint": "eslint src/**/*.ts", "pack": "ncc build", "test": "jest", "all": "npm run build && npm run format && npm run lint && npm run pack && npm test" } } 

mit eslint, prettier, ncc, jestnicht unbedingt als globale ausführbaren Dateien installiert , sondern als lokal für Ihr Projekt innerhalb node_modules/.bin/.

Die kürzlich eingeführte Einführung von npx ermöglicht es uns, diese node_modulesprojektbezogenen Befehle wie ein global installiertes Programm durch Präfix npx ...(dh npx prettier --write **/*.ts) auszuführen .

Abhängigkeiten vs devDependencies

Diese beiden kommen in Form von Schlüsselwertobjekten mit den Namen der npm-Bibliotheken als Schlüssel und ihren semantisch formatierten Versionen als Wert. Dies ist ein Beispiel aus der TypeScript-Aktionsvorlage von Github:

{ "dependencies": { "@actions/core": "^1.2.3", "@actions/github": "^2.1.1" }, "devDependencies": { "@types/jest": "^25.1.4", "@types/node": "^13.9.0", "@typescript-eslint/parser": "^2.22.0", "@zeit/ncc": "^0.21.1", "eslint": "^6.8.0", "eslint-plugin-github": "^3.4.1", "eslint-plugin-jest": "^23.8.2", "jest": "^25.1.0", "jest-circus": "^25.1.0", "js-yaml": "^3.13.1", "prettier": "^1.19.1", "ts-jest": "^25.2.1", "typescript": "^3.8.3" } } 

Diese Abhängigkeiten werden über den npm installBefehl with --saveund --save-devflags installiert . Sie sollen für Produktions- bzw. Entwicklungs- / Testumgebungen verwendet werden. Wir werden uns im nächsten Abschnitt eingehender mit der Installation dieser Pakete befassen.

In der Zwischenzeit ist es wichtig, die möglichen Zeichen zu verstehen, die vor den semantischen Versionen auftreten (vorausgesetzt, Sie haben das major.minor.patchSemver-Modell gelesen):

  • ^: neueste Nebenversion. Beispielsweise kann eine ^1.0.4Spezifikation eine Version installieren, 1.3.0wenn dies die neueste Nebenversion in der 1Hauptserie ist.
  • ~: neueste Patch-Version. Auf die gleiche Weise wie ^bei Nebenversionen kann die ~1.0.4Spezifikation die Version installieren, 1.0.7wenn dies die neueste Nebenversion in der 1.0Nebenserie ist.

Alle diese genauen Paketversionen werden in einer generierten package-lock.jsonDatei dokumentiert .

package-lock.json

Diese Datei beschreibt die genauen Versionen der Abhängigkeiten, die in einem npm-JavaScript-Projekt verwendet werden. Wenn package.jsones sich um ein generisches beschreibendes Etikett handelt, package-lock.jsonhandelt es sich um eine Zutatentabelle.

Und genau wie wir normalerweise die Inhaltsstofftabelle eines Produkts nicht lesen (es sei denn, Sie sind zu gelangweilt oder müssen es wissen), package-lock.jsonist es nicht dazu gedacht, von Entwicklern Zeile für Zeile gelesen zu werden (es sei denn, wir möchten es unbedingt lösen ". funktioniert in meiner Maschine "Probleme).

package-lock.jsonwird normalerweise vom npm installBefehl generiert und auch von unserem NPM-CLI-Tool gelesen, um die Reproduktion von Build-Umgebungen für das Projekt mit sicherzustellen npm ci.

Wie man NPM Wombats effektiv als "Käufer" befiehlt

Wie aus den 1,3 Millionen veröffentlichten Paketen gegenüber 16 Milliarden Downloads hervorgeht, verwendet die Mehrheit der npm-Benutzer npm in dieser Richtung. Es ist also gut zu wissen, wie man dieses mächtige Werkzeug einsetzt.

npm installieren

Dies ist der am häufigsten verwendete Befehl, da wir heutzutage JavaScript / Node.js-Anwendungen entwickeln.

Standardmäßig npm install wird die neueste Version eines Pakets mit dem ^Versionszeichen installiert . Im npm installRahmen eines npm-Projekts werden Pakete node_modulesgemäß den package.jsonSpezifikationen in den Projektordner heruntergeladen , wobei die Paketversion aktualisiert (und neu generiert package-lock.json) wird, wo immer dies möglich ist, ^und ~Versionsübereinstimmung.

Sie können ein globales Flag angeben, -gwenn Sie ein Paket im globalen Kontext installieren möchten, das Sie überall auf Ihrem Computer verwenden können (dies ist bei Befehlszeilen-Toolpaketen wie Live-Server üblich).

npm hat die Installation von JavaScript-Paketen so einfach gemacht, dass dieser Befehl häufig falsch verwendet wird. Dies führt dazu, dass npm der Hintern vieler Witze von Programmierern wie diesen ist:

Hier kommt die --productionFlagge zur Rettung! Im vorherigen Abschnitt haben wir die Verwendung in der Produktions- bzw. Entwicklungs- / Testumgebung erörtert dependenciesund vorgesehen devDependencies. Mit diesem --productionFlag werden die Unterschiede in node_modulesgemacht.

By attaching this flag to the npm install command, we will only install packages from dependencies, thus drastically reducing the size of our node_modules to whatever is absolutely necessary for our applications to be up and running.

Just like how as boy and girl scouts we didn't bring lemon squeezers to our lemonade booth, we shouldn't bring devDependencies to production!

npm ci

So if npm install --production is optimal for a production environment, must there be a command that's optimal for my local development, testing setup?

The answer is npm ci.

Just like how if package-lock.json doesn't already exist in the project it's generated whenever npm install is called, npm ci consumes this file to download the exact version of each individual package that the project depends on.

This is how we can make sure that the our project's context stays exactly the same across different machines, whether it's our laptops used for development or CI (Continuous Integration) build environments like Github Actions.

npm audit

With the humongous number of packages that have been published and can easily be installed, npm packages are susceptible to bad authors with malicious intentions like these.

Realising that there was an issue in the ecosystem, the npm.js organisation came up with the idea of npm audit. They maintain a list of security loopholes that developers can audit their dependencies against using the npm audit command.

npm audit gives developers information about the vulnerabilities and whether there're versions with remediations to upgrade to. For example,

If the remediations are available in the next non-breaking version upgrades, npm audit fix can be used to upgrade the affected dependencies' versions automatically.

How to effectively command NPM wombats as "seller"

We have gone through how to wield the NPM CLI tool as a consumer, but what about effectively using it as an author (and potentially becoming a JavaScript open source wizard ?)?

npm publish

Sending a package to our npmjs.com fulfillment centre is super easy as we only need to run npm publish. The tricky part, which is not specific to npm package authors, is determining the version of the package.

The rule of thumb according to semver.org:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards compatible manner, and
  3. PATCH version when you make backwards compatible bug fixes.

It's even more important to follow the above rule when publishing your packages to ensure that you're not breaking anyone's code as the default version matching in npm is ^ (aka the next minor version).

❤️ npm ❤️ JavaScript ❤️ Node.js ❤️

That's all we need to know to start wielding npm effectively and command our lovely army of wombats!