Aufwärmen · Aufgabe 1 von 7
// B2.3 · ca. 32 Min. · Einstieg
semver-Bereiche und Updates
Nach dieser Lektion können Sie eine Versionsnummer lesen, in package.json den Bereich schreiben, den Sie meinen, und Abhängigkeiten aktualisieren, ohne von den Änderungen überrascht zu werden.
Danach können Sie
- major.minor.patch lesen: welche Zahl ein Fix, ein Feature oder eine inkompatible Änderung erhöht und wie Prereleases sortieren
- Vorhersagen, was exakte Versionen, ^, ~, x-Bereiche und Prerelease-Bereiche zulassen, auch unter 1.0.0
- npm outdated und npm update verwenden und sagen, was jeder Befehl ändert
Vorhersagen · Aufgabe 2 von 7
Sagen Sie es vorher, bevor Sie weiterlesen. dep1 1.1.1 ist mit der package.json unten installiert. Seitdem sind dep1 1.1.2, 1.2.0 und 1.2.2 erschienen, und 1.2.2 ist als latest markiert. Sie führen npm update aus. Welche Version von dep1 ist danach installiert?
{ "dependencies": { "dep1": "~1.1.1" } }Üben · Aufgabe 3 von 7
Setzen Sie den Operator ein, damit der Bereich 1.4.2 und 1.9.0 zulässt, aber nicht 2.0.0.
"dep1": "____1.4.2""dep1": "1.4.2"Üben · Aufgabe 4 von 7
Ordnen Sie jedem Bereich in package.json die Versionen zu, die er zulässt.
Üben · Aufgabe 5 von 7
Welche dieser Versionen lässt dieser Bereich zu?
"dep1": "^0.2.3"Denksport · Aufgabe 6 von 7
Knobelaufgabe. Die Registry hat dep1 1.4.0-beta.1, 1.4.0-beta.3, 1.4.0, 1.4.7 und 1.5.0-beta.1. Welche Version wählt npm install für diesen Bereich?
"dep1": "^1.4.0-beta.2"Anwenden · Aufgabe 7 von 7
Mini-Aufgabe. Führen Sie in einem neuen Ordner npm init -y aus. Wählen Sie ein kleines Paket und listen Sie seine Versionen mit npm view <package> versions. Installieren Sie eine ältere mit npm install <package>@<version> und sehen Sie nach, welchen Bereich npm in package.json gespeichert hat. Führen Sie npm outdated aus und lesen Sie Current, Wanted und Latest. Führen Sie npm update aus und vergleichen Sie package.json und package-lock.json mit vorher. Wechseln Sie zum Schluss mit npm install <package>@latest auf den neuesten Major.
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Versionen werden als Zahlen verglichen
Bevor npm die höchste Version wählen kann, die ein Bereich erlaubt, muss es wissen, welche Version höher ist. Dieses Programm sortiert vier Versionen zweimal: als Text, wie sort() es standardmäßig tut, und Teil für Teil als Zahlen, so wie semver sie vergleicht. Als Text kommt 1.10.0 zuerst, weil das Zeichen 1 vor 9 sortiert. Es läuft auch im Browser.
main.js
// Versions are compared number by number, not letter by letter.
const versions = ["1.9.0", "1.10.0", "1.2.10", "1.2.9"];
function compare(a, b) {
const x = a.split(".").map(Number);
const y = b.split(".").map(Number);
for (let i = 0; i < 3; i++) {
if (x[i] !== y[i]) return x[i] - y[i];
}
return 0;
}
console.log("as text: ", [...versions].sort().join(" < "));
console.log("as numbers:", [...versions].sort(compare).join(" < "));
console.log("newest:", [...versions].sort(compare).at(-1));
console.log('"1.10.0" > "1.9.0" is', "1.10.0" > "1.9.0");
Ausführen mit
node main.jsAusgabe
as text: 1.10.0 < 1.2.10 < 1.2.9 < 1.9.0
as numbers: 1.2.9 < 1.2.10 < 1.9.0 < 1.10.0
newest: 1.10.0
"1.10.0" > "1.9.0" is false- sort() ohne Funktion vergleicht Strings Zeichen für Zeichen, darum landet "1.10.0" vor "1.2.10".
- compare() prüft major, dann minor, dann patch und geht nur weiter, solange sie gleich sind.
- Dieses compare() kennt keine Prereleases: "0-beta" ist keine Zahl. Das semver-Paket von npm kann sie.
Ändern und ausführen
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Übungen
Übung 1 von 2
Eine Version lesen
Schreiben Sie parseVersion(text). Für eine Version aus drei ganzen Zahlen mit Punkten dazwischen, etwa "1.4.2" oder "10.20.30", liefert sie {major, minor, patch} als Zahlen. Für alles andere liefert sie null: einen Bereich wie "^1.4.2", eine unvollständige Version wie "1.4", ein führendes v wie in "v1.4.2", vier Teile oder ein Prerelease wie "2.0.0-beta.1" (dieser Parser lässt sie aus). Prüfen Sie die Tests mit node --test.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Ein regulärer Ausdruck mit ^ und $ kann verlangen, dass der ganze Text aus Ziffern, Punkt, Ziffern, Punkt, Ziffern besteht: /^(\d+)\.(\d+)\.(\d+)$/.
Hinweis 2
exec() liefert null, wenn der Text nicht passt; geben Sie dann null zurück.
Hinweis 3
Die Gruppen sind Strings. Number(match[1]) macht aus der ersten eine Zahl.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// {major, minor, patch} for a version such as "1.4.2", or null.
export function parseVersion(text) {
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(text);
if (match === null) return null;
return {major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3])};
}
Auf dem eigenen Computer ausführen
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// {major, minor, patch} for a version such as "1.4.2", or null.
export function parseVersion(text) {
return null;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {parseVersion} from './main.js';
test('zerlegt 1.4.2 in drei Zahlen', () => {
assert.deepEqual(parseVersion('1.4.2'), {major: 1, minor: 4, patch: 2}, `parseVersion('1.4.2') lieferte ${JSON.stringify(parseVersion('1.4.2'))}`);
});
test('liest Zahlen mit mehr als einer Stelle', () => {
assert.deepEqual(parseVersion('10.20.30'), {major: 10, minor: 20, patch: 30}, `parseVersion('10.20.30') lieferte ${JSON.stringify(parseVersion('10.20.30'))}`);
});
test('liefert null für Bereiche und anderen Text, der keine einfache Version ist', () => {
for (const text of ['^1.4.2', '1.4', 'v1.4.2', '1.4.2.0', '2.0.0-beta.1', '1.x.0', '']) {
assert.equal(parseVersion(text), null, `parseVersion(${JSON.stringify(text)}) lieferte ${JSON.stringify(parseVersion(text))}, erwartet: null`);
}
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 2 von 2
Ein Caret-Bereich, von Hand
parseVersion ist fertig. Schreiben Sie allowsCaret(range, version) für einen Caret-Bereich mit Major 1 oder höher, etwa "^1.4.2": Die Funktion liefert true, wenn version denselben Major hat und nicht kleiner ist als die Version des Bereichs. "^1.4.2" erlaubt also 1.4.2, 1.9.0 und 1.10.0, aber nicht 1.4.1, 1.3.9 oder 2.0.0. Vergleichen Sie die Teile als Zahlen. Bereiche unter 1.0.0 und Prereleases gehören nicht dazu; die übernimmt das semver-Paket von npm.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
range.slice(1) entfernt das ^, und parseVersion macht aus beiden Strings Zahlen.
Hinweis 2
Ein anderer Major ist nie erlaubt. Bei gleichem Major ist ein höherer Minor immer erlaubt.
Hinweis 3
Bei gleichem Major und Minor muss der Patch gleich oder höher sein.
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// {major, minor, patch} for a version such as "1.4.2", or null.
export function parseVersion(text) {
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(text);
if (match === null) return null;
return {major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3])};
}
// true if version is allowed by a caret range such as "^1.4.2" (major 1 or more).
export function allowsCaret(range, version) {
const base = parseVersion(range.slice(1));
const v = parseVersion(version);
if (v.major !== base.major) return false;
if (v.minor !== base.minor) return v.minor > base.minor;
return v.patch >= base.patch;
}
Auf dem eigenen Computer ausführen
Installieren Sie Node.js 24 LTS oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// {major, minor, patch} for a version such as "1.4.2", or null.
export function parseVersion(text) {
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(text);
if (match === null) return null;
return {major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3])};
}
// true if version is allowed by a caret range such as "^1.4.2" (major 1 or more).
export function allowsCaret(range, version) {
return false;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {allowsCaret} from './main.js';
test('erlaubt die Version selbst und neuere Minors und Patches', () => {
for (const v of ['1.4.2', '1.4.9', '1.9.0']) {
assert.equal(allowsCaret('^1.4.2', v), true, `allowsCaret('^1.4.2', '${v}') sollte true sein`);
}
});
test('vergleicht Zahlen, keinen Text: 1.10.0 ist neuer als 1.4.2', () => {
assert.equal(allowsCaret('^1.4.2', '1.10.0'), true, `allowsCaret('^1.4.2', '1.10.0') sollte true sein`);
});
test('lehnt kleinere Versionen ab', () => {
for (const v of ['1.4.1', '1.3.9', '0.9.9']) {
assert.equal(allowsCaret('^1.4.2', v), false, `allowsCaret('^1.4.2', '${v}') sollte false sein`);
}
});
test('lehnt einen neuen Major ab', () => {
assert.equal(allowsCaret('^1.4.2', '2.0.0'), false, `allowsCaret('^1.4.2', '2.0.0') sollte false sein`);
assert.equal(allowsCaret('^2.0.0', '2.5.1'), true, `allowsCaret('^2.0.0', '2.5.1') sollte true sein`);
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenHäufige Fehler
Einen Bereich lesen, als wäre er eine Version
// {major, minor, patch} for a version such as "1.4.2", or null.
function parseVersion(text) {
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(text);
if (match === null) return null;
return {major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3])};
}
const dependencies = {dep1: "^1.4.2"};
console.log("dep1 major:", parseVersion(dependencies.dep1).major);
Was Node.js ausgibt
TypeError: Cannot read properties of null (reading 'major')Warum, und die Lösung
"^1.4.2" in package.json ist ein Bereich, keine Version, darum liefert der Parser null, und .major scheitert. Die wirklich installierte Version steht in package-lock.json und in node_modules/dep1/package.json. Prüfen Sie ein Ergebnis auf null, bevor Sie es verwenden, und geben Sie einen Bereich nur an Code, der Bereiche versteht, etwa die Funktion satisfies() aus dem semver-Paket von npm.
semver importieren, ohne es zu installieren
import semver from "semver";
console.log(semver.satisfies("1.9.0", "^1.4.2"));
Was Node.js ausgibt
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'semver' imported fromWarum, und die Lösung
npm bringt eine eigene Kopie von semver mit, aber diese Kopie liegt in npm, nicht in Ihrem Projekt, also findet Node.js sie nicht. Installieren Sie das Paket zuerst ins Projekt: npm install semver. Das trägt es in "dependencies" und node_modules ein, dann funktioniert der Import und gibt true aus.
Ein Parser, der Prereleases vergisst
// The three numbers of a version such as 1.4.2.
function parts(version) {
return version.match(/^(\d+)\.(\d+)\.(\d+)$/).slice(1).map(Number);
}
console.log(parts("1.4.2"));
console.log(parts("2.0.0-beta.1"));
Was Node.js ausgibt
TypeError: Cannot read properties of null (reading 'slice')Warum, und die Lösung
2.0.0-beta.1 ist eine gültige Version: ein Prerelease mit dem Tag beta.1. Das Muster erlaubt nur drei Zahlen, also liefert match() null, und .slice scheitert. Erlauben Sie entweder ein Tag nach einem Bindestrich, wie in /^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?$/, oder prüfen Sie auf null und melden Sie die Version, die Sie nicht lesen können. Denken Sie daran: 2.0.0-beta.1 sortiert vor 2.0.0.
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.