Back

Ein praktisches CI-Setup für Node.js-Projekte

Ein praktisches CI-Setup für Node.js-Projekte

Jedes Node.js-Projekt erreicht einen Punkt, an dem manuelles Testen unzuverlässig wird. Jemand vergisst, den Linter vor dem Push auszuführen. Tests laufen lokal durch, schlagen aber auf dem Rechner eines Teammitglieds fehl. Ein Dependency-Update bringt die Produktionsumgebung zum Absturz, weil niemand die Inkompatibilität bemerkt hat.

Eine gut strukturierte CI-Pipeline fängt diese Probleme automatisch ab. Dieser Artikel erklärt, wie ein solides Basis-CI-Setup für Node.js mit GitHub Actions aussieht, warum jede Komponente existiert und wie Sie über die einzelnen Bestandteile nachdenken sollten, damit Ihre Pipeline langfristig wartbar bleibt.

Wichtigste Erkenntnisse

  • Verwenden Sie npm ci statt npm install in CI-Pipelines für deterministische, reproduzierbare Builds basierend auf Ihrer Lockfile
  • Strukturieren Sie Ihre Pipeline nach dem Fail-Fast-Prinzip: Dependencies installieren → Linting und Typecheck → Tests ausführen
  • Testen Sie gegen die Node.js-Versionen, die Sie tatsächlich unterstützen, mithilfe einer Versionsmatrix, wobei der Fokus auf Active-LTS-Releases liegt
  • Führen Sie statische Analysen vor Tests aus, um Fehler schnell zu erkennen und klarere Fehlermeldungen zu erhalten
  • Halten Sie Ihre Pipeline einfach und wartbar, indem Sie überkomplexes Caching und übermäßiges Version-Pinning vermeiden

Was eine JavaScript-CI-Baseline-Pipeline leisten sollte

Eine praktische CI-Pipeline für Node.js-Projekte kümmert sich um drei Aspekte: konsistente Dependencies sicherstellen, Code-Qualität validieren und Tests über relevante Node-Versionen hinweg ausführen.

Die Pipeline sollte schnell und sichtbar fehlschlagen. Wenn etwas kaputtgeht, müssen Entwickler sofort Bescheid wissen und verstehen, warum.

Die Kernphasen

Ein zuverlässiger GitHub Actions Node-CI-Workflow folgt dieser Abfolge:

Dependencies installierenLinting und TypecheckTests ausführen

Jede Phase ist Voraussetzung für die nächste. Es macht keinen Sinn, eine vollständige Test-Suite auszuführen, wenn der Code nicht einmal korrekt geparst werden kann.

Dependency-Installation: Warum npm ci wichtig ist

Die wichtigste npm-CI-Best-Practice ist die Verwendung von npm ci anstelle von npm install in Ihrer Pipeline.

npm ci erfüllt zwei wichtige Funktionen für CI:

  1. Es installiert exakt das, was in Ihrer Lockfile steht – keine Versionsauflösung, keine Überraschungen
  2. Es löscht zunächst node_modules, um einen sauberen Ausgangszustand zu gewährleisten

Dieses deterministische Verhalten bedeutet, dass Ihre CI-Umgebung genau dem entspricht, was Ihre Lockfile spezifiziert. Wenn ein Build fehlschlägt, wissen Sie, dass der Fehler nicht durch Dependency-Drift verursacht wurde.

Ihre Lockfile (package-lock.json für npm, pnpm-lock.yaml für pnpm, yarn.lock für Yarn) muss in Ihr Repository committed sein. Ohne sie funktioniert npm ci nicht, und Sie verlieren die Reproduzierbarkeit.

Package-Manager-Verwaltung mit Corepack

Wenn Ihr Team pnpm oder Yarn verwendet, übernimmt Corepack die Versionierung des Package-Managers. Aktivieren Sie es in Ihrem Workflow, bevor Sie Dependencies installieren. Dies stellt sicher, dass alle – einschließlich CI – dieselbe Package-Manager-Version verwenden, die in Ihrer package.json angegeben ist.

Versionsmatrizen: Testen über Node-Releases hinweg

Eine Versionsmatrix ermöglicht es Ihnen, Ihre Pipeline gleichzeitig gegen mehrere Node.js-Versionen laufen zu lassen. Für die meisten Projekte reicht das Testen gegen die Active-LTS-Version aus. Projekte mit breiteren Kompatibilitätsanforderungen könnten die aktuelle Maintenance-LTS-Version hinzufügen.

Der Matrix-Ansatz fängt Kompatibilitätsprobleme frühzeitig ab. Ein Syntax-Feature, das in neueren Node-Versionen funktioniert, existiert möglicherweise nicht in älteren Versionen, auf die Ihre Nutzer angewiesen sind.

Halten Sie Ihre Matrix minimal. Das Testen gegen jede mögliche Version erhöht die CI-Laufzeit ohne proportionalen Nutzen. Konzentrieren Sie sich auf Versionen, die Ihr Projekt tatsächlich unterstützt.

Linting und Type-Checking vor Tests

