# Wie Laravel mit JavaScript und CSS umgeht — und was das für uns heisst

Diese Doku beantwortet drei Fragen mit Blick auf einen **möglichen** (nicht
beschlossenen) Umzug auf Laravel: Wie kommen JS und CSS in Laravel auf die Seite?
Wird das gebündelt? Und was bedeutet das konkret für unsere frameworklose
`git-pull`-App?

Stand: Laravel 12.x / 13.x, Tailwind CSS v4, Vite 5+ (2025/2026). Sie ergänzt
[css-strategie.md](css-strategie.md) — dort steht die CSS-Namensstrategie und die
Durable-vs-Wegwerf-Abwägung (§5) — und
[frontend-abhaengigkeiten.md](frontend-abhaengigkeiten.md) — dort steht unser
heutiger „npm nur als Bezugsquelle, `dist/` committen"-Ansatz (§1). Diese Doku
schaut speziell auf **Asset-Verrohrung und Build-Pipeline**.

> **Umsetzungsstand** (siehe `CHANGELOG.md`): Von den unten als *durable* bewerteten
> Arbeiten sind bereits erledigt — Konsolidierung der neun `style.css` zu **einer**
> `css/app.css`, totes CSS entfernt, der zentrale `partials/head.php` mit lokal
> committetem `library/`. Die Vite-/Blade-/Tailwind-Aussagen bleiben unverändert:
> Sie beschreiben den *möglichen* Laravel-Weg, nicht den aktuellen Stand.

## Kurzantwort

**Ja, Laravel bündelt** — und zwar zwingend über **Vite** (seit Laravel 9.19 der
Default; Laravel Mix / Webpack sind Geschichte). Es gibt keinen unterstützten
„kein Build"-Weg mehr wie unseren heutigen. `npm run build` erzeugt aus
`resources/js` und `resources/css` minifizierte, tree-geshakete, inhaltsgehashte
Bundles in `public/build/`, plus eine `manifest.json`; im `<head>` steht nur noch
`@vite([...])`, das im Dev auf den HMR-Server und im Prod auf die gehashten
Dateien zeigt. Für uns heisst das: Unser committetes `library/` ist eine **Brücke,
keine dauerhafte Investition** — ein Laravel-Umzug ersetzt es durch npm-Deps +
Vite-Bundle und bringt einen Build-Schritt in den Deploy. Was den Umzug
**überlebt**, ist Token-CSS, die konsolidierte `app.css`, entferntes totes CSS und
sprechende Komponenten-Namen; **Wegwerfarbeit** wäre die no-build-Verrohrung selbst
und schwere BEM-Bäume.

---

## 1. Laravels Standard-Mechanismus: Vite

### 1.1 Die Pipeline im Überblick

Laravel liefert seit Version 9.19 **Vite** als Standard-Bundler mit (davor Laravel
Mix auf Webpack-Basis — das ist der veraltete Stand, der in vielen älteren
Tutorials noch steht). Eine frische Laravel-App bringt Vite und eine fertige
`vite.config.js` bereits mit; man muss nichts zusätzlich aufsetzen.

Die Bestandteile:

| Teil | Rolle |
|---|---|
| `resources/js/app.js` | JS-Entry-Point. Importiert weitere Module per ES-`import`. |
| `resources/css/app.css` | CSS-Entry-Point. |
| `vite.config.js` | Konfiguriert Vite; deklariert die Entry-Points via `laravel-vite-plugin`. |
| `@vite([...])`-Blade-Directive | Bindet die Assets im `<head>` ein — kontextabhängig Dev oder Prod. |
| `package.json` | npm-Abhängigkeiten (Vite, Plugins, Frontend-Libs). |
| `public/build/` | **Erzeugtes** Ausgabeverzeichnis der Production-Bundles (nicht ins Repo). |

Die typische `vite.config.js` einer Standard-App:

```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
});
```

Im Layout-Blade steht dann nur noch:

```blade
<head>
    {{-- ... --}}
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
```

Das ersetzt unsere heutige Kette aus einzelnen `<link>`/`<script>`-Tags in
`partials/head.php` (Bootstrap-CSS, custom-colors, FontAwesome, jQuery, Popper,
Bootstrap-JS, `script.js`, `csrf.js`) durch **eine** Directive. Welche Dateien
tatsächlich geladen werden, ergibt sich aus den `import`-Bäumen der beiden
Entry-Points — nicht mehr aus einer handgepflegten Tag-Liste.

### 1.2 `npm run dev` vs. `npm run build` — wird gebündelt?

**Ja, und in zwei Modi:**

