| Tool | Version | Zweck |
|---|---|---|
| PHP | 8.1 oder neuer | Serverseitiges Rendering |
| Node.js | 18+ | Build-Prozess (esbuild) |
| cwebp | optional | WebP-Konvertierung im Build |
Optional: wget (Fallback im Rechtstext-Sync-Script).
Entwicklungsserver starten:
php -S 127.0.0.1:8080 router.phpAlternativ mit CI-Router (robusteres 404-Handling):
php -S 127.0.0.1:8080 scripts/ci-router.phpVerfügbare Routen:
http://127.0.0.1:8080/— Startseitehttp://127.0.0.1:8080/weihnachtsmaerchen/— Weihnachtsmärchenhttp://127.0.0.1:8080/impressum/— Impressumhttp://127.0.0.1:8080/datenschutz/— Datenschutz
npm installDev-Dependencies: esbuild (^0.28.0), playwright (^1.59.1).
node scripts/build.jsDer Build-Prozess führt drei Schritte aus:
- Quelle:
assets/css/main.css(756 Zeilen) - Ziel:
assets/css/main.min.css - Tool: esbuild
- Quelle:
assets/js/main.js(73 Zeilen) - Ziel:
assets/js/main.min.js - Tool: esbuild
- Konvertiert alle JPEG/PNG-Dateien in
assets/img/zu WebP - Tool:
cwebp(Qualität 80, Methode 6) - Ausnahmen: Dateien mit
iconoderlogoim Namen behalten das PNG-Format - Bereits existierende WebP-Dateien werden nicht erneut konvertiert
Die asset()-Helper-Funktion hängt den Datei-Timestamp als Versionsparameter an:
asset('/assets/css/main.min.css')
// → /assets/css/main.min.css?v=1712345678Bei Änderungen an einer Asset-Datei ändert sich automatisch der Timestamp und damit die URL — kein manueller Cache-Bust nötig.
Die Templates laden immer die minifizierten Versionen:
<link rel="stylesheet" href="<?= e(asset('/assets/css/main.min.css')) ?>">
<script src="<?= e(asset('/assets/js/main.min.js')) ?>" defer></script># PHP-Server auf Port 8082 starten
php -S 127.0.0.1:8082 scripts/ci-router.php &
# Tests ausführen
node scripts/playwright-test.jsGetestet werden:
| Seite | Viewport | Beschreibung |
|---|---|---|
| Startseite | Desktop (1280×800) | Hero-Bild, Layout, Scroll |
| Startseite | iPhone 13 | Mobile Navigation, Responsive |
| Weihnachtsmärchen | Desktop (1280×800) | Event-Meta, Poster, Layout |
| Weihnachtsmärchen | iPhone 13 | Mobile Ansicht |
Der Test scrolled automatisch, um Lazy-Loading auszulösen, und prüft ob das Hero-Bild vorhanden ist.
Die Pipeline (.github/workflows/deploy.yml) führt im test-Job folgende Checks aus:
- PHP-Syntax-Prüfung: Alle
.php-Dateien werden mitphp -lgeprüft - Route-Tests: Alle 4 Routen müssen HTTP 200 zurückgeben
- Asset-Tests: Kritische Assets müssen erreichbar sein:
/assets/css/main.css/assets/js/main.js/assets/img/vb-logo.png/assets/img/vb-icon.png/assets/img/vorhang.jpg/assets/img/weihnachtsmaerchen-2025.jpeg
- 404-Test: Unbekannte Route muss HTTP 404 zurückgeben
Schritt-für-Schritt-Anleitung:
Beispiel: spielzeit.php im Projektverzeichnis:
<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
$meta = meta([
'title' => 'Spielzeit 2026/2027 | Volksbühne Worms 1908 e. V.',
'description' => 'Aktuelle Spielzeit der Volksbühne Worms.',
'canonical' => site_url('/spielzeit/'),
]);
$activeNav = 'spielzeit';
$bodyClass = 'page-spielzeit';
$structuredData = null;
require __DIR__ . '/partials/layout-start.php';
?>
<main id="main-content">
<section class="hero hero-inner">
<div class="container">
<p class="eyebrow">Aktuelles</p>
<h1>Spielzeit 2026/2027</h1>
<p class="lead">Übersicht aller Stücke und Termine.</p>
</div>
</section>
<section class="section">
<div class="container prose" data-reveal>
<!-- Inhalt hier -->
</div>
</section>
</main>
<?php require __DIR__ . '/partials/layout-end.php'; ?>In includes/site-config.php den $navigation-Array ergänzen:
['key' => 'spielzeit', 'label' => 'Spielzeit', 'href' => '/spielzeit/'],Produktion (.htaccess):
RewriteRule ^spielzeit/?$ spielzeit.php [L,QSA]Lokal/CI (router.php und scripts/ci-router.php):
Die Route-Map erweitern:
'/spielzeit' => 'spielzeit.php',Den Regex und die Route-Map ergänzen.
Falls die Seite neue kritische Assets verwendet, diese in .github/workflows/deploy.yml ergänzen.
declare(strict_types=1)in jeder PHP-Datei- Alle dynamischen Ausgaben durch
e()escapen:<?= e($value) ?> - Zentrale Konfiguration in
includes/site-config.php - Keine Framework-Abhängigkeit, kein Composer
- Custom Properties (Design-Tokens) in
:root - Komponenten-Klassen mit BEM-ähnlicher Namenskonvention
- Responsive Breakpoints bei
48rem(768px) und80rem(1280px) prefers-reduced-motionwird berücksichtigt
- Vanilla JS, kein Framework
- Strict Mode (
"use strict") - IIFE-Pattern zur Kapselung
- Feature-Prüfung vor Verwendung (
IntersectionObserver in window)
- Alle Bilder, Fonts und Stylesheets werden selbstgehostet (keine CDN-Abhängigkeiten)
- Fonts liegen als WOFF2-Subset-Dateien vor
- Bilder: WebP-Format bevorzugt, PNG/JPEG als Fallback für Icons/Logos
.htaccesssetzt URL-Rewrites und.php-Kanonisierung um- Wenn die Hosting-Umgebung alle Requests auf
index.phproutet, greift der Fallback - Legal-HTML sollte vor Deployment aktuell sein (siehe content-workflow.md)
- FTP-Deploy über GitHub Actions bei Push auf
main(siehe architecture.md für Details zur CI/CD-Pipeline)