Optimierung von CI/CD für Full-Stack-Projekte: Nutzung des Remote Caching und On-Demand Builds von Turborepo
Lukas Schneider
DevOps Engineer · Leapcell

Einleitung
Moderne Full-Stack-JavaScript-Anwendungen werden immer komplexer und übernehmen zunehmend eine Monorepo-Architektur zur Verwaltung mehrerer voneinander abhängiger Dienste, Frontend-Anwendungen und freigegebener Bibliotheken. Während Monorepos erhebliche Vorteile in Bezug auf Code-Sharing und vereinfachtes Dependencymanagement bieten, können sie auch Herausforderungen mit sich bringen, insbesondere in Continuous Integration/Continuous Delivery (CI/CD)-Pipelines. Ein häufiger Engpass sind die Zeit und die Ressourcen, die bei jedem Commit für den erneuten Aufbau unveränderter Teile der Codebasis verschwendet werden. Stellen Sie sich ein Szenario vor, in dem eine kleine CSS-Änderung in einer Frontend-App einen vollständigen Neuaufbau und eine erneute Testung jedes einzelnen Dienstes und jeder einzelnen Anwendung in Ihrem Monorepo auslöst – dies ist nicht nur ineffizient, sondern auch kostspielig in Bezug auf Cloud-Ressourcen und Entwickler-Wartezeiten. Dieser Artikel zielt darauf ab, diese Herausforderungen anzugehen, indem untersucht wird, wie die leistungsstarke Kombination aus Remote Caching und On-Demand Builds von Turborepo CI/CD-Prozesse für Full-Stack-JavaScript-Projekte dramatisch optimieren kann, um schnellere Feedback-Schleifen und reduzierte Infrastrukturkosten zu gewährleisten.
Kernkonzepte und Implementierung
Bevor wir uns mit den Optimierungsdetails befassen, wollen wir die Kernkonzepte, die für die Effektivität von Turborepo zentral sind, klar verstehen.
Was ist ein Monorepo?
Ein Monorepo ist ein einziges Repository, das mehrere verschiedene Projekte enthält, oft mit gemeinsamen Abhängigkeiten und Konfigurationen. In einem typischen Full-Stack-JavaScript-Setup könnten dies ein React-Frontend, eine Node.js-Backend-API, gemeinsame UI-Komponenten und Utility-Bibliotheken sein, die sich alle im selben Git-Repository befinden.
Was ist Turborepo?
Turborepo ist ein Hochleistungs-Build-System für JavaScript- und TypeScript-Monorepos. Es wurde entwickelt, um die Entwicklungs- und CI/CD-Erfahrung zu optimieren, indem Build-Artefakte intelligent zwischengespeichert und nur das Notwendigste neu erstellt wird.
Wichtige Funktionen von Turborepo
Zwei Funktionen sind für unsere Diskussion besonders relevant:
- Remote Caching: Turborepo kann Build-Artefakte (z. B. kompilierter Code, Testergebnisse, gebündelte Assets) in einem Remote-Cache speichern. Dieser Cache kann von mehreren Entwicklern und CI/CD-Pipelines gemeinsam genutzt werden. Wenn eine bestimmte Aufgabe (wie
build
odertest
) für ein bestimmtes Projekt mit denselben Eingaben zuvor ausgeführt wurde, kann Turborepo die zwischengespeicherten Ausgaben abrufen, anstatt die Aufgabe erneut auszuführen. - On-Demand Builds (oder inkrementelle Builds): Turborepo analysiert den Abhängigkeitsgraphen Ihres Monorepos und ermittelt, welche Projekte und Aufgaben von Änderungen betroffen sind. Es führt dann nur die Aufgaben für die betroffenen Projekte aus und überspringt nicht betroffene.
Einrichtung von Turborepo
Zuerst müssen Sie Turborepo in Ihrem Monorepo einrichten. Angenommen, Sie haben eine package.json
im Stammverzeichnis Ihres Monorepos und einzelne package.json
-Dateien in Ihren Workspace-Paketen (z. B. apps/web
, packages/ui
):
// root package.json { "name": "my-fullstack-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "apps/*", "packages/*" ], "scripts": { "build": "turbo run build", "dev": "turbo run dev --parallel", "test": "turbo run test" }, "devDependencies": { "turbo": "^LatestVersion" } }
Konfigurieren Sie als Nächstes Ihre turbo.json
-Datei im Stammverzeichnis Ihres Monorepos, um Pipeline-Aufgaben und deren Caching-Verhalten zu definieren.
// turbo.json { "$schema": "https://turbo.build/schema.json", "globalDependencies": [ "**/.env" // Beispiel: Jede .env-Dateiänderung macht Caches ungültig ], "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**"], "cache": true }, "test": { "dependsOn": [], "outputs": ["coverage/**"], "cache": true }, "lint": { "outputs": [] }, "dev": { "cache": false, // Dev-Server sind normalerweise langlaufend, daher ist kein Caching erforderlich "persistent": true } } }
In diesem turbo.json
:
build
: Hängt von^build
ab, was bedeutet, dass zuerst alle Abhängigkeiten des aktuellen Pakets erstellt werden. Es speichert die Ausgabeverzeichnissedist/**
und.next/**
im Cache.test
: Keine spezifischen Projekt abhängigkeiten für Tests, aber führt Tests aus. Cachtcoverage/**
.cache: true
fürbuild
undtest
aktiviert den Caching-Mechanismus von Turborepo.
Implementierung von Remote Caching
Turborepo unterstützt Remote Caching über eine verschlüsselte Netzwerkverbindung zu einem dedizierten Turborepo Remote Cache-Dienst (Vercel-Produkt oder selbst gehostete Alternativen).
-
Vercel-Integration (Der einfachste Weg): Wenn Ihr Monorepo auf Vercel gehostet wird, ist Remote Caching weitgehend automatisch. Verknüpfen Sie einfach Ihr Turborepo mit einem Vercel-Team, und es wird der Remote-Cache von Vercel verwendet.
-
Self-Hosting (AWS S3, Google Cloud Storage usw.): Für Self-Hosting müssen Sie Umgebungsvariablen konfigurieren. Für AWS S3:
# Legen Sie diese in Ihren CI/CD-Umgebungsvariablen fest TURBO_REMOTE_CACHE_SIGNATURE_KEY="your-secret-key-for-signing-cache-requests" TURBO_REMOTE_CACHE_API="https://my-self-hosted-cache-endpoint.com" # Oder direkte S3-URL TURBO_REMOTE_CACHE_READ_ONLY=false # Auf true setzen für Lesezugriff in einigen CI-Stufen
Sie benötigen außerdem einen Backend-Dienst, der die Remote-Cache-API von Turborepo mithilfe eines Speicheranbieters wie S3 implementiert. Turbo bietet Open-Source-Beispiele und Tools dafür.
Beispiel für einen CI/CD-Workflow (GitHub Actions):
# .github/workflows/ci.yml name: CI on: push: branches: - main pull_request: branches: - main jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: 18 - name: Install dependencies run: npm install # Oder yarn install / pnpm install - name: Turborepo Remote Cache-Konfiguration env: TURBO_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Bei Verwendung von Vercel Remote Cache TURBO_TEAM: your-vercel-team-id # Bei Verwendung von Vercel Remote Cache # Oder für Self-Hosted: # TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} # TURBO_REMOTE_CACHE_API: ${{ secrets.TURBO_REMOTE_CACHE_API }} run: | # Dieser Befehl stellt automatisch eine Verbindung zum Remote-Cache her, wenn Umgebungsvariablen gesetzt sind # oder wenn er über `vercel link` mit Vercel verknüpft ist echo "Configuring Turborepo for remote caching..." - name: Build affected projects run: npm run build # Dies ruft `turbo run build` auf # Turborepo nutzt hier automatisch den Remote-Cache. # Wenn ein Build für ein Projekt zwischengespeichert wurde, wird er wiederhergestellt. # Andernfalls wird er erstellt und dann die Ausgabe im Cache gespeichert. - name: Test affected projects run: npm run test # Dies ruft `turbo run test` auf # Ähnlich wie beim Build nutzt das Testen die Zwischenspeicherung.
On-Demand Builds in Aktion
Die On-Demand Build-Funktionalität von Turborepo funktioniert nahtlos mit Remote Caching. Wenn Sie turbo run build
oder turbo run test
ausführen, führt Turborepo die folgenden Schritte aus:
- Graphenanalyse: Es konstruiert einen Abhängigkeitsgraphen Ihres Monorepos.
- Fingerprinting: Für jede Aufgabe (z. B.
build
fürapps/web
) berechnet es einen eindeutigen "Fingerabdruck", der auf den Eingaben der Aufgabe (Quellcodedateien, Abhängigkeiten, Umgebungsvariablen,turbo.json
-Konfiguration usw.) basiert. - Cache-Lookup: Es prüft, ob dieser Fingerabdruck zuerst im lokalen Cache und dann im Remote-Cache vorhanden ist.
- Ausführung oder Wiederherstellung:
- Wenn ein Cache-Treffer auftritt, stellt es die Ausgaben aus dem Cache wieder her und kennzeichnet die Aufgabe als
cache hit
. - Wenn kein Cache-Treffer erzielt wird, führt es die Aufgabe aus und speichert dann ihre Ausgaben sowohl im lokalen als auch im Remote-Cache.
- Wenn ein Cache-Treffer auftritt, stellt es die Ausgaben aus dem Cache wieder her und kennzeichnet die Aufgabe als
- Betroffene Projekte: Wenn Sie eine Änderung vornehmen, bewertet Turborepo nur die Projekte neu, die direkt oder indirekt von dieser Änderung betroffen sind, und berechnet neue Fingerabdrücke. Nicht betroffene Projekte werden höchstwahrscheinlich vollständig zwischengespeichert finden.
Praktisches Beispiel:
Nehmen wir an, Ihr Monorepo hat apps/web
(React-App) und packages/ui
(gemeinsame UI-Komponenten).
- Wenn Sie eine Datei in
apps/web
ändern: Nur diebuild
- undtest
-Aufgaben vonapps/web
werden potenziell ausgeführt. Die Aufgaben vonpackages/ui
werden aus dem Cache abgerufen. - Wenn Sie eine Datei in
packages/ui
ändern: Sowohl die Aufgaben vonpackages/ui
als auch die Aufgaben vonapps/web
(daapps/web
vonpackages/ui
abhängt) werden potenziell ausgeführt. Andere nicht verwandte Projekte werden aus dem Cache abgerufen.
Diese intelligente Orchestrierung bedeutet, dass CI/CD-Pipelines nicht mehr bei jedem Commit alles neu erstellen, was zu deutlich schnelleren Ausführungen und reduziertem Ressourcenverbrauch führt.
Fazit
Remote Caching und On-Demand Builds von Turborepo verändern grundlegend, wie Full-Stack-JavaScript-Monorepos in CI/CD verwaltet werden. Durch intelligentes Speichern und Abrufen von Build-Artefakten und die selektive Ausführung nur betroffener Aufgaben eliminiert Turborepo redundante Arbeit, was die Build-Zeiten und CI/CD-Kosten drastisch reduziert. Die Übernahme von Turborepo ist ein strategischer Schritt für jedes Team, das seine Entwicklungszyklen beschleunigen und die Effizienz seiner Full-Stack-Monorepo-Workflows verbessern möchte.