Zum Inhalt springen
aviral gupta

// B2.1 · ca. 34 Min. · Einstieg

package.json und npm-Skripte

Nach dieser Lektion können Sie eine package.json anlegen und lesen, ihre Skripte mit npm ausführen und entscheiden, wann node --run genügt.

Lektion 1 von 5 in B2 npm und Pakete

Anfang des Moduls

Danach können Sie

  • package.json mit npm init -y anlegen und name, version, private, type, dependencies und devDependencies lesen
  • Skripte mit npm run, npm test und npm start ausführen, Argumente nach -- übergeben und pre- und post-Skripte vorhersagen
  • Zwischen npm run und node --run wählen und wissen, was node --run absichtlich weglässt
  1. Aufwärmen · Aufgabe 1 von 7

    Aufwärmen: Sie führen npm init -y in einem leeren Ordner aus, mit npm 11.19.0. Welche dieser Felder stehen in der neuen package.json? Wählen Sie alle zutreffenden.

    Wählen Sie alle zutreffenden aus.

  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. Das ist die package.json, und step.js gibt die Wörter aus, die es erhält. Sie führen npm run -s build aus (-s blendet nur die eigenen >-Zeilen von npm aus). Was erscheint, Zeile für Zeile?

    {
      "name": "demo",
      "version": "1.0.0",
      "scripts": {
        "prebuild": "node step.js pre",
        "build": "node step.js build",
        "postbuild": "node step.js post"
      }
    }
  3. Üben · Aufgabe 3 von 7

    Das Skript "greet" ist node greet.js. Füllen Sie die Lücke so, dass greet.js --name Ada erhält und npm --name nicht für eine eigene Option hält.

    npm run greet ____ --name Ada
    npm run greet --name Ada
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem Eintrag der package.json zu, was er bewirkt.

  5. Üben · Aufgabe 5 von 7

    In diesem Projekt tippen Sie npm run dev. Was passiert?

    {
      "name": "demo",
      "version": "1.0.0",
      "scripts": {
        "start": "node main.js",
        "test": "node --test"
      }
    }
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Dasselbe Projekt wie vorhin: "prebuild", "build" und "postbuild" führen jeweils step.js aus. Was gibt dieser Befehl aus?

    node --run build
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Führen Sie in einem neuen Ordner npm init -y aus. Ändern Sie in der package.json "type" auf "module", ergänzen Sie "private": true, ersetzen Sie das Skript "test" durch node --test und fügen Sie ein Skript "pretest" hinzu, das echo checking ausführt. Schreiben Sie sum.js mit einer exportierten Funktion sum und sum.test.js mit einem Test. Führen Sie npm test aus, dann node --run test, und vergleichen Sie die Ausgaben.

    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

npm run und node --run nebeneinander

Dieses Programm spielt Ihr Terminal. Es schreibt ein kleines Projekt in einen temporären Ordner: ein Skript "build" mit "prebuild" und "postbuild", die alle step.js ausführen; step.js gibt die erhaltenen Wörter und die Variable npm_package_version aus. Dann führt es denselben Befehl mit npm run und mit node --run aus und gibt aus, was jeweils auf stdout erschien. Sie brauchen Node.js und npm, aber kein Netzwerk.

main.js

// Plays the part of your terminal: makes a small project in a temporary
// folder and runs the same script with npm run and with node --run.
import {execSync} from "node:child_process";
import {mkdtempSync, writeFileSync} from "node:fs";
import {tmpdir} from "node:os";
import {join} from "node:path";

const dir = mkdtempSync(join(tmpdir(), "scripts-"));
const pkg = {
  name: "demo",
  version: "1.0.0",
  private: true,
  scripts: {
    prebuild: "node step.js prebuild",
    build: "node step.js build",
    postbuild: "node step.js postbuild"
  }
};
writeFileSync(join(dir, "package.json"), JSON.stringify(pkg, null, 2));
// step.js prints the words it got and the version that npm passes on.
writeFileSync(join(dir, "step.js"), 'console.log(process.argv.slice(2).join(" "), "| version:", process.env.npm_package_version);\n');