Führen Sie statische Analysen vor Ihrer Test-Suite aus. ESLint erkennt Code-Qualitätsprobleme. TypeScript (falls Sie es verwenden) erkennt Typfehler. Beide laufen schneller als die meisten Test-Suites.

Diese Reihenfolge ist aus zwei Gründen wichtig:

  1. Schnelleres Feedback: Syntaxfehler werden in Sekunden sichtbar, nicht in Minuten
  2. Klarere Fehler: Ein Linting-Fehler ist einfacher zu diagnostizieren als ein kryptischer Testfehler, der durch dasselbe zugrunde liegende Problem verursacht wurde

Konfigurieren Sie diese Tools so, dass sie den Build bei Fehlern abbrechen. Warnungen, die den Build nicht fehlschlagen lassen, werden ignoriert.

Testausführung und Fehler-Sichtbarkeit

Ihre Testphase sollte klare Ausgaben produzieren. Wenn Tests fehlschlagen, müssen Entwickler das Problem schnell identifizieren können – idealerweise ohne eingeklappte Log-Bereiche durchsuchen zu müssen.

Die meisten Test-Runner unterstützen CI-freundliche Ausgabeformate. Jest, Vitest und der eingebaute Test-Runner von Node erkennen alle CI-Umgebungen und passen ihre Ausgabe entsprechend an.

Berücksichtigen Sie diese Praktiken:

  • Führen Sie Tests mit Coverage aus nur dann, wenn Sie die Coverage-Daten tatsächlich verwenden werden
  • Parallelisieren Sie Testdateien, wenn Ihr Runner dies unterstützt und Ihre Tests unabhängig sind
  • Fail Fast während Development-Branches und führen Sie die vollständige Suite auf main aus

Caching: Eine Anmerkung zu den Erwartungen

Dependency-Caching kann Installationszeiten reduzieren, aber die Vorteile variieren. Kleine Projekte mit wenigen Dependencies sehen möglicherweise minimale Verbesserungen. Große Monorepos können Minuten pro Durchlauf einsparen.

Überentwickeln Sie das Caching nicht. Das eingebaute Caching in actions/setup-node behandelt gängige Fälle. Wenn Ihre Installationen langsam sind, messen Sie, bevor Sie Komplexität hinzufügen.

Ihre Pipeline wartbar halten

Eine CI-Pipeline, die ständige Updates erfordert, wird zur Last. Vermeiden Sie es, Action-Versionen auf spezifische Patches zu pinnen – verwenden Sie Major-Version-Tags, die kompatible Updates erhalten. Referenzieren Sie Node-Versionen nach ihrer Release-Linie statt nach exakten Versionen, wenn möglich.

Das Ziel ist eine JavaScript-CI-Pipeline, die zuverlässig läuft, ohne häufige Wartung zu benötigen. Wenn Sie sie aktualisieren müssen, sollten die Änderungen absichtlich sein, nicht reaktiv.

Fazit

Ein solides Node.js-CI-Setup erfordert keine aufwendige Konfiguration. Installieren Sie Dependencies deterministisch mit npm ci, führen Sie statische Analysen vor Tests aus und testen Sie gegen die Node-Versionen, die Sie unterstützen. Machen Sie Fehler sichtbar und halten Sie die Pipeline einfach genug, um sie zu warten.

Beginnen Sie mit dieser Baseline. Fügen Sie Komplexität nur hinzu, wenn Sie ein spezifisches Problem zu lösen haben.

FAQs

npm ci installiert exakt das, was Ihre Lockfile spezifiziert, ohne Versionen aufzulösen, und löscht zunächst node_modules für einen sauberen Ausgangszustand. npm install kann die Lockfile aktualisieren und unterschiedliche Versionen auflösen. Für CI bietet npm ci deterministische Builds, die exakt Ihrer committeten Lockfile entsprechen.

Testen Sie gegen Versionen, die Ihr Projekt tatsächlich unterstützt. Für die meisten Projekte reicht die Active-LTS-Version aus. Fügen Sie die Maintenance-LTS hinzu, wenn Sie breitere Kompatibilität benötigen. Vermeiden Sie das Testen gegen jede mögliche Version, da dies die CI-Zeit ohne proportionalen Nutzen erhöht.

Linting läuft schneller als die meisten Test-Suites und erkennt Syntax- und Code-Qualitätsprobleme in Sekunden. Die vorherige Ausführung liefert schnelleres Feedback und erzeugt klarere Fehlermeldungen. Ein Linting-Fehler ist einfacher zu diagnostizieren als ein kryptischer Testfehler, der durch dasselbe zugrunde liegende Problem verursacht wurde.

Das hängt von Ihrer Projektgröße ab. Kleine Projekte mit wenigen Dependencies sehen minimale Verbesserungen durch Caching. Große Monorepos können Minuten pro Durchlauf einsparen. Beginnen Sie mit dem eingebauten Caching in actions/setup-node und messen Sie die tatsächlichen Installationszeiten, bevor Sie Komplexität hinzufügen.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay