Zum Inhalt springen
aviral gupta

// B4.2 · ca. 30 Min. · Einstieg

Ein Vite-Projekt von Grund auf

Nach dieser Lektion legen Sie auf Ihrem Computer ein React-Projekt mit Vite an, erklären, welche Datei Ihre App auf die Seite bringt, und starten, bauen und prüfen es.

Lektion 2 von 4 in B4 Ein Projekt einrichten

Danach können Sie

  • Ein Vite-React-Projekt mit npm create vite anlegen, auf einer Node.js-Version, die Vite unterstützt
  • Erklären, wie index.html, src/main.jsx und src/App.jsx die App auf die Seite bringen
  • Den Entwicklungsserver starten, nach dist bauen und den Build mit den npm-Skripten ansehen
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion B4.1: von Grund auf bauen. Welchen Vite-Befehl zeigt die Seite "Build a React app from Scratch" von react.dev?

  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie voraus, bevor Sie weiterlesen. npm run dev läuft, und Sie öffnen http://localhost:5173/. Welche Datei des Projekts lädt der Browser zuerst?

  3. Üben · Aufgabe 3 von 7

    node --version gibt v18.20.4 aus. Was brauchen Sie laut vite.dev für Vite?

  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jeder Datei und jedem Ordner des neuen Projekts die Aufgabe zu.

  5. Üben · Aufgabe 5 von 7

    Ergänzen Sie das Modul, aus dem src/main.jsx createRoot importiert.

    import { StrictMode } from 'react'
    import { createRoot } from '____'
    import './index.css'
    import App from './App.jsx'
    import { createRoot } from ''
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Die src/main.jsx Ihres Projekts legt wie die Vorlage <StrictMode> um App, und npm run dev liefert die Seite aus. App rendert zwei Counter-Komponenten, und Counter gibt in seinem Rumpf etwas aus. Wie viele Zeilen zeigt die Konsole, wenn die Seite lädt?

    function Counter() {
      console.log('Counter');
      const [count, setCount] = useState(0);
      return <button onClick={() => setCount((count) => count + 1)}>count is {count}</button>;
    }
    
    function App() {
      return (
        <>
          <Counter />
          <Counter />
        </>
      );
    }
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe: Ihr eigenes Vite-Projekt. Prüfen Sie in einem Terminal node --version, führen Sie dann npm create vite@latest my-app -- --template react, cd my-app, npm install und npm run dev aus und öffnen Sie die ausgegebene Local-Adresse. Während der Server läuft, ersetzen Sie src/App.jsx durch Ihre eigene Komponente und speichern: Die Seite aktualisiert sich. Stoppen Sie den Server mit Strg+C, führen Sie npm run build aus und sehen Sie in dist nach, dann führen Sie npm run preview aus und öffnen dessen Adresse.

    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

Die Form der Vorlage, im Runner

Ein Vite-Projekt hat seinen Einstieg in src/main.jsx und seine erste Komponente in src/App.jsx und importiert ./index.css. Hier exportiert main.jsx nur App: Der Runner tut, was src/main.jsx tut, und rendert sie in #root in <StrictMode>, und er wendet index.css selbst an. App.jsx importiert einen Counter aus dessen eigener Datei, mit Endung, wie Dateien in src/ es tun. Counter nutzt die Updater-Form der Vorlage, setCount((count) => count + 1). Der Schnappschuss zeigt #root nach dem ersten Rendern.

main.jsx

import App from './App.jsx';

// In a Vite project, src/main.jsx ends with
//   createRoot(document.getElementById('root')).render(
//     <StrictMode>
//       <App />
//     </StrictMode>,
//   )
// and imports './index.css'. The runner does both for this default export.
export default App;

App.jsx

import Counter from './Counter.jsx';

export default function App() {
  return (
    <>
      <h1>my-app</h1>
      <Counter />
      <p>
        Edit <code>src/App.jsx</code> and save to test <code>HMR</code>
      </p>
    </>
  );
}

Counter.jsx

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount((count) => count + 1)}>
      count is {count}
    </button>
  );
}

index.css

body {
  font-family: system-ui, sans-serif;
}

Ausführen mit

npm run dev