for (const command of ["npm run build -- --fast", "node --run build -- --fast"]) {
  console.log("$ " + command);
  console.log(execSync(command, {cwd: dir, encoding: "utf8"}).trim());
}

Ausführen mit

node main.js

Ausgabe

$ npm run build -- --fast
> demo@1.0.0 prebuild
> node step.js prebuild

prebuild | version: 1.0.0

> demo@1.0.0 build
> node step.js build --fast

build --fast | version: 1.0.0

> demo@1.0.0 postbuild
> node step.js postbuild

postbuild | version: 1.0.0
$ node --run build -- --fast
build --fast | version: undefined
  • npm run gibt vor jedem Skript > demo@1.0.0 und den Befehl aus; npm run -s würde diese Zeilen ausblenden.
  • --fast erreicht nur build: npm gibt Argumente nach -- an das genannte Skript weiter, nicht an prebuild oder postbuild.
  • node --run hat nur build ausgeführt, und npm_package_version ist dort undefined: Es setzt keine npm_-Variablen.
  • Beide Befehle haben --fast an denselben Eintrag "build" der package.json angehängt.

Übungen

Übung 1 von 2

Was npm run ausführen wird

Schreiben Sie runOrder(pkg, name). pkg ist eine eingelesene package.json. Geben Sie die Skriptnamen zurück, die npm run <name> ausführt, in Reihenfolge: pre<name>, falls vorhanden, dann <name>, dann post<name>, falls vorhanden. Fehlt <name> in "scripts" oder gibt es gar kein "scripts", werfen Sie einen Error mit der Meldung Missing script: "<name>", wie npm. Die letzte Zeile von main.js gibt die Reihenfolge für ein kleines Projekt aus.

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
  1. Hinweis 1

    Verwenden Sie pkg.scripts ?? {}, damit eine package.json ohne "scripts" Ihren Code nicht abstürzen lässt.

  2. Hinweis 2

    name in scripts sagt Ihnen, ob ein Skript existiert. Werfen Sie zuerst, wenn nicht.

  3. Hinweis 3

    Bilden Sie die drei möglichen Namen "pre" + name, name und "post" + name, und behalten Sie nur die, die in scripts stehen.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

// The script names that npm run <name> runs, in order.
export function runOrder(pkg, name) {
  const scripts = pkg.scripts ?? {};
  if (!(name in scripts)) throw new Error('Missing script: "' + name + '"');
  return ["pre" + name, name, "post" + name].filter((script) => script in scripts);
}

const pkg = {scripts: {prebuild: "node clean.js", build: "node build.js", postbuild: "echo done"}};
console.log(runOrder(pkg, "build"));
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

// The script names that npm run <name> runs, in order.
export function runOrder(pkg, name) {
  return [name];
}

const pkg = {scripts: {prebuild: "node clean.js", build: "node build.js", postbuild: "echo done"}};
console.log(runOrder(pkg, "build"));

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runOrder} from './main.js';

const pkg = {
  name: 'demo',
  scripts: {prebuild: 'node clean.js', build: 'node build.js', postbuild: 'echo done', test: 'node --test', posttest: 'echo tested', start: 'node main.js'}
};

test('führt prebuild, build und postbuild in dieser Reihenfolge aus', () => {
  const got = runOrder(pkg, 'build');
  assert.deepEqual(got, ['prebuild', 'build', 'postbuild'], `runOrder(pkg, "build") lieferte ${JSON.stringify(got)}`);
});

test('lässt ein pre- oder post-Skript weg, das es nicht gibt', () => {
  const test = runOrder(pkg, 'test');
  assert.deepEqual(test, ['test', 'posttest'], `runOrder(pkg, "test") lieferte ${JSON.stringify(test)}`);
  const start = runOrder(pkg, 'start');
  assert.deepEqual(start, ['start'], `runOrder(pkg, "start") lieferte ${JSON.stringify(start)}`);
});

test('wirft Missing script für ein Skript, das es nicht gibt', () => {
  assert.throws(() => runOrder(pkg, 'dev'), {message: 'Missing script: "dev"'}, 'runOrder(pkg, "dev") sollte einen Error mit der Meldung Missing script: "dev" werfen');
});

