package.json: ~ versus ^

Node.js verwendet das Konzept des Semantic Versioning für die Versionierung von Modulen. Bei Bedarf lassen sich in der Datei package.json dafür auch Bereiche angeben, beispielsweise mit den Zeichen ~ und ^. Was ist der Unterschied zwischen den beiden Varianten?

In Pocket speichern vorlesen Druckansicht 2 Kommentare lesen
Lesezeit: 3 Min.
Von
  • Golo Roden
Inhaltsverzeichnis

Node.js verwendet das Konzept des Semantic Versioning für die Versionierung von Modulen. Bei Bedarf lassen sich in der Datei package.json dafür auch Bereiche angeben, beispielsweise mit den Zeichen ~ und ^. Was ist der Unterschied zwischen den beiden Varianten?

Als im Februar 2014 die Version 0.10.26 von Node.js erschienen ist, steckte eine der gravierendsten Neuerungen in der mitgelieferten Paketverwaltung npm. Installierte man ein Modul unter Angabe des Parameters --save, wurde die Versionsnummer in der Datei package.json nicht länger mit einer Tilde versehen, sondern mit einem Einfügezeichen (Caret).

Seither führt beispielsweise der Aufruf von

$ npm install express --save

zu einem Eintrag der Form:

"dependencies": {
"express": "^4.15.2"
}

Früher hätte npm die Abhängigkeit wie folgt eingetragen:

"dependencies": {
"express": "~4.15.2"
}

Was ist der Unterschied zwischen den beiden Varianten?

Das Caret bedeutet, dass entweder die angeforderte Version zu installieren ist, oder eine dazu kompatible neuere. Ob zwei Versionen zueinander kompatibel sind, ergibt sich dank Semantic Versioning auf einen Blick. Daher könnte npm statt Express 4.15.2 auch die Versionen 4.15.3, 4.15.4 oder 4.16.0 installieren – nicht aber 5.0.0.

Der Wechsel der Hauptversionsnummer deutet auf eine inkompatible Änderung hin. Daher ist der Ausdruck

^4.15.2

letztlich gleichbedeutend zu dem in package.json ebenfalls gültigen Ausdruck:

>= 4.15.2 < 5.0.0

Das Vorgehen ist sinnvoll, um beispielsweise die neuesten Fehlerkorrekturen zu erhalten, inkompatible Änderungen jedoch zu vermeiden.

Anders verhält sich hingegen die Tilde. Sie bedeutet, dass entweder die angeforderte oder eine ähnliche Version zu installieren ist. In dem Fall bedeutet "ähnlich", dass die letzte angegeben Versionsnummer variabel ist. Daher könnte npm anstelle von Express 4.15.2 auch die Versionen 4.15.3 oder 4.15.4 installieren, nicht jedoch 4.16.0, und schon gar nicht 5.0.0.

Die Tilde schützt also nicht nur vor inkompatiblen Änderungen, sondern verhindert auch den Wechsel auf eine neuere Version, die zwar Erweiterungen, aber keine Fehlerkorrekturen enthält.

Der vor drei Jahren erfolgte Wechsel ist durchaus sinnvoll, allerdings stellt sich generell die Frage, ob das Abweichen von einer strikten Versionsnummer eine gute Idee ist. Der alternative Installer Yarn beispielsweise fixiert die installierten Versionen in einem sogenannten Lock-File, und auch die kommende Version 5 von npm wird einen ähnlichen Mechanismus enthalten.

Das Festzurren von Versionsnummern sorgt in jedem Fall dafür, verlässlichere und besser reproduzierbare Builds zu erhalten. Das Prüfen und Aktualisieren auf neuere Versionen kann man dann getrost einem Werkzeug überlassen, was diese Aufgabe automatisiert übernimmt.

tl;dr: Das Caret installiert eine kompatible Version, die Tilde eine ähnliche Version. Beide Vorgehensweisen sind allerdings zu hinterfragen, wenn man reproduzierbare Builds anstrebt. In dem Fall sollte mit festen Versionen und gegebenenfalls einem Lock-File gearbeitet werden. ()