TypeScript-Monorepo-Konfiguration

Monorepo ist ein Entwicklungsmuster, bei dem mehrere Projekte im selben Code-Repository untergebracht werden.

TypeScript unterstützt Monorepo durch Projektreferenzen und Toolchains und ermöglicht so eine effiziente Verwaltung mehrerer Pakete.


SVG-Diagramm: Monorepo-Struktur Background Title Monorepo Project Structure Root directory Root directory (root) package.json | tsconfig.json | lerna.json | turbo.json Package directory packages/ directory Package 1 utils Package 2 ui-components Package 3 hooks Package 4 app Bottom section: Tools Management tools: npm workspaces | yarn workspaces | pnpm | lerna | turbo Arrow marker

Warum ein Monorepo notwendig ist

Wenn ein Projekt mehrere Pakete enthält (wie Utility-Bibliotheken, Komponentenbibliotheken und Anwendungen), erfordert der traditionelle Ansatz die Pflege mehrerer Code-Repositories.

Ein Monorepo platziert alle Pakete im selben Repository, wodurch Code-Sharing bequemer und die Versionsverwaltung einheitlicher wird.

Die Projektreferenz-Funktion von TypeScript macht die Typprüfung und das Erstellen von Monorepo-Projekten effizienter.

Konzept:Monorepo (ein einziges Repository) platziert mehrere zusammenhängende Projekte im selben Code-Repository und erleichtert so Code-Sharing und koordinierte Entwicklung.


pnpm Workspace

pnpm ist ein moderner Paketmanager mit nativer Unterstützung für Workspace-Funktionen.

package.json im Stammverzeichnis

{
    "name": "my-monorepo",
    "version": "1.0.0",
    "private": true,

    // pnpm-Workspace aktivieren
    "packages": [
        "packages/*"
    ],

    // Entwicklungsabhängigkeiten
    "devDependencies": {
        "typescript": "^5.0.0"
    },

    // Skripte
    "scripts": {
        "build": "pnpm -r run build",
        "clean": "pnpm -r run clean",
        "type-check": "pnpm -r run type-check"
    }
}

pnpm:Die Workspace-Funktion von pnpm kann Pakete im packages-Verzeichnis automatisch miteinander verknüpfen.


Projektstruktur

Erstelle die Verzeichnisstruktur für ein Monorepo-Projekt.

Verzeichnisstruktur

mein-Monorepo/
├── packages/
│ ├── utils/# Hilfspaket
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│   │
│ ├── ui-components/# UI-Komponentenpaket
│ │ ├── src/
│ │ │ ├── Button.tsx
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│   │
│ └── app/# Anwendung
│ ├── src/
│ │ └── index.tsx
│ ├── package.json
│ └── tsconfig.json
│
├── package.json# Root-Konfiguration
├── tsconfig.base.json# Basiskonfiguration
└── pnpm-workspace.yaml# pnpm-Konfiguration

packages:Alle Pakete werden unter dem packages-Verzeichnis abgelegt, jeweils mit eigener package.json und tsconfig.json.


TypeScript-Basiskonfiguration

Erstellen Sie eine Basiskonfiguration, die alle Pakete verwenden können.

tsconfig.base.json

{
    // Compiler-Optionen
    "compilerOptions": {
        // Zielversion
        "target": "ES2020",

        // Modulsystem
        "module": "ESNext",

        // Strikter Modus
        "strict": true,

        // Bibliothekstypenprüfung überspringen
        "skipLibCheck": true,

        // ES-Modul-Interop aktivieren
        "esModuleInterop": true,

        // Konsistente Groß-/Kleinschreibung in Dateinamen erzwingen
        "forceConsistentCasingInFileNames": true,

        // Modulauflösung
        "moduleResolution": "bundler",

        // JSON-Module auflösen
        "resolveJsonModule": true,

        // Isolierte Module
        "isolatedModules": true,

        // Keine Ausgabedateien generieren
        "noEmit": true
    }
}

Vererbung:Jedes tsconfig.json eines Pakets erbt die Basiskonfiguration und überschreibt nur Optionen, die angepasst werden müssen.


Konfiguration des Utility-Pakets

TypeScript für das Utility-Paket konfigurieren.

packages/utils/tsconfig.json