test('wirft auch, wenn package.json gar kein "scripts" hat', () => {
  assert.throws(() => runOrder({name: 'empty'}, 'test'), {message: 'Missing script: "test"'}, 'runOrder({name: "empty"}, "test") sollte Missing script: "test" werfen');
});

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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Übung 2 von 2

Prüfen, was npm init -y geliefert hat

Schreiben Sie checkPackage(pkg), das für eine eingelesene package.json eine Liste von Problemen liefert, in dieser Reihenfolge: 'type: set it to "module"', wenn "type" nicht "module" ist; 'private: set it to true', wenn "private" nicht true ist; 'test: write a real test script', wenn es kein Skript "test" gibt oder es noch der Platzhalter von npm init -y ist, der in PLACEHOLDER steht. Eine package.json ohne Probleme ergibt [].

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
  1. Hinweis 1

    Prüfen Sie die drei Regeln nacheinander mit if und fügen Sie mit push die Meldung jeder verletzten Regel hinzu.

  2. Hinweis 2

    pkg.private !== true ist auch dann wahr, wenn "private" fehlt.

  3. Hinweis 3

    pkg.scripts?.test ist undefined, wenn es kein Objekt "scripts" gibt; !test deckt also beide fehlenden Fälle ab.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

// The "test" script that npm init -y writes.
const PLACEHOLDER = 'echo "Error: no test specified" && exit 1';

export function checkPackage(pkg) {
  const problems = [];
  if (pkg.type !== "module") problems.push('type: set it to "module"');
  if (pkg.private !== true) problems.push("private: set it to true");
  const test = pkg.scripts?.test;
  if (!test || test === PLACEHOLDER) problems.push("test: write a real test script");
  return problems;
}

console.log(checkPackage({name: "demo", version: "1.0.0", type: "commonjs", scripts: {test: PLACEHOLDER}}));
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

// The "test" script that npm init -y writes.
const PLACEHOLDER = 'echo "Error: no test specified" && exit 1';

export function checkPackage(pkg) {
  const problems = [];
  return problems;
}

console.log(checkPackage({name: "demo", version: "1.0.0", type: "commonjs", scripts: {test: PLACEHOLDER}}));

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {checkPackage} from './main.js';

// Exactly what npm init -y wrote with npm 11.19.0.
const fromInit = {
  name: 'demo',
  version: '1.0.0',
  description: '',
  main: 'index.js',
  scripts: {test: 'echo "Error: no test specified" && exit 1'},
  keywords: [],
  author: '',
  license: 'ISC',
  type: 'commonjs'
};

test('findet alle drei Probleme in dem, was npm init -y schreibt', () => {
  const got = checkPackage(fromInit);
  assert.deepEqual(got, ['type: set it to "module"', 'private: set it to true', 'test: write a real test script'], `checkPackage(fromInit) lieferte ${JSON.stringify(got)}`);
});

test('liefert eine leere Liste für eine fertige package.json', () => {
  const got = checkPackage({name: 'demo', version: '1.0.0', private: true, type: 'module', scripts: {test: 'node --test'}});
  assert.deepEqual(got, [], `eine fertige package.json ergab ${JSON.stringify(got)}`);
});

test('behandelt ein fehlendes Skript test wie den Platzhalter', () => {
  const got = checkPackage({private: true, type: 'module'});
  assert.deepEqual(got, ['test: write a real test script'], `eine package.json ohne scripts ergab ${JSON.stringify(got)}`);
});

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.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Ein Komma nach dem letzten Eintrag der package.json

// package.json as it was saved, with a comma after the last script.
const text = `{
  "name": "demo",
  "scripts": {
    "start": "node main.js",
  }
}`;
const pkg = JSON.parse(text);
console.log(pkg.scripts.start);

Was Node.js ausgibt

SyntaxError: Expected double-quoted property name in JSON at position 66 (line 5 column 3)

Warum, und die Lösung