Ausgabe

<!-- #root -->
<div id="root"><h1>my-app</h1><button>count is 0</button><p>Edit <code>src/App.jsx</code> and save to test <code>HMR</code></p></div>
  • <StrictMode> rendert kein eigenes Element: #root enthält nur, was App zurückgibt.
  • Counter.jsx wird als ./Counter.jsx importiert, mit Endung, wie im Ordner src/ eines Vite-Projekts.
  • index.css wendet der Runner an; in Vite braucht src/main.jsx dafür import './index.css'.
  • Im Browser bleibt die Seite aktiv: Klicken Sie auf den Button. In einem Vite-Projekt würde das Speichern von App.jsx sie über HMR aktualisieren.
Ändern und ausführen

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 React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Übungen

Übung 1 von 2

Den Einstieg schreiben, wie src/main.jsx es tut

src/main.jsx rendert App in das Element aus index.html. Schreiben Sie diesen Schritt als Funktion: start(rootElement) erzeugt eine Root für rootElement, rendert <App /> in <StrictMode> hinein und gibt die Root zurück. App.jsx ist vorgegeben. Ausführen zeigt App über den Default-Export; die Tests setzen ein leeres Element auf die Seite, rufen start damit auf und klicken auf den Zähler.

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 React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Hinweise
  1. Hinweis 1

    createRoot allein zeigt nichts an; die Root braucht einen Aufruf von render.

  2. Hinweis 2

    Übernehmen Sie die Form der Vorlage: root.render(<StrictMode><App /></StrictMode>);

  3. Hinweis 3

    Beenden Sie die Funktion mit return root;

Eine Lösung zeigen

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

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';

// For the runner, which renders this into #root.
export default App;

// What src/main.jsx does, as a function that works for any element.
export function start(rootElement) {
  const root = createRoot(rootElement);
  root.render(
    <StrictMode>
      <App />
    </StrictMode>,
  );
  return root;
}
Auf dem eigenen Computer ausführen

Installieren Sie React 19.3 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.jsx

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';

// For the runner, which renders this into #root.
export default App;

// What src/main.jsx does, as a function that works for any element.
export function start(rootElement) {
  const root = createRoot(rootElement);
  // TODO: render <App /> inside <StrictMode>, then return the root.
}

main.test.jsx

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {act, within} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {start} from './main.jsx';

// The page of index.html: an empty element for the app.
function indexHtml() {
  document.body.innerHTML = '<div id="app-root"></div>';
  return document.getElementById('app-root');
}

async function mount(element) {
  let root;
  await act(async () => {
    root = start(element);
  });
  return root;
}

async function unmount(root) {
  if (root && typeof root.unmount === 'function') await act(async () => root.unmount());
}

test('start zeigt App im Element', async () => {
  const element = indexHtml();
  const root = await mount(element);
  const heading = within(element).queryByRole('heading', {level: 1});
  assert.equal(heading?.textContent, 'my-app', 'das Element enthält ' + JSON.stringify(element.innerHTML));
  await unmount(root);
});

test('Der Zähler funktioniert nach start', async () => {
  const user = userEvent.setup();
  const element = indexHtml();
  const root = await mount(element);
  const button = within(element).queryByRole('button', {name: 'count is 0'});
  assert.ok(button !== null, 'im Element gibt es keinen Button "count is 0"');
  await user.click(button);
  await user.click(button);
  assert.equal(button.textContent, 'count is 2', 'nach zwei Klicks zeigt der Button ' + JSON.stringify(button.textContent));
  await unmount(root);
});

test('start gibt die Root zurück', async () => {
  const element = indexHtml();
  const root = await mount(element);
  assert.equal(typeof root?.render, 'function', 'start hat ' + String(root) + ' zurückgegeben, nicht die Root von createRoot');
  await unmount(root);
});

App.jsx

import { useState } from 'react';

export default function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>my-app</h1>
      <button onClick={() => setCount((count) => count + 1)}>count is {count}</button>
    </>
  );
}

Legen Sie main.jsx in einem Vite-React-Projekt (npm create vite@latest, Vorlage react) als App.jsx in src/ ab und starten Sie es mit npm run dev. React rendert es dort wie hier in <StrictMode>.

