frontend/ci: Build-Hinweis in die App-Quelle, env-gesteuert; Prod-Build ohne

Der Latest-Build-Hinweis wandert vom Workflow-sed in die App (app.js,
mountBuildBadge), damit ihn auch der Dev-Server zeigt — ein Post-Build-sed
erreicht den Dev-Server nicht. Logik umgekehrt: Hinweis ist der Normalfall,
nur die produktive Installation schaltet ihn ab.

Drei Zustaende ueber Vite-Env VITE_BUILD_BADGE (Auswertung in app.js):
- Dev-Server (import.meta.env.DEV) -> 🔧 "Vorschau/lokaler Entwicklungsstand"
- Default `npm run build` (Env ungesetzt) -> 🚧 "latest build"; der Pages-
  Deploy nutzt den Default und traegt den Hinweis dadurch automatisch (die
  sed-Injektion entfaellt).
- `npm run build:prod` (Vite-Modus prod, .env.prod: VITE_BUILD_BADGE=none)
  -> KEIN Badge; esbuild eliminiert den Zweig als toten Code.

Verifiziert zur Laufzeit (Dev + `vite preview` auf beiden Builds): 🔧 im Dev,
🚧 im Default-Build, gar nichts im Prod-Build (Titel sauber "Werkbaum").
34 Vitest-Tests gruen, Workflow-YAML/Shell gueltig.

Doku: D16 fortgeschrieben (quellbasiert/env statt sed, Begruendung); README
(de/en) mit Prod-Build-Anleitung inkl. LICENSE-/Versions-Caveats; frontend/
CLAUDE.md; .claude/launch.json bekommt einen frontend-dist-Preview (vite
preview, Port 8138) zum Verifizieren gebauter Dateien.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-07-22 05:56:59 +02:00
co-authored by Claude Opus 4.8
parent b7bf9182ea
commit 0f27bab905
10 changed files with 135 additions and 23 deletions
+6
View File
@@ -0,0 +1,6 @@
# Produktions-Build (`npm run build:prod`, Vite-Modus „prod").
# Schaltet den Build-Hinweis hinter dem Titel ab — nur die echte produktive
# Installation läuft ohne das 🔧/🚧-Symbol. Alle anderen Builds (Dev-Server und
# der Default-`npm run build`, u. a. der GitHub-Pages-Deploy) zeigen ihn.
# Siehe app.js (mountBuildBadge) und docs/DECISIONS.md D16.
VITE_BUILD_BADGE=none
+7 -2
View File
@@ -15,8 +15,13 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
in **eine** self-contained `dist/index.html` — die bleibt `file://`-tauglich
(D16) und ist die Deploy-Artefakt-Quelle (Pages-Workflow, siehe README).
- `npm --prefix frontend test` — Vitest (`tests/**/*.test.js`).
- `node_modules/` und `dist/` sind ge-`.gitignore`-t; `package-lock.json` ist
eingecheckt (der Workflow nutzt `npm ci`).
- `npm --prefix frontend run build:prod` — Produktions-Build **ohne** den
Build-Hinweis hinter dem Titel (Vite-Modus `prod`, `.env.prod` setzt
`VITE_BUILD_BADGE=none`). Nur die echte produktive Installation nutzt diesen
Weg; Dev-Server (🔧) und Default-`build` (🚧, u. a. Pages-Deploy) zeigen den
Hinweis. Logik: `mountBuildBadge()` in `app.js` (D16).
- `node_modules/` und `dist/` sind ge-`.gitignore`-t; `.env.prod` und
`package-lock.json` sind eingecheckt (der Workflow nutzt `npm ci`).
## Konventionen
- Vanilla HTML/CSS/JS, ES-Module; keine Frameworks. Testwerkzeug: Vitest.
+1
View File
@@ -7,6 +7,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"build:prod": "vite build --mode prod",
"preview": "vite preview",
"test": "vitest run",
"test:watch": "vitest"
+33
View File
@@ -1103,3 +1103,36 @@ let startLang = 'de';
try{ startLang = localStorage.getItem('werkbaum-lang') || 'de'; }catch(_){}
applyLang(I18N[startLang] ? startLang : 'de'); /* setzt Texte + rendert */
applyMobile(); /* Mobil-Verhalten (nach Sprache/Restore) anwenden */
/* ---------- Build-Hinweis (Vorschau/Dev + „latest build") ----------
Kennzeichnet einen nicht-produktiven Build mit einem kleinen Symbol samt
Tooltip hinter dem Titel. Gesteuert per Vite-Env `VITE_BUILD_BADGE`; ohne
Vorgabe entscheidet der Modus:
Dev-Server (`npm run dev`) -> import.meta.env.DEV -> 'dev' (🔧 Vorschau)
Default-Build (`npm run build`) -> Voreinstellung -> 'latest' (🚧)
`npm run build:prod` -> .env.prod: none -> KEIN Badge
So trägt einzig die echte Produktions-Installation keinen Hinweis. Bewusst
kein I18N-Text (Deploy-Metainfo, nicht Produkt-Feature; D14/D16) — der
Tooltip ist knapp zweisprachig (DE · EN). */
function mountBuildBadge(){
const kind = import.meta.env.VITE_BUILD_BADGE
|| (import.meta.env.DEV ? 'dev' : 'latest');
if(kind === 'none') return;
const BADGES = {
dev: {icon:'🔧', label:'Preview build (local dev)',
title:'Vorschau lokaler Entwicklungsstand · Preview (local dev build)'},
latest: {icon:'🚧', label:'Latest build may be buggy',
title:'Aktueller Entwicklungsstand (latest build) kann noch Fehler enthalten · Latest development build may still be buggy'},
};
const b = BADGES[kind];
const h1 = document.querySelector('header h1');
if(!b || !h1) return;
const el = document.createElement('span');
el.className = 'build-badge';
el.setAttribute('role', 'img');
el.setAttribute('aria-label', b.label);
el.title = b.title;
el.textContent = b.icon;
h1.appendChild(el);
}
mountBuildBadge();
+2
View File
@@ -50,6 +50,8 @@
body.fullscreen .app,
body.fullscreen .site-footer{max-width:none}
h1{font-size:1.25rem;font-weight:600;letter-spacing:-.01em}
/* Build-Hinweis hinter dem Titel (nur nicht-produktive Builds, siehe app.js) */
.build-badge{margin-left:.45em;font-size:.58em;line-height:1;vertical-align:middle;cursor:help;user-select:none;text-decoration:none}
header p{margin-top:4px;color:var(--muted);font-size:.9rem}
.sub-short{display:none} /* Kurzfassung nur auf kleinem Bildschirm */
.langsel{