Startseite / Artikel / Eine für die Produktion bereite React-Baseline: Was jedes Paket tatsächlich tut

Eine für die Produktion bereite React-Baseline: Was jedes Paket tatsächlich tut

Einführen Sie Vite, Tailwind v4, Redux Toolkit, React Router, Jest und Prettier für eine React-Anwendung ein und verstehen Sie, warum jedes Paket sowie jede Konfigurationszeile vorhanden ist.

3165 Wörter

Durch Ausführung von npm create vite erhält man eine React-Anwendung, die zwar angezeigt werden kann, aber nicht so ist, wie man sie echten Nutzern zur Verfügung stellen würde: Es gibt kein Styling-System, keinen gemeinsamen Zustand, keine Routenverwaltung, keine Tests und kein einheitliches Codeformat. Diese Anleitung schafft Schritt für Schritt diese fehlenden Grundlagen mithilfe von Tailwind CSS, Redux Toolkit, React Router, Jest zusammen mit der React Testing Library sowie Prettier. Für jedes Paket werden zwei Fragen beantwortet: Was tut es eigentlich, und was bricht, wenn man es weglässt? Am Ende wird man eine funktionierende Basis haben, auf der weitere Funktionen entwickelt werden können – und genauso wichtig: Man wird in der Lage sein, seinen eigenen package.json zu lesen und jede Zeile darin zu erklären.