Programm ausführen:

npm run dev

Für die Prüfungen gibt es noch keinen Befehl auf Ihrem Computer. Sie stehen in main.test.jsx, geschrieben mit node:test und React Testing Library.

Übung 2 von 2

Eine Komponente pro Datei

Header und Counter des Teeladens liegen jetzt in Header.jsx und Counter.jsx, wie Dateien im Ordner src/ eines Vite-Projekts. main.jsx hat noch eine alte Kopie von Counter, die nicht zählen kann. Importieren Sie Counter aus ./Counter.jsx, löschen Sie die alte Kopie und rendern Sie unter der Überschrift einen Counter mit der Beschriftung Green und einen mit Black. Jeder muss seine eigenen Klicks zählen.

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 React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Hinweise
  1. Hinweis 1

    Counter.jsx hat einen Default-Export, also importieren Sie ohne geschweifte Klammern: import Counter from './Counter.jsx';

  2. Hinweis 2

    Zwei Komponenten können in einer Datei nicht denselben Namen tragen, also muss die alte function Counter weg.

  3. Hinweis 3

    Übergeben Sie die Beschriftung als Prop: <Counter label="Green" /> und <Counter label="Black" />.

Eine Lösung zeigen

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

import Header from './Header.jsx';
import Counter from './Counter.jsx';

export default function App() {
  return (
    <>
      <Header title="Tea shop" />
      <Counter label="Green" />
      <Counter label="Black" />
    </>
  );
}
Auf dem eigenen Computer ausführen

Installieren Sie React 19.3 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.jsx

import Header from './Header.jsx';

// TODO: Counter now lives in Counter.jsx. Import it from there,
// delete this old copy, and render one Counter per tea.
function Counter() {
  return <button>Tea: 0</button>;
}

export default function App() {
  return (
    <>
      <Header title="Tea shop" />
      <Counter />
    </>
  );
}

main.test.jsx

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {render, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from './main.jsx';

test('Die Seite zeigt die Überschrift Tea shop und zwei Zähler', () => {
  render(<App />);
  assert.equal(screen.getByRole('heading', {level: 1}).textContent, 'Tea shop', 'die Überschrift');
  const labels = screen.queryAllByRole('button').map((button) => button.textContent);
  assert.deepEqual(labels, ['Green: 0', 'Black: 0'], 'die Buttons zeigen ' + JSON.stringify(labels));
});

test('Green zählt seine eigenen Klicks', async () => {
  const user = userEvent.setup();
  render(<App />);
  const green = screen.queryByRole('button', {name: 'Green: 0'});
  assert.ok(green !== null, 'es gibt keinen Button "Green: 0"');
  await user.click(green);
  await user.click(green);
  assert.equal(green.textContent, 'Green: 2', 'nach zwei Klicks zeigt Green ' + JSON.stringify(green.textContent));
  const black = screen.queryByRole('button', {name: /^Black/});
  assert.equal(black?.textContent, 'Black: 0', 'der Klick auf Green hat Black geändert zu ' + JSON.stringify(black?.textContent));
});

Header.jsx

export default function Header({ title }) {
  return <h1>{title}</h1>;
}

Counter.jsx

import { useState } from 'react';

export default function Counter({ label }) {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount((count) => count + 1)}>
      {label}: {count}
    </button>
  );
}

Legen Sie main.jsx in einem Vite-React-Projekt (npm create vite@latest, Vorlage react) als App.jsx in src/ ab und starten Sie es mit npm run dev. React rendert es dort wie hier in <StrictMode>.

Programm ausführen:

npm run dev

Für die Prüfungen gibt es noch keinen Befehl auf Ihrem Computer. Sie stehen in main.test.jsx, geschrieben mit node:test und React Testing Library.

Häufige Fehler

Den Import von StrictMode weglassen

import { createRoot } from 'react-dom/client';

export default function App() {
  return <h1>my-app</h1>;
}

// Typed from src/main.jsx without its first line, for a second root
const preview = document.createElement('div');
document.body.append(preview);
createRoot(preview).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

Was React ausgibt

ReferenceError: StrictMode is not defined

Warum, und die Lösung

