Was ist npm?
npm ist der Standard-Package-Manager für JavaScript und die größte Software-Registry der Welt. Es wird zusammen mit Node.js ausgeliefert, installiert die von deinem Projekt deklarierten Abhängigkeiten, löst deren Versionen auf und bietet dir über Skripte einen konsistenten Task-Runner.
Fast jedes JavaScript-Projekt ist auf npm angewiesen, selbst wenn im Hintergrund ein anderer Client verwendet wird. Zu verstehen, was es tatsächlich macht – wie Versionen aufgelöst werden, wofür die Lockfile da ist und warum CI einen anderen Befehl nutzt – beseitigt eine ganze Kategorie von verwirrenden Fehlern.
package.json
Das Manifest beschreibt dein Projekt. Es enthält Metadaten, Abhängigkeiten und Skripte.
{
"name": "my-app",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest run",
"lint": "eslint ."
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"vite": "^6.0.0",
"vitest": "^3.0.0"
}
}
dependencies werden zur Laufzeit benötigt; devDependencies sind Tools, die für die Entwicklung und den Build-Prozess verwendet werden. Das private Flag verhindert ein versehentliches Veröffentlichen, und type: "module" aktiviert ES-Module.
Versionsbereiche
npm verwendet Semantic Versioning: major.minor.patch. Ein Bereich in package.json beschreibt, welche Updates akzeptiert werden.
| Bereich | Bedeutung | Erlaubt |
|---|---|---|
1.2.3 |
exakt | nichts |
~1.2.3 |
Patch-Updates | 1.2.4, 1.2.5 |
^1.2.3 |
Minor- und Patch-Updates | 1.3.0, 1.4.2 |
* |
beliebig | jede Version |
Das Caret-Symbol ist der Standard und für die meisten Abhängigkeiten die sinnvollste Wahl. Exakte Versionen blockieren Bugfixes und Sicherheitspatches, während die Lockfile bereits die Reproduzierbarkeit garantiert.
Die Lockfile
package-lock.json zeichnet die exakte Version und den Integrity-Hash jedes Pakets im Tree auf, einschließlich transitiver Abhängigkeiten.
- Checken Sie die Datei in die Versionsverwaltung ein.
- Bearbeiten Sie sie niemals manuell.
- Generieren Sie sie bewusst neu, wenn Sie ein Update beabsichtigen.
- Nutzen Sie sie als einzige Source of Truth für die installierten Versionen.
Ohne eine Lockfile können zwei Installationen desselben package.json unterschiedliche Trees erzeugen, wodurch ein Bug, der nur in der Produktion auftritt, nahezu unmöglich zu reproduzieren ist.
Abhängigkeiten installieren
Die beiden wichtigsten Installationsbefehle haben unterschiedliche Zwecke.
# development: resolve ranges, may update the lockfile
npm install
# CI and clean environments: exact install from the lockfile
npm ci
# add a runtime dependency
npm install zod
# add a development tool
npm install -D vitest
npm ci löscht node_modules, installiert strikt aus der Lockfile und bricht ab, wenn package.json und die Lockfile nicht übereinstimmen. Das macht den Vorgang in der CI sowohl schneller als auch sicherer. Verwende npm install lokal, wenn du Abhängigkeiten änderst.
Scripts
Scripts sind benannte Befehle, die über npm run ausgeführt werden. Sie ermöglichen es einem Projekt, eine konsistente Schnittstelle für alle Beteiligten bereitzustellen, einschließlich der CI.
npm run dev
npm run build
npm test # shorthand for npm run test
Scripts können lokale Binaries direkt aufrufen, sodass "dev": "vite" ohne eine globale Installation funktioniert. Sie lassen sich zudem kombinieren: ein ci-Script kann beispielsweise Linting, Tests und den Build-Prozess nacheinander ausführen. Wenn diese Befehle in package.json hinterlegt sind, muss sich niemand mehr an den exakten Aufruf erinnern.
npx und Workspaces
npx führt eine Package-Binary aus, ohne dass eine globale Installation erforderlich ist, was ideal für Tools ist, die man nur einmalig benötigt.
npx create-vite@latest my-app
npx eslint .
Workspaces ermöglichen es, mehrere Packages in einem einzigen Repository zu verwalten, die sich eine gemeinsame node_modules und Lockfile teilen.
{
"workspaces": ["packages/*", "apps/*"]
}
npm verknüpft die Packages miteinander, sodass ein Workspace von einem benachbarten Package abhängen kann, ohne dass dieses veröffentlicht werden muss. Für größere Monorepos ergänzen Tools wie Turborepo zusätzliche Funktionen wie Caching und Task-Orchestrierung.
Sicherheit und Wartung
npm enthält einen Audit-Befehl, mit dem dein Dependency-Tree auf bekannte Sicherheitslücken überprüft werden kann.
npm audit
npm audit fix
npm outdated
Führe Audits regelmäßig durch und lies die Ergebnisse sorgfältig, anstatt blind fix auszuführen, da dies zu Breaking Changes führen kann. npm outdated zeigt dir, für welche Abhängigkeiten neuere Versionen verfügbar sind, was dir hilft, Upgrades geplant anzugehen, anstatt sie aufstauen zu lassen.
Best Practices
- Committe
package-lock.jsonund bearbeite es niemals manuell. - Nutze
npm ciin der CI undnpm installnur bei Änderungen an den Dependencies. - Halte dependencies und devDependencies strikt getrennt.
- Bevorzuge Caret-Ranges und überlasse das Fixieren exakter Versionen der Lockfile.
- Definiere Scripts für jede gängige Aufgabe.
- Führe
npm auditundnpm outdatedregelmäßig nach einem Zeitplan aus. - Nutze Workspaces für Monorepos anstelle von separaten Repositories.
Häufige Fehler
- Das Löschen der Lockfile, um Installationsprobleme zu “beheben”.
- Das Ausführen von
npm installin der CI, was zu nicht reproduzierbaren Builds führt. - Das Platzieren von Build-Tools in
dependencies, was die Runtime-Installationen aufbläht. - Das Ignorieren von Audit-Warnungen, bis sie kritisch werden.
- Das globale Installieren von Paketen, obwohl
npxoder eine devDependency ausreichen würden. - Das Bearbeiten von
node_modulesin der Erwartung, dass die Änderungen dauerhaft gespeichert bleiben.
Wie geht es weiter?
npm ist das Fundament der JavaScript-Toolchain. Vergleiche es mit pnpm in Bezug auf Geschwindigkeit und Speicherplatzeffizienz, verstehe die Node.js-Runtime, mit der es ausgeliefert wird, und ergänze Turborepo, wenn dein Repository zu einem Monorepo anwächst. Bereinige anschließend die Skripte eines Projekts, sodass das gesamte Team einen einheitlichen Satz an Befehlen nutzt.