{
    // Basiskonfiguration erben
    "extends": "../../tsconfig.base.json",

    // Compiler-Optionen
    "compilerOptions": {
        // Ausgabeverzeichnis
        "outDir": "./dist",

        // Verzeichnis für Deklarationsdateien
        "declarationDir": "./dist/types",

        // Deklarationsdateien generieren
        "declaration": true,

        // Deklarationen für Einstiegsdateien generieren
        "declarationMap": true,

        // Modulexportformat
        "module": "ESNext",

        // Projektreferenzen aktivieren
        "composite": true
    },

    // Enthaltene Dateien
    "include": ["src/**/*"],

    // Ausgeschlossene Dateien
    "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

composite:Nach dem Aktivieren von Projektreferenzen kann TypeScript dieses Paket inkrementell kompilieren.


Anwendungskonfiguration

TypeScript für die Hauptanwendung konfigurieren und auf andere Pakete verweisen.

packages/app/tsconfig.json

{
    // Basiskonfiguration erben
    "extends": "../../tsconfig.base.json",

    // Compiler-Optionen
    "compilerOptions": {
        // Ausgabeverzeichnis
        "outDir": "./dist",

        // JSX-Konfiguration
        "jsx": "react-jsx",

        // Pfad-Aliase
        "baseUrl": ".",
        "paths": {
            "@my-utils/*": ["../utils/src/*"],
            "@my-ui/*": ["../ui-components/src/*"]
        }
    },

    // Projektreferenzen
    "references": [
        { "path": "../utils" },
        { "path": "../ui-components" }
    ],

    // Enthaltene Dateien
    "include": ["src/**/*"],

    // Ausgeschlossene Dateien
    "exclude": ["node_modules", "dist"]
}

Pfad-Aliase:Du kannst Pfad-Aliase konfigurieren, um direkt auf andere Pakete im selben Repository zu verweisen.


Abhängigkeiten zwischen Paketen

Deklariere Abhängigkeiten von Paketen im selben Repository in package.json.

packages/app/package.json

{
    "name": "@my-org/app",
    "version": "1.0.0",
    "private": true,

    "dependencies": {
        // Pakete im selben Repository referenzieren
        "@my-org/utils": "workspace:*",
        "@my-org/ui-components": "workspace:*",

        // Externe Abhängigkeiten
        "react": "^18.2.0",
        "react-dom": "^18.2.0"
    },

    "devDependencies": {
        // Entwicklungsabhängigkeiten
        "@types/react": "^18.2.0",
        "typescript": "^5.0.0"
    }
}

Workspace:Verwende workspace:*, um auf andere Pakete im selben Repository zu verweisen, und pnpm wird sie automatisch auflösen.


Build-Skripte

Erstelle einheitliche Build-Skripte für das Monorepo.

package.json im Stammverzeichnis

{
    "scripts": {
        // Alle Pakete bauen
        "build": "pnpm -r run build",

        // Alle Build-Artefakte bereinigen
        "clean": "pnpm -r run clean",

        // Typprüfung
        "type-check": "pnpm -r run type-check",

        // Alle Pakete testen
        "test": "pnpm -r run test",

        // Inkrementeller Build
        "build:watch": "pnpm -r --parallel run build:watch",

        // Die Anwendung starten
        "dev": "pnpm --filter @my-org/app run dev"
    }
}

pnpm -r:Skripte mit demselben Namen rekursiv in allen Paketen ausführen.


Hinweise

  • Paketnamenskonvention:Verwende das Format @org-name/package
  • Unabhängige Versionen:Jedes Paket kann unabhängig versioniert werden
  • Workspace-Protokoll:Verwende workspace:*, um auf Pakete im selben Repository zu verweisen
  • Build-Reihenfolge:Pakete, die als Abhängigkeit verwendet werden, müssen zuerst gebaut werden

Best Practices:Ein Monorepo eignet sich für die Verwaltung mehrerer zusammengehöriger Projekte und kann die Wiederverwendung von Code und die Entwicklungseffizienz erheblich verbessern.


Zusammenfassung

Monorepo ist ein empfohlenes Muster für modernes Frontend-Projektmanagement.

  • pnpm Workspace:Native Monorepo-Unterstützung
  • Projektreferenzen:Inkrementelle Kompilierung aktivieren
  • Pfadaliase:Bequemes Referenzieren von Paketen im selben Repository
  • Einheitliche Verwaltung:Konfiguration und Abhängigkeiten gemeinsam nutzen

Empfehlung:Wenn ein Projekt mehrere zusammenhängende Pakete enthält, solltest du zuerst den Monorepo-Ansatz in Betracht ziehen.

Andere Erweiterungen