<StrictMode> ist eine Komponente aus React und muss wie jede andere importiert werden: import { StrictMode } from 'react'. JSX importiert sie nicht für Sie. Der Lauf stoppt mit Uncaught ReferenceError, bevor in dieser Root etwas rendert.

Die Komponente umbenennen, aber nicht ihren Export

import App from './App.jsx';

export default App;

Was React ausgibt

ReferenceError: App is not defined

Warum, und die Lösung

export default App; am Ende einer Datei exportiert einen Namen, der in dieser Datei existieren muss. Nach der Umbenennung gibt es in App.jsx kein App mehr, also scheitert das Modul beim Laden, und nichts rendert. Exportieren Sie den neuen Namen, export default Shop;, oder schreiben Sie in einem Zug export default function Shop(). Die importierende Datei darf ihren eigenen Namen behalten: import App from './App.jsx' funktioniert weiter.

JSX in einer .js-Datei

import Counter from './Counter.js';

export default function App() {
  return <Counter />;
}

Was React ausgibt

SyntaxError: Unexpected token '<'

Warum, und die Lösung

Der Runner dieses Kurses wandelt JSX nur in .jsx-Dateien in JavaScript um, also wird Counter.js als reines JavaScript geladen, wo < keinen Ausdruck beginnen kann, und nichts läuft. vite.dev nennt .jsx und .tsx als die Dateien mit JSX-Unterstützung, und die Komponenten der Vorlage sind .jsx-Dateien. Benennen Sie die Datei in Counter.jsx um und importieren Sie sie als ./Counter.jsx. Die Formulierung ist die von V8; Firefox und Safari formulieren es anders.

React im Browser: React 19.3.0 (Entwicklungs-Build) und React Testing Library, MIT, von dieser Website ausgeliefert; JSX übersetzt TypeScript 6.0.3, Apache-2.0. 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

Das Projekt anlegen

Prüfen Sie zuerst node --version: Vite verlangt Node.js 20.19+ oder 22.12+. Dann führen Sie npm create vite@latest my-app -- --template react aus. Ab npm 7 ist das zusätzliche -- nötig, damit --template bei create-vite ankommt. vite.dev nennt die Vorlagen react, react-compiler, react-ts und react-compiler-ts; die Seite von react.dev nutzt react-ts, also TypeScript, dieser Kurs react, also JavaScript. create-vite gibt danach die nächsten Schritte aus: cd my-app, npm install, npm run dev. Bei einem Lauf am 05.10.2026 installierte das vite 8.3.2 und react 19.3.0.

index.html, src/main.jsx, src/App.jsx

In einem Vite-Projekt liegt index.html im Projektordner, nicht in public/: Sie ist der Einstiegspunkt. Sie enthält ein leeres <div id="root"></div> und <script type="module" src="/src/main.jsx">. src/main.jsx importiert StrictMode, createRoot, ./index.css und App aus ./App.jsx und ruft dann createRoot(document.getElementById('root')).render(<StrictMode><App /></StrictMode>) auf. src/App.jsx ist die Komponente, die Sie bearbeiten. Strict Mode rendert Komponenten zweimal, nur in der Entwicklung. In diesem Kurs spielt Ihre main.jsx die Rolle von App.jsx: Der Runner übernimmt die Aufgabe von main.jsx und wendet .css-Dateien selbst an, also importieren Sie hier nie CSS, ein Vite-Projekt aber schon.

Starten, bauen, ansehen

package.json enthält die Skripte. npm run dev startet vite, einen Entwicklungsserver, der Local: http://localhost:5173/ ausgibt. Lassen Sie ihn laufen: Wenn Sie src/App.jsx speichern, aktualisiert Hot Module Replacement (HMR) die offene Seite, wozu der Text der Vorlage "Edit src/App.jsx and save to test HMR" einlädt. npm run build startet vite build und schreibt eine gebündelte, optimierte App in den Ordner dist. npm run preview startet vite preview, das dist unter http://localhost:4173 ausliefert, damit Sie den Build lokal prüfen. Es ist nicht als Produktionsserver gedacht: Veröffentlicht wird der Ordner dist.

Quellen

Zuletzt geprüft am 5. Oktober 2026