mitmario.dev

Versionen verstehen

Node.js Sandbox 3 Min Lesezeit 3 BeispieleLektion 3 von 7

In deiner package.json steht nicht einfach eine Version, sondern ein Bereich. Und dieser Bereich entscheidet, welchen fremden Code dein Projekt bei der nächsten frischen Installation bekommt.

Das ist keine Kleinigkeit. Es heißt, dass in deinem Projekt gleich Code landen kann, den du nie gesehen hast.

Die drei Zahlen

Eine Version wie 1.4.2 besteht aus drei Teilen, und jeder gibt ein Versprechen ab.

Major (die 1) bricht. Wenn diese Zahl steigt, darf sich alles ändern. Funktionen können verschwinden, Aufrufe anders aussehen. Dein Code muss vielleicht angepasst werden.

Minor (die 4) ergänzt. Es kommt etwas dazu, aber alles Bisherige funktioniert weiter.

Patch (die 2) repariert. Ein Fehler ist behoben, sonst ändert sich nichts.

Diese Verabredung heißt Semantic Versioning, kurz Semver. Sie ist der Grund, warum du überhaupt einen Bereich angeben kannst, statt jede Version einzeln zu prüfen.

Das Dach

Ein ^ vor der Version ist die Voreinstellung. npm install schreibt es von sich aus hin.

Was ^1.4.2 hereinlässt
const kandidaten = ["1.4.1", "1.4.2", "1.4.9", "1.7.0", "2.0.0"];

for (const version of kandidaten) {
  const [major, minor, patch] = version.split(".").map(Number);
  const erlaubt = major === 1 && (minor > 4 || (minor === 4 && patch >= 2));

  console.log(`${version.padEnd(6)} ${erlaubt ? "ja" : "nein"}`);
}

^1.4.2 heißt: alles ab 1.4.2 bis unter 2.0.0.

Achte auf die beiden Ränder. 1.4.1 ist zu alt und fällt raus, obwohl es dieselbe Minor-Version ist: Der Bereich beginnt bei der genannten Version, nicht bei der Minor-Reihe. Und 2.0.0 fällt raus, weil dort das Bruchversprechen greift.

1.7.0 ist dagegen drin. Das ist der Punkt, an dem viele stutzen: Du bekommst eine Minor-Version, die es zum Zeitpunkt deines npm install noch gar nicht gab, mit Funktionen, die du nie angeschaut hast.

Die Tilde

Was ~1.4.2 anders macht
const kandidaten = ["1.4.1", "1.4.2", "1.4.9", "1.7.0", "2.0.0"];

for (const version of kandidaten) {
  const [major, minor, patch] = version.split(".").map(Number);
  const erlaubt = major === 1 && minor === 4 && patch >= 2;

  console.log(`${version.padEnd(6)} ${erlaubt ? "ja" : "nein"}`);
}

~1.4.2 ist enger: alles ab 1.4.2 bis unter 1.5.0. Nur Patches also, nur Fehlerbehebungen.

Der Unterschied zeigt sich an genau einer Zeile: 1.7.0 ist beim Dach erlaubt und bei der Tilde nicht.

Und ganz ohne Zeichen davor, also 1.4.2, ist es festgenagelt: genau diese Version, sonst keine.

Der Sonderfall unter 1.0.0

Der Sonderfall unterhalb von 1.0.0
const kandidaten = ["0.4.1", "0.4.2", "0.4.9", "0.5.0", "1.0.0"];

for (const version of kandidaten) {
  const [major, minor, patch] = version.split(".").map(Number);
  const erlaubt = major === 0 && minor === 4 && patch >= 2;

  console.log(`${version.padEnd(6)} ${erlaubt ? "ja" : "nein"}`);
}

Hier verhält sich das Dach plötzlich wie eine Tilde. ^0.4.2 erlaubt nur bis unter 0.5.0, obwohl das eine Minor-Erhöhung ist.

Der Grund steht in der Semver-Verabredung selbst: Vor 1.0.0 gilt ein Projekt als noch nicht gefestigt, und dort darf jede Minor-Erhöhung brechen. Die Minor-Stelle übernimmt also die Rolle der Major-Stelle.

Praktisch heißt das: Ein Paket in 0.x ist nicht automatisch schlecht, aber es gibt dir weniger Sicherheit. Ein ^ schützt dich dort nur eine Stelle weit.

Warum es trotzdem manchmal knallt

Jetzt der wichtigste Satz dieser Lektion.

Semver ist ein Versprechen, kein Mechanismus. Nichts an npm prüft, ob eine Version hält, was ihre Nummer verspricht. Ein Mensch entscheidet beim Veröffentlichen, welche Zahl er hochzählt, und Menschen schätzen sich falsch ein.

Deshalb bricht gelegentlich ein Patch etwas. Nicht aus Bosheit, sondern weil jemand einen Fehler behoben hat, auf dessen genaues Verhalten sich jemand anders verlassen hatte.

Und deshalb reicht ein Versionsbereich allein nicht aus, um eine Installation reproduzierbar zu machen. Was dafür wirklich sorgt, ist die Datei aus der nächsten Lektion.

Zum Mitnehmen

Semver ist ein Versprechen, kein Mechanismus. Eingehalten wird es von Menschen, und deshalb bricht auch mal ein Patch etwas.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, auf dem Server geprüft

    Öffnet sich mit dem Basis Konto.