package.json ist JSON, kein JavaScript: kein Komma nach dem letzten Eintrag und keine Kommentare. JSON.parse lehnt diesen Text ab, und npm ebenso: npm start bricht mit npm error code EJSONPARSE ab, mit dem Hinweis, dass package.json echtes JSON sein muss. Löschen Sie das Komma nach "node main.js".

Sich unter node --run auf ein pre-Skript verlassen

// main.js, started by the "build" script. The "prebuild" script writes
// version.txt first, but only npm run build runs prebuild.
import {readFileSync} from "node:fs";

const version = readFileSync("version.txt", "utf8").trim();
console.log("building version", version);

Was Node.js ausgibt

Error: ENOENT: no such file or directory, open 'version.txt'

Warum, und die Lösung

npm run build führt vor build das Skript prebuild aus, das version.txt schreibt. node --run build führt nur build aus, also fehlt die Datei, genau wie bei node main.js von Hand. Starten Sie ein solches Projekt mit npm run build, oder machen Sie den Schritt in einem Skript sichtbar: "build": "node version.js && node main.js".

npm_package_version unter node --run lesen

// main.js, started by "start": "node main.js". npm start sets
// npm_package_version; node --run start and node main.js do not.
const [major] = process.env.npm_package_version.split(".");
console.log("major version", major);

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'split')

Warum, und die Lösung

npm setzt für seine Skripte npm_package_name, npm_package_version und npm_lifecycle_event. node --run lässt sie absichtlich weg und setzt nur NODE_RUN_SCRIPT_NAME und NODE_RUN_PACKAGE_JSON_PATH, daher ist die Variable undefined. Damit das Programm unabhängig vom Startweg funktioniert, lesen Sie die Version aus der package.json selbst statt aus der Umgebung.

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.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

package.json beschreibt das Projekt

npm init -y schreibt eine package.json, ohne zu fragen: "name" aus dem Ordnernamen, "version" 1.0.0, ein Platzhalter-Skript "test" und, mit npm 11.19.0, "type": "commonjs", den Standardwert der npm-Einstellung init-type. "type" liest Node.js: "module" macht .js-Dateien zu ES-Modulen, wie dieser Kurs sie verwendet; ändern Sie es also. "name" und "version" sind nur zum Veröffentlichen Pflicht; "private": true lässt npm das Veröffentlichen ganz verweigern. "dependencies" listet Pakete, die das Programm zum Laufen braucht, "devDependencies" Werkzeuge nur für die Entwicklung, etwa eine Testbibliothek. package.json ist striktes JSON: keine Kommentare und kein Komma nach dem letzten Eintrag.

npm run führt ein Skript aus, mit pre und post

npm run build führt den Befehl aus, der unter "build" in "scripts" steht: in einer Shell, im Ordner der package.json, mit node_modules/.bin im PATH. Vorher gibt npm > demo@1.0.0 build und den Befehl aus; -s blendet diese Zeilen aus. npm run allein listet die Skripte. npm test und npm start sind Kurzformen für npm run test und npm run start; ohne Skript "start", aber mit einer server.js, führt npm start node server.js aus. Zu jedem Skript führt npm außerdem pre<name> davor und post<name> danach aus, sofern es sie gibt. Argumente nach -- erreichen nur das Skript selbst, nicht sein pre- oder post-Skript. Ohne -- hält npm --fast für eine eigene Option.

node --run ist absichtlich kleiner

node --run build führt denselben Eintrag "build" aus und hängt Argumente nach -- an. Die Node.js-Doku listet, was es absichtlich weglässt: pre- und post-Skripte und die Umgebungsvariablen des Paketmanagers. npm_package_version und npm_lifecycle_event sind im Skript also undefined; node --run setzt stattdessen NODE_RUN_SCRIPT_NAME. Es gibt keine >-Zeilen aus und kennt keinen Rückgriff auf server.js. Ein Flag ohne -- nach dem Skriptnamen geht an node selbst: node --run build --fast bricht mit node: bad option: --fast ab. Nehmen Sie node --run für einfache Befehle und npm run, wenn ein Projekt auf pre- oder post-Skripte oder npm_-Variablen angewiesen ist.

Quellen

Zuletzt geprüft am 30. September 2026