Der Technologiestack im Überblick:

  • Tailwind CSS für das Styling
  • Redux Toolkit für gemeinsame Anwendungsdaten
  • React Router für die Navigierung zwischen Seiten
  • Jest, React Testing Library sowie ein kleines Babel-Toolchain, damit die Tests überhaupt ausgeführt werden können
  • Prettier, damit die Formatierung nicht mehr Gegenstand von Meinungsverschiedenheiten ist
  • Einige davon lassen sich in einer Zeile installieren. Andere verbergen überraschende Details; „React Testing Library“ beispielsweise besteht tatsächlich aus drei Paketen mit jeweils unterschiedlichen Aufgaben.

    Fangen Sie mit einem neuen Vite-Projekt unter Verwendung des React + TypeScript-Vorlagen an:

    npm create vite@latest react-production-stack -- --template react-ts
    cd react-production-stack
    npm install
    

    Tailwind CSS: Styling wird zuerst integriert

    Pakete: tailwindcss, @tailwindcss/vite

    Da das Styling jeden Komponenten betrifft, ist es sinnvoll, zuerst zu überprüfen, ob alles funktioniert, bevor weitere Elemente hinzugefügt werden.

    npm install tailwindcss @tailwindcss/vite
    

    Dies installiert beide Pakete als reguläre Abhängigkeiten statt als devDependencies. Genau genommen läuft keines der Pakete im Browser – das Vite-Plugin erledigt seine Arbeit während des Builds und nur der generierte CSS landet im Produktionspaket. Viele Teams ordnen sie daher unter devDependencies ein, und bei einer gebündelten Single-Page-App ergibt sich mit beiden Optionen dasselbe Ergebnis. Wählen Sie eine Konvention und bleiben Sie dabei konsequent.

    Dann registrieren Sie das Plugin zusammen mit dem React-Plugin in der Vite-Konfiguration:

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    import tailwindcss from '@tailwindcss/vite'
    
    export default defineConfig({
      plugins: [react(), tailwindcss()],
    })
    

    Ersetzen Sie anschließend den Inhalt von src/index.css durch eine einzige Import-Anweisung. Das ist der gesamte Inhalt des Files:

    /* Tailwind v4 is CSS-first. No config file, no content globs. */
    @import 'tailwindcss';
    

    Das ist wirklich die gesamte Einrichtung. Tailwind v4 arbeitet klassenbasiert: Es gibt weder ein tailwind.config.js noch eine Liste von Inhaltseinheiten, da es selbstständig nach Klassennamen in Ihren Quelldateien sucht.

    Überprüfen, ob es funktioniert

    Fügen Sie vorübergehend einige Utility-Klassen zu einem Überschriftstext in App.tsx hinzu, zum Beispiel text-3xl font-bold text-blue-600, führen Sie npm run dev aus und überprüfen Sie, ob sich die Überschrift ändert. Wenn das der Fall ist, sind das Plugin und die CSS-Importe miteinander verbunden.

    Warum Utility-Klassen statt separater Stylesheets

    Tailwind platziert die Styles direkt im Markup, das sie beeinflussen. Bei einem separaten CSS-Datei ist es leicht, ein Komponenten zu bearbeiten und dessen Stylesheet zu vergessen, wodurch sich allmählich nutzlose und veraltete Regeln ansammeln. Insbesondere Dashboards verwenden immer wieder dieselben Bausteine (Karten, Abzeichen, Schaltflächen), und deren Zusammenstellung aus einem gemeinsamen Satz an Utility-Klassen sorgt für visuelle Konsistenz bei geringerem Wartungsaufwand. Der Trade-off besteht in einer Gewöhnungsänderung: Anstatt Klassennamen wie .card-header-active zu erfinden, werden die einzelnen Elemente aus kleinen, vordefinierten Klassen zusammengesetzt.

    Redux Toolkit: ein Store und eine Brücke zu React

    Pakete: @reduxjs/toolkit, react-redux

    Diese beiden Pakete lassen sich leicht verwechseln, doch sie erfüllen unterschiedliche Aufgaben:

    • @reduxjs/toolkit ist der Store selbst: Er speichert die Anwendungsdaten und führt Updates an ihnen durch.
    • react-redux ist die Verbindung zu React: Er stellt <Provider> sowie die Hooks bereit, die von den Komponenten verwendet werden, um diese Daten zu lesen und zu aktualisieren.

    Sie benötigen beide, da keines von ihnen die Aufgaben des anderen übernehmen kann.

    npm install @reduxjs/toolkit react-redux
    

    Erstellen Sie den Store in src/app/store.ts. Er beginnt mit einem leeren Reducer-Map und exportiert zwei aus dem Store abgeleitete Typen, damit der Rest der Anwendung sie nicht manuell aufschreiben muss:

    import { configureStore } from '@reduxjs/toolkit'
    
    export const store = configureStore({
      reducer: {},
    })
    
    export type RootState = ReturnType<typeof store.getState>
    export type AppDispatch = typeof store.dispatch
    

    Das Objekt reducer: {} bleibt vorerst leer. Slices werden hinzugefügt, sobald echte Funktionen wie Projekte oder Aufgaben sie benötigen; es hat keinen Sinn, Zustände vorher zu erfinden, bevor irgendeine Ansicht sie verwendet.

    Anschließend werden typisierte Hooks in src/app/hooks.ts definiert. Die in neueren React Redux-Versionen verfügbaren withTypes-Hilfsfunktionen binden useDispatch und useSelector einmal an die Typen Ihres Stores, sodass Komponenten eine vollständige Typinferenz erhalten, ohne jede Aufrufstelle annotieren zu müssen:

    import { useDispatch, useSelector } from 'react-redux'
    import type { AppDispatch, RootState } from './store'
    
    export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
    export const useAppSelector = useSelector.withTypes<RootState>()
    

    Übermittlung des Stores an den Komponentenbaum

    Zu diesem Zeitpunkt existiert der Store bereits, aber React hat keine Kenntnis davon. <Provider> macht ihn für jede darunterliegende Komponente verfügbar, weshalb er ganz oben im Baum in src/main.tsx platziert wird:

    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import { Provider } from 'react-redux'
    import { store } from './app/store'
    import App from './App'
    import './index.css'
    
    createRoot(document.getElementById('root')!).render(
      <StrictMode>
        <Provider store={store}>
          <App />
        </Provider>
      </StrictMode>,
    )
    

    Jedes Element, das innerhalb von <Provider> dargestellt wird, kann nun useAppSelector und useAppDispatch aufrufen.

    Überprüfung der Funktionsfähigkeit

    Starten Sie die Anwendung und stellen Sie sicher, dass die Seite weiterhin ohne den Fehler "could not find react-redux context" angezeigt wird. Dieser Fehler tritt auf, wenn eine Komponente die Redux-Hooks außerhalb eines Providers verwendet. Mit einem leeren Store gibt es vorerst nichts anderes zu testen.

    Wann Redux erforderlich ist und wann useState ausreicht

    Nicht alles gehört in Redux, und das Hineinpacken aller Zustände in den Store ist genauso falsch wie das Behalten von allem lokal. Eine praktische Faustregel:

    • useState für Daten, die nur für einen einzigen Bildschirm oder eine Komponente relevant sind: ob ein Modal geöffnet ist, der aktuelle Wert eines Eingabefeldes oder die ausgewählte Option in einem Dropdown-Menü.
  • Redux für Daten, die mehrere Bildschirme oder Komponenten gleichzeitig benötigen, wie beispielsweise eine Aufgabenliste, die auf mehreren Seiten angezeigt wird, oder eine einzelne Aufgabe, die im Dashboard sowie in der Aufgabenliste und im Detailbildschirm der Aufgabe erscheint.
  • Falls ein Zustandswert sonst über mehrere Ebenen weitergegeben oder auf verschiedenen Bildschirmen dupliziert werden müsste, ist das ein gutes Zeichen dafür, dass er in den Store gehört.

    React Router: Routing vor der ersten eigentlichen Seite

    Paket: react-router

    Das Hinzufügen von Routing, bevor es eine eigentliche Seite gibt, mag vorzeitig erscheinen, bringt aber schnell Vorteile: Jeder neue Bildschirm wird zu einer zusätzlichen <Route>, anstatt dass später eine Umstrukturierung der Anwendung notwendig wird.

    npm install react-router
    

    Platzieren Sie die Route-Tabelle in einem eigenen Modul, src/routes/AppRoutes.tsx. Derzeit wird / auf ein Platzhalterkomponente abgebildet, das mit Tailwind-Utilities gestylt ist:

    import { Route, Routes } from 'react-router'
    
    function Placeholder() {
      return (
        <div className="flex min-h-screen items-center justify-center">
          <p className="text-slate-600">Routes coming soon</p>
        </div>
      )
    }
    
    export function AppRoutes() {
      return (
        <Routes>
          <Route path="/" element={<Placeholder />} />
        </Routes>
      )
    }
    

    src/App.tsx rendernt anschließend einfach diese Route-Tabelle:

    import { AppRoutes } from './routes/AppRoutes'
    
    function App() {
      return <AppRoutes />
    }
    
    export default App
    

    Zum Schluss umschließen Sie die Anwendung mit <BrowserRouter> in src/main.tsx, neben dem Redux-Provider:

    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import { Provider } from 'react-redux'
    import { BrowserRouter } from 'react-router'
    import { store } from './app/store'
    import App from './App'
    import './index.css'
    
    createRoot(document.getElementById('root')!).render(
      <StrictMode>
        <Provider store={store}>
          <BrowserRouter>
            <App />
          </BrowserRouter>
        </Provider>
      </StrictMode>,
    )
    

    Die resultierende Kette ist main.tsx<App /><AppRoutes /> → die jeweilige <Route>, die zur URL passt. Redux und der Router sind unabhängig, daher spielt die Reihenfolge ihrer Nestung keine Rolle; die einzige Voraussetzung ist, dass beide <App> umschließen.

    Überprüfung der Funktionalität

    Führen Sie npm run dev aus und öffnen Sie /. Wenn der Platzhaltext angezeigt wird, sind <BrowserRouter>, <Routes> und <Route> alle korrekt verbunden.

    Jest und React Testing Library: vier Aufgaben, elf Pakete

    Pakete: jest, @testing-library/react, babel-jest sowie weitere

    Dies ist der schritt, der am längsten dauert. Die Konzepte sind nicht schwierig, doch „Tests hinzufügen“ bedeutet in Wirklichkeit das Installieren von etwa elf Paketen, die vier unterschiedliche Aufgaben übernehmen, und anschließend das Erreichen, dass ein Test mit dem Router funktioniert. Das Gruppieren der Pakete nach Aufgabe macht das Ganze viel verständlicher.

    Gruppe A: der Testausführer und ein simulierter Browser

    npm install -D jest jest-environment-jsdom
    
    • jest ist der Ausführer. Er entdeckt *.test.tsx-Dateien, führt sie aus und meldet Erfolge sowie Misserfolge. Ohne ihn funktioniert nichts anderes in diesem Abschnitt.
    • jest-environment-jsdom ist notwendig, weil Jest in Node läuft, wo es kein document gibt. Es stellt einen simulierten DOM bereit, damit Komponenten etwas zum Rendern haben.

    Gruppe B: React Testing Library besteht aus drei Paketen

    npm install -D @testing-library/react
    npm install -D @testing-library/jest-dom
    npm install -D @testing-library/user-event
    

    Was die Leute als „React Testing Library“ bezeichnen, sind eigentlich drei Bibliotheken, jede mit ihrer eigenen Aufgabe:

    • @testing-library/react rendernt eine Komponente auf der simulierten Seite und bietet Abfragen wie screen.getByText(...) an.
  • @testing-library/jest-dom fügt lesbare Matcher wie toBeInTheDocument() hinzu, sodass Sie die Ergebnisse von Abfragen nicht manuell mit null vergleichen müssen.
  • @testing-library/user-event simuliert reales Benutzerverhalten. Das Eingeben erzeugt die vollständige Sequenz aus Fokussierung, Tastendruck, Eingabe und Tastenentfernung, wie sie ein Browser auslösen würde, anstatt nur ein einzelnes künstliches Ereignis an ein Element zu senden.
  • Kurz gesagt: Rendern, überprüfen, interagieren. Drei Aufgaben, drei Pakete – und Sie möchten fast immer alle davon.

    Gruppe C: Die Babel-Toolkette, die es Jest ermöglicht, TSX zu lesen

    Diese Gruppe existiert aus einem einzigen Grund: Jest kann TypeScript- oder JSX-Dateien nicht von selbst verstehen.

    • babel-jest verbindet die beiden. Jest leitet jede Datei vor der Ausführung durch Babel.
  • @babel/preset-typescript entfernt Typangaben. Es führt keine Typüberprüfung durch; es löscht einfach : string sowie ähnliche Syntaxe aus.
  • @babel/preset-react kompiliert JSX in gewöhnliche Funktionsaufrufe um.
  • @babel/preset-env wandelt moderne Syntax in Formate um, die von Ihrer Node-Version unterstützt werden.
  • Im Gegensatz zur Gruppe B sollten diese Präsets zusammen in einem Befehl installiert werden. Alle Präsets erfordern ein kompatibles @babel/core, und ihre getrennte Installation in einem Projekt, das bereits Jest enthält (das seine eigenen Babel-Abhängigkeiten mitbringt), kann dazu führen, dass npm versucht, inkompatible Versionen miteinander in Einklang zu bringen. Ein bekanntes Symptom ist der Fehler ERESOLVE unable to resolve dependency tree bei der nächsten Installation eines einzelnen Pakets. Die gleichzeitige Installation der gesamten Gruppe ermöglicht es npm, eine einheitliche Version zu finden.

    Eine zweite, subtilere Falle entsteht durch das Kopieren langer Befehle aus PDFs oder Webseiten. Text, der in weichen Zeilenformatierungen dargestellt wird, kann beim Einfügen zu echten Zeilenumbrüchen führen – dadurch wird ein Paketname wie @babel/preset-typescript in zwei Teile geteilt, und die Shell führt den zweiten Teil als separaten, sinnlosen Befehl aus. Explizite Zeilenerweiterungen sorgen dafür, dass die Brüche genau dort entstehen, wo man es möchte. Im Folgenden wird die Syntax des Windows Command Prompt verwendet:

    npm install -D babel-jest ^
      @babel/core ^
      @babel/preset-env ^
      @babel/preset-react ^
      @babel/preset-typescript
    

    Das am Ende stehende ^ signalisiert cmd.exe, dass der Befehl in der nächsten Zeile fortgesetzt wird. In PowerShell ist das Fortsetzungszeichen ein Backtick, und in bash oder zsh ein Backslash. Unabhängig von der Shell handelt es sich dabei dennoch um genau einen npm install-Befehl.

    Gruppe D: Typen nur für Ihren Editor

    npm install -D @types/jest
    

    Dieses Paket hat keinen Einfluss darauf, wie Tests ausgeführt werden; Babel hat zu diesem Zeitpunkt bereits alle Typen entfernt. Es existiert, damit TypeScript und Ihr Editor globale Funktionen wie test(...) und expect(...) erkennen, anstatt sie als Fehler zu melden.

    Hinzufügen der Testskripte

    Durch das Installieren von Jest erhalten Sie keinen npm test-Befehl, daher fügen Sie die Skripte selbst in package.json hinzu:

    "scripts": {
      "dev": "vite",
      "build": "tsc -b && vite build",
      "lint": "eslint .",
      "test": "jest",
      "test:watch": "jest --watch"
    }
    

    npm test führt den gesamten Testumfang einmal aus. npm run test:watch läuft weiter und führt nur die Tests aus, die durch die gerade gespeicherte Datei betroffen sind; halten Sie es in einem zweiten Terminal geöffnet, während Sie arbeiten.

    Zwei weitere Befehle sind für den Fall, dass etwas schiefgeht, erwähnenswert:

    npx jest src/App.test.tsx   # run one file only
    npx jest --clearCache       # when Jest keeps showing an error
                                # you already fixed
    

    Der Cache-Befehl ist wichtiger, als es auf den ersten Blick scheint. Jest speichert transformierte Dateien, sodass nach einer Änderung von babel.config.cjs oder jest.config.cjs weiterhin die alten Ausgaben bereitgestellt werden können und ein Fehler gemeldet wird, den Sie bereits behoben haben. Wenn eine Lösung scheinbar nicht funktioniert, leeren Sie den Cache, bevor Sie zu dem Schluss kommen, dass die Lösung falsch ist.

    Die vollständige Testkonfiguration

    Nachfolgend finden Sie alle Konfigurationsdateien in voller Länge, zusammen mit einer Erklärung dazu, wofür jeder Teil zuständig ist.

    babel.config.cjs

    Die Vorlagen spiegeln Gruppe C wider: Sie richten sich auf die aktuelle Node-Version aus, verwenden den automatischen JSX-Runtime, sodass Dateien React importieren müssen, und entfernen TypeScript. Das eingebettete Plugin kümmert sich um etwas, was Jest nicht kann: import.meta, das Vite-Code für Funktionen wie import.meta.env und den Hot-Module-Replacement verwendet, aber in der von Jest hier ausgeführten CommonJS-Ausgabe nicht gültig ist.

    function stripImportMeta() {
      return {
        visitor: {
          MetaProperty(path) {
            path.replaceWithSourceString('({ url: "", hot: undefined })')
          },
        },
      }
    }
    
    module.exports = {
      presets: [
        ['@babel/preset-env', { targets: { node: 'current' } }],
        ['@babel/preset-react', { runtime: 'automatic' }],
        '@babel/preset-typescript',
      ],
      plugins: [stripImportMeta],
    }
    

    Es handelt sich um ein echtes Babel-Plugin, das als Inline-Funktion statt als installiertes Paket geschrieben wurde; Babel akzeptiert beide Formen. MetaProperty ist der AST-Node-Typ, den Babel für import.meta verwendet, und der Visitor ersetzt jeden Vorkommen durch ein einfaches Objekt mit einem leeren url-Wert und einem undefinierten hot-Wert. Beachten Sie, dass dadurch auch alle Werte von import.meta.env vor dem getesteten Code versteckt werden, weshalb Komponenten, die Umgebungsvariablen lesen, diese separat emuliert haben müssen.

    jest.config.cjs

    Diese Datei verbindet den Runner mit allem anderen. Sie wählt die jsdom-Umgebung aus, lädt nach Bereitstellung der Umgebung eine Setup-Datei, leitet jede JavaScript- und TypeScript-Datei über babel-jest weiter und weist Importe von Styles und Bildern auf Stubs-Module zu.

    module.exports = {
      testEnvironment: 'jsdom',
      setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
      moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'mjs', 'json'],
      transform: {
        '^.+\\.(ts|tsx|js|jsx|mjs)
    : 'babel-jest', }, transformIgnorePatterns: ['node_modules/(?!(react-router|cookie-es)/)'], moduleNameMapper: { '\\.(css|less|scss|sass)
    : '<rootDir>/test/styleMock.js', '\\.(png|jpg|jpeg|gif|svg|webp)
    : '<rootDir>/test/fileMock.js', }, }

    Der Eintrag transformIgnorePatterns verdient eine Erwähnung. Standardmäßig wandelt Jest nichts innerhalb von node_modules um. Der negative Lookahead macht eine Ausnahme für react-router und cookie-es, die als ES-Module veröffentlicht werden und von Jests CommonJS-Pipeline ohne Umwandlung nicht geladen werden können. Fügen Sie später eine weitere nur für ESM verfügbare Abhängigkeit hinzu und erhalten Sie einen SyntaxError: Cannot use import statement outside a module, dann gehört dieser Muster hierhin.

    jest.setup.ts

    Die Setup-Datei registriert die jest-dom-Matcher und fügt TextEncoder sowie TextDecoder zum globalen Scope hinzu. Die jsdom-Umgebung stellt sie nicht zur Verfügung, während React Router davon ausgeht, dass sie vorhanden sind; daher werden sie aus Nodes node:util-Modul entliehen:

    import { TextEncoder, TextDecoder } from 'node:util'
    import '@testing-library/jest-dom'
    
    Object.assign(globalThis, { TextEncoder, TextDecoder })
    

    Stil- und Dateimocke

    Jest hat keine Ahnung, wie man eine CSS-Datei oder ein PNG-File importiert. Die beiden untenstehenden Stumpfmodule sind die Orte, an denen moduleNameMapper diese Importe umleitet, sodass eine Komponente mit import './App.css' den Testlauf nicht zum Abbruch bringt:

    // test/styleMock.js
    module.exports = {}
    
    // test/fileMock.js
    module.exports = 'test-file-stub'
    

    src/App.test.tsx

    Schließlich der Test, der die gesamte Konfiguration überprüft. Er rendernt App innerhalb eines MemoryRouter, der den Routing-Zustand im Speicher speichert anstelle der tatsächlichen Browser-URL zu lesen, und prüft, ob der Platzhaltext vorhanden ist:

    import { render, screen } from '@testing-library/react'
    import { MemoryRouter } from 'react-router'
    import App from './App'
    
    test('renders the placeholder route content', () => {
      render(
        <MemoryRouter>
          <App />
        </MemoryRouter>,
      )
      expect(screen.getByText(/routes coming soon/i)).toBeInTheDocument()
    })
    

    Auch wenn dieser Test klein ist, berührt er jeden Aspekt der Infrastruktur: die TSX-Kompilierung, das ESM-Router-Paket, die Textkodierungs-Polyfills, die Verarbeitung von import.meta sowie den jest-dom-Matcher. Wenn er bestanden wird, ist die Einrichtung in Ordnung.

    Prettier: Ende der Debatten über Formatierung

    Pakete: prettier, eslint-config-prettier

    npm install -D prettier eslint-config-prettier
    
    • prettier formatiert Ihren Code in einem einheitlichen Stil, meist beim Speichern.
    • eslint-config-prettier hat ein einziges, spezifisches Ziel: Es deaktiviert ESLint-Regeln, die mit der Formatierung durch Prettier kollidieren, wie beispielsweise Regeln zu Anführungszeichen, Semikolons und nachgestellten Kommas.

    Das zweite Paket fügt keine eigenen Regeln hinzu; es verhindert lediglich, dass die beiden Tools miteinander in Konflikt geraten. In eslint.config.js muss es die letzte Eintragung in Ihrer Konfigurationsliste sein, da spätere Einträge frühere überschreiben – es muss also die anderen überschreiben und nicht von ihnen überschrieben werden.

    Warum das zusätzliche Paket sinnvoll ist

    Ohne automatische Formatierung neigt die Überprüfungszeit dazu, sich eher nach Tabulatoren als nach Leerzeichen auszurichten – anstatt logisch zu sein. Prettier bietet absichtlich nur wenige Optionen an, sodass kaum noch Diskussionsbedarf besteht – und genau das ist der Sinn dahinter.

    Alles zusammenfügen

    Ein Mangel bleibt bestehen. tsc -b prüft alles unter src, einschließlich der Testdateien, und kennt standardmäßig nichts über test oder expect. Fügen Sie die relevanten Typpakete der types-Array in tsconfig.app.json hinzu:

    "types": ["vite/client", "jest", "@testing-library/jest-dom"]
    

    Dann führen Sie die vollständige Überprüfungssequenz aus, wobei zuerst der günstigste Schritt ausgeführt wird:

    npm run lint    # fast, catches obvious mistakes
    npm test        # fast, catches broken behaviour
    npm run build   # slower — real compile, real Tailwind output
    npm run dev     # slowest — but the only one that proves it renders
    

    Linting ist schnell und erkennt offensichtliche Fehler, Tests bestätigen das Verhalten, der Build führt eine echte Kompilierung durch und erzeugt die tatsächliche Tailwind-Ausgabe, während der Dev-Server – die langsamste Überprüfung – der einzige ist, der beweist, dass die Anwendung im Browser dargestellt wird. Wenn alle vier Schritte erfolgreich sind, ist die Grundlage geschaffen – ohne auch nur eine Zeile an Funktionscode.

    Eine Anmerkung zu Alternativen

    Ein Großteil des Jest-Bereichs – die Babel-Presets, das import.meta-Plugin sowie die ESM-Ausnahmen – existiert, weil Jest nicht Vites Build-Pipeline teilt. Wenn Sie weniger Komponenten bevorzugen, nutzt Vitest Ihre Vite-Konfiguration und arbeitet mit denselben Testing Library-Paketen. Für einen anderen Ansatz zur Reduzierung der Test-Tools finden Sie unseren Leitfaden zu der Ersetzung von Jest durch Node’s natives Test-Tool. Die obige Jest-Einrichtung bleibt eine solide Wahl, wenn Ihr Team bereits mit Jest vertraut ist oder auf sein Ökosystem angewiesen ist.

    Kernpunkte

    • Betrachten Sie jede Abhängigkeit als Entscheidung: Erfahren Sie, wozu sie dient und was ohne sie fehlt.
    • Tailwind v4 benötigt lediglich das Vite-Plugin sowie eine CSS-Import-Anweisung; es ist keine Konfigurationsdatei erforderlich.
  • Redux Toolkit speichert die Daten und React Redux verbindet sie mit den Komponenten; typisierte Hooks sorgen für eine klare Nutzung, während der lokale UI-Zustand weiterhin in useState gehalten werden sollte.
  • Durch die frühzeitige Einbeziehung des Routers wird jede zukünftige Seite mit nur einer Änderung erstellt.
  • Jest in einem Vite-Projekt benötigt einen Runner, eine DOM-Umgebung, drei Pakete aus der Testing Library, eine Babel-Toolkette sowie einige gezielte Konfigurationsanpassungen; falls eine Anpassung ignoriert zu werden scheint, sollte der Jest-Cache geleert werden.
  • Installieren Sie abhängige Pakete mit einem einzigen Befehl und verwenden Sie explizite Zeilenfortsetzungen, wenn ein Befehl über mehrere Zeilen geht.
  • Weitere Literatur