**`npm run dev`** startet den **Vite-Dev-Server** mit **Hot Module Replacement
(HMR)**. `@vite` erkennt den laufenden Dev-Server automatisch und injiziert den
Vite-Client; Änderungen an JS/CSS erscheinen im Browser sofort, ohne vollen
Reload. Nichts wird auf die Platte geschrieben — die Assets werden zur Laufzeit vom
Dev-Server geliefert. (In Laravel 12 startet `composer run dev` bequem den PHP- und
den Vite-Server gemeinsam.)

**`npm run build`** erzeugt das **Production-Bundle** nach `public/build/`. Dabei
tut Vite (auf Basis von Rollup) genau das, was „bündeln" umfasst:

- **Bündeln**: ES-Module-`import`-Bäume werden zu wenigen Dateien zusammengefasst.
- **Minifizieren**: JS und CSS werden verkleinert.
- **Tree-Shaking**: ungenutzte Exporte fliegen raus — es landet nur, was wirklich
  importiert wird.
- **Cache-Busting per Content-Hash**: Dateinamen bekommen einen Hash aus dem Inhalt
  (`app-4f3c2a.js`). Ändert sich der Inhalt, ändert sich der Name — der Browser
  lädt garantiert die neue Version, alte bleiben cachebar. („versioned assets".)
- **`manifest.json`**: bildet die Entry-Namen auf die gehashten Dateinamen ab.
  `@vite` liest im Prod-Modus dieses Manifest und schreibt die korrekten
  `<link>`/`<script>`-Tags — inklusive **automatisch der CSS**, die aus dem
  JS-Entry importiert wurde.

Kurz: Der ganze Zweck, den wir heute mit committeten `dist/`-Dateien und
Content-Cache-Bewusstsein von Hand umgehen, ist in Laravel der Normalfall — nur
automatisiert und mit Tree-Shaking/Minifizierung obendrauf.

## 2. CSS in Laravel heute: Tailwind ist der Default

### 2.1 Was die Starter Kits mitbringen

Laravel hat seine Starter Kits **überarbeitet**: Breeze und Jetstream sind durch
drei neue, zweckgebaute Starter Kits ersetzt — **React** (Inertia 2, React 19),
**Vue** (Composition API, TypeScript) und **Livewire** (bleibt in PHP/Blade). Für
CSS nutzen **alle drei Tailwind CSS v4**. Das ältere `laravel/ui` mit
Bootstrap-Scaffolding gilt als Legacy; **Bootstrap ist kein Default-Pfad mehr.**

### 2.2 Wie CSS eingebunden wird

CSS läuft durch dieselbe Vite-Pipeline. `resources/css/app.css` ist der Entry;
unter Tailwind v4 steht dort im Kern:

```css
@import "tailwindcss";
```

Tailwind v4 ist ein **grundlegender Bruch** zu v3: Es gibt **keine
`tailwind.config.js` mehr** — das CSS selbst ist die Single Source of Truth. Das
Theme (Farben, Fonts, Spacing) wird per **`@theme`-Directive** direkt im CSS als
CSS-Custom-Properties definiert, und Tailwind generiert daraus die Utility-Klassen:

```css
@import "tailwindcss";

@theme {
    --color-primary: #4578a5;   /* erzeugt bg-primary, text-primary, … */
    --radius-card: 0.5rem;
}
```

Weil `@theme` echte CSS-Variablen ausgibt, sind dieselben Tokens auch in
handgeschriebenem CSS nutzbar (`var(--color-primary)`) — das Design-System bleibt
einfach-gesourct. **Genau hier landet später unser `css/custom-colors.css`**
(siehe §4).

Eingebunden wird das CSS über Vite (`@tailwindcss/vite`-Plugin in der
`vite.config.js`); im `@vite`-Aufruf muss die CSS oft nicht einmal separat stehen,
wenn sie aus `app.js` importiert wird — dann zieht sie das Manifest automatisch mit.

### 2.3 Bootstrap KANN man weiter über Vite nutzen

Ein Tailwind-Zwang besteht technisch nicht. Bootstrap läuft in Laravel problemlos
über Vite:

```bash
npm install bootstrap @popperjs/core
```

```js
// resources/js/app.js
import 'bootstrap';                 // Bootstrap-JS (Popper im Bundle)
import '../css/app.css';            // zieht die Bootstrap-CSS/SCSS mit
```

```css
/* resources/css/app.css — entweder das fertige CSS … */
@import 'bootstrap/dist/css/bootstrap.min.css';
```

Oder, mit SCSS (`npm i -D sass`), ein echtes Theme über Bootstrap-Variablen —
`resources/css/app.scss` mit `@import "bootstrap/scss/bootstrap"` und
vorangestellten `$primary`-Overrides. Vite kompiliert SCSS out of the box, sobald
`sass` installiert ist. Das ist der Weg, auf dem unser bestehender
Bootstrap-Bestand einen Laravel-Umzug ohne visuelles Redesign überleben könnte —
er ist nur nicht mehr der Pfad des geringsten Widerstands.

## 3. Blade & Komponenten: das Ende von „eine .php pro Seite + Head-Partial"

Unser heutiges Muster — pro URL eine `.php`, die `partials/head.php`,
`partials/header.php` usw. per `include` einzieht — hat in Blade zwei direkte
Entsprechungen:

**Layout-Blade** ersetzt das Head-/Header-Partial. Ein `layouts/app.blade.php`
enthält `<head>` samt `@vite(...)` einmal; jede Seite `@extends('layouts.app')`
und füllt nur ihren Inhalt in einen `@yield`/`@section`-Slot. Das ist dieselbe
Idee wie unser Partial, nur als Framework-Konvention statt handgebautem `include`.

**Blade-Components** (`<x-...>`) ersetzen die verstreuten `echo`-Markup-Blöcke.
Aus unserem `termineSidebar.php` würde `<x-termine-sidebar :termine="$t" />`, aus
`bpTable.php` würde `<x-bptable ... />`. Der **semantische Block-Name** aus der
CSS-Strategie (`lbm-termine`, `lbm-bptable`) wird zum **Component-Namen** — die
Erkenntnis „wo fängt eine Komponente an?" ist genau die Information, die Blade
braucht.

Wichtig für die CSS-Planung: **Component-scoped Markup entwertet BEMs Kernnutzen.**
Global-eindeutige Klassennamen gegen Kollisionen braucht man weniger, wenn die
Komponente das Markup ohnehin kapselt (und Tailwind-Utilities die Kosmetik tragen).
Deshalb steht in [css-strategie.md §7](css-strategie.md) die Empfehlung „BEM light":
Block-Namen ja, schwerer `__element--modifier`-Apparat nein.

## 4. Was heisst das für UNS — der Kern

### 4.1 Deploy: `git pull` ohne Build vs. Vite-Build

Unser heutiger Deploy ist bewusst build-frei: `package.json` deklariert nur, die
fertigen `dist/`-Dateien liegen committet unter `library/` (JS-Pendant zum
ebenfalls committeten `vendor/`), der Server macht `git pull`, fertig
([frontend-abhaengigkeiten.md §1](frontend-abhaengigkeiten.md)). Das ist für den
Bootstrap-4-Bestand **richtig** und bleibt es bis zu einem Framework-Wechsel.

Ein Laravel-Umzug **beendet dieses Modell zwangsläufig**, weil `public/build/`
ein *erzeugtes* Artefakt aus `npm run build` ist. Zwei gangbare Deploy-Muster:

- **Build in CI** (der übliche Weg): CI/CD führt `npm ci && npm run build` aus und
  deployt das Ergebnis; `public/build/` und `node_modules/` bleiben aus dem Repo.
  Das ist Standard, verlangt aber eine Build-Umgebung im Deploy — den Schritt, den
  wir heute gerade *nicht* haben.
- **Build-and-commit** (Brücke, falls der Server hart bei `git pull` bleiben muss):
  `public/build/` würde committet, analog zu heute `library/`. Möglich, aber gegen
  die Framework-Konvention, und man handelt sich Merge-Konflikte auf gehashten
  Bundle-Dateien ein. Nur als Übergangskrücke sinnvoll.

Konsequenz für **jetzt**: keine Energie in ausgefeilte no-build-Tooling-Konstrukte
stecken, die Vite später ohnehin wegräumt. Das committete `library/` erfüllt seinen
Zweck heute — mehr soll es nicht werden.

### 4.2 Durable vs. Wegwerfarbeit

Deckungsgleich mit [css-strategie.md §5](css-strategie.md), hier auf den
Asset-Blickwinkel zugespitzt:

**Durable — überlebt jeden Weg, inklusive Laravel:**

- **Design-Tokens als CSS-Custom-Properties** (`css/custom-colors.css`). Wandern in
  Tailwind v4 1:1 in den `@theme`-Block; `--primary: #4578A5` bleibt die Quelle.
  `color-mix()` ist natives CSS und überlebt ohnehin alles.
- **Konsolidierung der neun `style.css` zu einer `css/app.css`.** Vite importiert
  genau *einen* CSS-Entry — eine Datei ist der Startpunkt, neun sind Ballast.
- **Totes CSS entfernen** (`.termin-item`-Block, tote `#header`-Regeln). Weniger zu
  migrieren ist immer richtig.
- **Sprechende Komponenten-Namen** (`lbm-termine`, `lbm-bptable`). Werden zu
  Blade-Component-Namen (`<x-termine>`).
- **`script.js` / `function.js` → modulares JS.** Der Umzug nach `resources/js` mit
  `import`-Struktur ist wenig Aufwand, sobald der Code in sauberen Funktionen/Modulen
  vorliegt statt als globale Script-Datei. Die *Aufteilung in Module* ist durable,
  die konkrete Einbindung nicht.
- **Optik(Klasse)/Funktion(`id`,`data-`) trennen.** Blade + Tailwind erwarten genau
  diese Trennung; reine Hygiene.

**Wegwerfarbeit — nur wertvoll, solange wir build-frei bei Bootstrap bleiben:**

- **Die no-build-Asset-Verrohrung selbst**: `dist/` nach `library/` kopieren, Pfade
  in `head.php` pflegen, PDF.js-Worker-URL von Hand setzen. Vite übernimmt das
  komplett — diese Mechanik wird ersatzlos abgebaut.
- **Schwere, projektweite BEM-`__element--modifier`-Bäume** über alle
  `echo`-Stellen. Blade-Components + Tailwind schreiben das Markup neu; die
  feingranulare Umbenennung wäre zweimal Arbeit am selben Markup. Der **Block-Name
  überlebt, der Element/Modifier-Apparat nicht.**
- **Eigene Utility-Klassen, die Bootstrap-Utilities duplizieren** — Tailwind ersetzt
  sie ohnehin.

### 4.3 Handlungsempfehlung (passt zur `css-strategie.md`-Linie „nur Durable jetzt")

**JETZT gefahrlos tun** (zahlt in jedem Szenario, hängt nicht am Laravel-Entscheid):

1. Token-Schicht in `custom-colors.css` vervollständigen. → wird `@theme`.
2. Neun `style.css` zu einer `css/app.css` konsolidieren, Widersprüche auflösen.
   → wird der Vite-CSS-Entry.
3. Totes CSS entfernen.
4. In Komponenten denken, *einen* sprechenden `lbm-`-Block-Namen je Block — „BEM
   light", **ohne** Vollausbau. → werden Blade-Component-Namen.
5. `script.js`/`function.js` in saubere Module/Funktionen gliedern. → wandern nach
   `resources/js`.
6. Optik/Funktion entkoppeln (Klasse vs. `data-`/`id`).

**Erst BEIM Laravel-Entscheid** (hängt daran, jetzt nicht vorwegnehmen):

- Vite einführen, die `library/`-`dist/`-Brücke abbauen, Deploy auf Build-in-CI
  umstellen.
- Bootstrap behalten (via Vite/SCSS, §2.3) **vs.** auf Tailwind wechseln — der
  natürliche Entscheidungsmoment, verzahnt mit dem offenen BS4→BS5-Thema. Ein
  Tailwind-Wechsel ist kein CSS-Refactoring, sondern ein visuelles Redesign plus
  Markup-Neuschrift; nicht vorwegnehmen, aber auch nicht verbauen.
- Komponenten in Blade-Components überführen, `head.php`/`header.php` in ein
  Layout-Blade auflösen.
- Tokens in `@theme` übernehmen (Copy der Custom Properties).

**Kurz:** Wir bauen jetzt nur das, was der Umzug mitnimmt (Token, eine `app.css`,
totes CSS raus, Komponenten-Namen, modulares JS, Optik/Funktion getrennt), und
verzichten bewusst auf die no-build-Sonderkonstruktionen und schwere BEM-Mechanik,
die Vite und Blade/Tailwind wieder verwerfen würden.

## Quellen

- [Asset Bundling (Vite) — Laravel 12.x Docs](https://laravel.com/docs/12.x/vite)
- [Starter Kits — Laravel 12.x Docs](https://laravel.com/docs/12.x/starter-kits)
- [Laravel Starter Kits: A New Beginning (Laravel Blog)](https://laravel.com/blog/laravel-starter-kits-a-new-beginning-for-your-next-project)
- [Theme variables — Tailwind CSS Docs](https://tailwindcss.com/docs/theme)
- [Functions and directives (`@theme`, `@import`) — Tailwind CSS Docs](https://tailwindcss.com/docs/functions-and-directives)
- [Tailwind CSS Installation Guide for Laravel](https://tailwindcss.com/docs/guides/laravel)
