{"id":49634256,"url":"https://github.com/ynamite/viterex_addon","last_synced_at":"2026-05-22T16:00:58.135Z","repository":{"id":354179942,"uuid":"1052307134","full_name":"ynamite/viterex_addon","owner":"ynamite","description":"ViteRex ist ein eigenständiges REDAXO 5 Addon, das ein modernes Vite-Frontend (Tailwind 4, Live-Reload, Hot-Module-Replacement) in jede Redaxo-Installation bringt. So lernt der Dino rennen.","archived":false,"fork":false,"pushed_at":"2026-04-27T19:55:16.000Z","size":2167,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-27T20:10:43.091Z","etag":null,"topics":["fluidtw","lightningcss","live-reload","prettier","redaxo-addon","redaxo5","tailwindcss","tailwindcss-v4","vite","vite-plugin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ynamite.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-07T20:26:51.000Z","updated_at":"2026-04-27T19:55:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ynamite/viterex_addon","commit_stats":null,"previous_names":["ynamite/viterex-addon","ynamite/viterex_addon"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/ynamite/viterex_addon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ynamite%2Fviterex_addon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ynamite%2Fviterex_addon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ynamite%2Fviterex_addon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ynamite%2Fviterex_addon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ynamite","download_url":"https://codeload.github.com/ynamite/viterex_addon/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ynamite%2Fviterex_addon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32652474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fluidtw","lightningcss","live-reload","prettier","redaxo-addon","redaxo5","tailwindcss","tailwindcss-v4","vite","vite-plugin"],"created_at":"2026-05-05T14:01:35.062Z","updated_at":"2026-05-22T16:00:58.088Z","avatar_url":"https://github.com/ynamite.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=\"1672\" height=\"941\" style=\"max-width: 100%; height: auto;\" alt=\"ViteRex Addon\" src=\"https://github.com/user-attachments/assets/371153d5-31e9-4670-8dbe-30034e0d9dcb\" /\u003e\n\n# ViteRex für REDAXO 5\n\n**Modernes Vite-Frontend in jeder REDAXO-Installation — ohne Kompromisse.**\n\nViteRex bringt [Vite](https://vite.dev/) in REDAXO. Egal ob klassische Ordnerstruktur, moderne ydeploy-Struktur oder Theme-Addon: ViteRex passt sich an, ohne dass du an deiner Projektstruktur schrauben musst. Hot-Module-Replacement, Live-Reload bei Backend-Inhaltsänderungen, [Tailwind 4](https://tailwindcss.com/), [Lightning CSS](https://lightningcss.dev/), HTTPS-Dev-Server, ein PHP-Asset-Helper und ein Backend-Badge mit Stage-Anzeige — alles vorkonfiguriert, alles über das REDAXO-Backend einstellbar.\n\nKonzeptionell inspiriert vom [laravel-vite-plugin](https://github.com/laravel/vite-plugin): Du registrierst ViteRex einmal, schreibst `REX_VITE` in dein Template, und das Addon kümmert sich um Dev-Server-Erkennung, Manifest-Auflösung, Preload-Tags und HMR.\n\n[Viterex-short.webm](https://github.com/user-attachments/assets/bcf2b29a-e61c-4511-aef8-09b552d2c7c1)\n\n---\n\n## Schnellstart\n\n```bash\n# 1. Im Backend installieren: AddOns → Installer → \"viterex_addon\" → installieren \u0026 aktivieren\n# 2. Backend → AddOns → ViteRex → Einstellungen öffnen, Pfade prüfen, speichern\n# 3. Auf \"Stubs installieren\" klicken → package.json, vite.config.js etc. landen im Projekt-Root\n# 4. Im Terminal:\nnpm install\nnpm run dev\n```\n\nFertig. Der Vite-Dev-Server läuft, deine REDAXO-Seite zeigt HMR.\n\n---\n\n## Was kann ViteRex?\n\nViteRex deckt den kompletten Frontend-Workflow für REDAXO ab — von der ersten `npm install` bis zum Production-Build. Kurzüberblick:\n\n- **Vite-Dev-Server-Integration** mit HMR und Live-Reload, plus Production-Builds mit gehashten Assets und `manifest.json`.\n- **`REX_VITE`-Platzhalter** in beliebigen Templates, Modulen oder Slices — automatisch eingesetzt vor `\u003c/head\u003e`, falls du ihn vergisst.\n- **Drei Ordnerstrukturen unterstützt**: classic, modern (ydeploy), Theme-Addon. Eingestellt wird im Backend, keine Auto-Detection-Magie zur Laufzeit.\n- **PHP-Helpers** für statische Assets in Templates: `Assets::url()`, `Assets::path()`, `Assets::inline()`.\n- **Backend-Konfiguration** mit allen Pfaden, Live-Reload-Globs und HTTPS-Toggle.\n- **„Stubs installieren\"-Knopf** kopiert `package.json`, `vite.config.js` und Dev-Tooling-Configs in dein Projekt — mit Backup-Funktion und automatischem `.gitignore`-Merge.\n- **Tailwind 4 + Lightning CSS** vorinstalliert in den Stubs, plus `@tailwindcss/forms`, `@tailwindcss/typography`, `tailwind-clamp`.\n- **Live-Reload bei Content-Änderungen im Backend**: ~30 REDAXO-Extension-Points (Artikel, Kategorien, Slices, Module, Templates, Medien, Sprachen, optional yform-Daten) lösen einen Browser-Reload aus.\n- **block_peek-Integration**: Der `REX_VITE`-Platzhalter funktioniert auch in den Block-Vorschau-iframes von [`block_peek`](https://github.com/FriendsOfREDAXO/block_peek).\n- **HTTPS-Dev-Server** via [mkcert](https://github.com/FiloSottile/mkcert) — ein Befehl, fertig.\n- **ViteRex-Badge** im Frontend \u0026 Backend (nur für eingeloggte Admins, nur in Dev/Staging): zeigt Stage, Vite-Status, Git-Branch, Cache-Clear-Button, REDAXO- und ViteRex-Version.\n- **Automatische SVG-Optimierung**: SVGO im Dev (mutiert Source-SVGs 1:1 in-place), `mathiasreker/php-svg-optimizer` für Mediapool-Uploads in Staging/Prod. Strippt `\u003cscript\u003e` und `on*`-Handler — schliesst eine standardmässig vorhandene XSS-Lücke beim SVG-Upload.\n- **noindex-Meta-Tag** auf Dev/Staging — wenn `ydeploy` installiert ist.\n- **Debug-Modus** wird automatisch passend zur Stage gesetzt.\n- **Erweiterbar** durch Downstream-Addons über ein Plugin-Wrapping-Modell, drei PHP-Extension-Points (`VITEREX_BADGE`, `VITEREX_PRELOAD`, `VITEREX_INSTALL_STUBS`) und eine öffentliche `StubsInstaller`-API für eigenes Scaffolding.\n- **Idempotente Installation**: Bei erstmaliger Installation werden Defaults gesetzt; Re-Installs überschreiben deine Einstellungen nicht.\n\n---\n\n## Voraussetzungen\n\n- **REDAXO** `\u003e= 5.13`\n- **PHP** `\u003e= 8.3` (war `\u003e= 8.1` bis v3.2.x — siehe CHANGELOG)\n- **Node.js** `\u003e= 18`, **npm** `\u003e= 9`\n\nEmpfohlene REDAXO-Addons (optional, aber sinnvoll):\n\n- `yrewrite` für Domain-/URL-Handling\n- `ydeploy` für Stage-Erkennung (dev/staging/prod) und automatisches noindex\n- `block_peek` für HMR in Block-Vorschauen\n- `developer` für Templates/Module im Filesystem statt Datenbank\n\n---\n\n## Installation\n\n### Über den REDAXO-Installer (empfohlen)\n\nBackend → _AddOns → Installer_, `viterex_addon` suchen, herunterladen, aktivieren.\n\n### Manuell von GitHub\n\nRepository nach `/src/addons/viterex_addon/` (modern) bzw. `redaxo/src/addons/viterex_addon/` (classic / Theme-Addon) entpacken, im Backend installieren und aktivieren.\n\n### Was beim Installieren passiert\n\n**Nichts im Projekt-Root.** Das Addon registriert sich nur und seedet `var/data/addons/viterex_addon/structure.json` (modern) bzw. `redaxo/data/addons/viterex_addon/structure.json` (classic/theme) mit Default-Pfaden. Konfiguration und Bereitstellung der Projekt-Dateien läuft über das Backend (siehe nächster Abschnitt).\n\n---\n\n## Erste Schritte\n\n### 1. Einstellungen prüfen\n\nBackend → _AddOns → ViteRex → Einstellungen_ öffnen. Defaults sind für die **moderne Ordnerstruktur** ausgelegt:\n\n| Struktur             | Öffentliches Verzeichnis | Build-Output        |\n| -------------------- | ------------------------ | ------------------- |\n| **modern** (ydeploy) | `public`                 | `public/dist`       |\n| **classic**          | _(leer lassen)_          | `dist`              |\n| **Theme-Addon**      | `theme/public`           | `theme/public/dist` |\n\nSpeichern → die Einstellungen werden in `rex_config` gespeichert und gespiegelt nach `structure.json`, das vom Vite-Plugin auf der Node-Seite gelesen wird.\n\n### 2. Stubs installieren\n\nAuf den Knopf **„Stubs installieren\"** klicken. Das Häkchen _„Existierende Dateien überschreiben\"_ steuert das Verhalten bei vorhandenen Dateien:\n\n- **Ohne Häkchen**: existierende Dateien bleiben, werden in der Übersicht als „übersprungen\" gemeldet.\n- **Mit Häkchen**: existierende Dateien werden mit Zeitstempel gesichert (`\u003cdatei\u003e.bak.YYYYmmdd-HHiiss`), bevor sie überschrieben werden — **nichts wird stillschweigend zerstört**.\n\nBereitgestellt werden folgende Dateien im Projekt-Root:\n\n- `package.json` (Vite 8, Tailwind 4, Plugins, Dev-Tooling)\n- `vite.config.js` (minimal, Laravel-Style — der Import-Pfad zu `viterex-vite-plugin.js` wird aus deiner _Öffentliches Verzeichnis_-Einstellung generiert)\n- `.env.example`, `.browserslistrc`, `.prettierrc`, `biome.jsonc`, `stylelint.config.js`, `jsconfig.json`\n- `\u003cassets_source_dir\u003e/js/main.js` und `\u003cassets_source_dir\u003e/css/style.css` als Default-Einstiegspunkte\n\nAußerdem wird die `.gitignore` Zeile-für-Zeile gescannt — fehlende ViteRex-Einträge (`.vite-hot`, `.vite-reload-trigger`, mkcert-Zertifikate) werden unter einer `# Added by viterex`-Markierung ergänzt.\n\n### 3. Loslegen\n\n```bash\nnpm install\nnpm run dev\n```\n\n`.vite-hot` taucht im Projekt-Root auf, der Browser zeigt deine Seite mit HMR.\n\n---\n\n## Der `REX_VITE`-Platzhalter\n\nIn beliebigen REDAXO-Templates den `REX_VITE`-Platzhalter im `\u003chead\u003e` ergänzen:\n\n```php\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    REX_VITE\n\u003c/head\u003e\n\u003cbody\u003e\n    ...\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n**Wichtig:** Der `REX_VITE`-Platzhalter wird **nur innerhalb von `\u003chead\u003e` und nur beim ersten Vorkommen** ersetzt. Jedes weitere `REX_VITE` — im Body, in Code-Beispielen auf Doku-Seiten, in Slice-Inhalten — bleibt unverändert als Literal-Text stehen. Wird im `\u003chead\u003e` gar kein `REX_VITE` gefunden, fügt der Output-Filter den Asset-Block automatisch vor dem ersten `\u003c/head\u003e` ein. Du kannst den Platzhalter also auch ganz weglassen — bequem, aber explizit ist besser, wenn du Kontrolle über die Position willst.\n\n### Formen\n\n| Form                                                              | Verhalten                                                |\n| ----------------------------------------------------------------- | -------------------------------------------------------- |\n| `REX_VITE`                                                        | Default-Einstiegspunkte (CSS + JS) aus den Einstellungen |\n| `REX_VITE[src=\"src/assets/js/main.js\"]`                           | Ein einzelner expliziter Einstiegspunkt                  |\n| `REX_VITE[src=\"src/assets/css/style.css\\|src/assets/js/main.js\"]` | Mehrere Einstiegspunkte, pipe-separiert                  |\n\n### Reihenfolge der ausgegebenen Tags\n\nPro Vorkommen wird in dieser Reihenfolge geschrieben:\n\n1. `\u003clink rel=\"modulepreload\"\u003e` und `\u003clink rel=\"preload\"\u003e` für Imports / CSS / Fonts / Assets aus dem Manifest (vollständige Walk-Funktion mit Zyklen-Erkennung).\n2. `\u003clink rel=\"stylesheet\"\u003e` für jeden CSS-Eintrag — **auch im Dev** (separater Vite-Eintrag).\n3. `\u003cscript type=\"module\" src=\"\u003cdevUrl\u003e/@vite/client\"\u003e` (nur Dev, einmal pro Vorkommen mit JS-Einträgen).\n4. `\u003cscript type=\"module\" src=\"...\"\u003e` pro JS-Eintrag.\n\n---\n\n## PHP-Helpers für statische Assets\n\nFür Dateien, die du aus PHP-Templates referenzierst (Background-Images, Logos, inline SVG):\n\n```php\nuse Ynamite\\ViteRex\\Assets;\n\n// URL eines Bildes (Dev: Vite-Dev-Server-URL, Prod: gehashter Build-Pfad)\n\u003cimg src=\"\u003c?= Assets::url('img/logo-640w.webp') ?\u003e\"\u003e\n\n// Background-Image im Style-Attribut:\n\u003cdiv style=\"background-image:url(\u003c?= Assets::url('img/hero.jpg') ?\u003e)\"\u003e…\u003c/div\u003e\n\n// Absoluter Filesystem-Pfad (z.B. für getimagesize()):\n$svgPath = Assets::path('img/logo.svg');\n\n// Inline-SVG / JSON / Text:\n\u003c?= Assets::inline('img/icon-arrow.svg') ?\u003e\n```\n\nAssets, die per JS oder CSS importiert werden (`import \"../img/foo.png?url\"` oder `background: url(\"../img/foo.png\")`), werden von Vite automatisch verarbeitet (gehasht) und ins Manifest eingetragen — keine zusätzliche Konfiguration nötig.\n\n---\n\n## Einstellungs-Felder\n\n| Feld                             | Default                    | Zweck                                                                                                                |\n| -------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |\n| **JS-Einstiegspunkt**            | `src/assets/js/main.js`    | Vite JS-Entry-Pfad                                                                                                   |\n| **CSS-Einstiegspunkt**           | `src/assets/css/style.css` | Vite CSS-Entry-Pfad                                                                                                  |\n| **Öffentliches Verzeichnis**     | `public`                   | Vom Webserver ausgeliefertes Verzeichnis. Modern: `public`. Classic: leer. Theme: `theme/public`.                    |\n| **Build-Output-Verzeichnis**     | `public/dist`              | Vite `outDir`                                                                                                        |\n| **Build-URL-Prefix**             | `/dist`                    | URL-Prefix für gebaute Assets                                                                                        |\n| **Assets-Source-Verzeichnis**    | `src/assets`               | Wo deine Source-Assets liegen                                                                                        |\n| **Assets-Unter-Verzeichnis**     | `assets`                   | Vite `build.assetsDir`                                                                                               |\n| **Statische Copy-Verzeichnisse** | `img`                      | Komma-separierte Liste — kopiert beim Build von `\u003cassets_source_dir\u003e/\u003cdir\u003e/` nach `\u003cout_dir\u003e/\u003cassets_sub_dir\u003e/\u003cdir\u003e` |\n| **HTTPS-Dev-Server aktivieren**  | aus                        | Aktiviert HTTPS, wenn mkcert-Zertifikate im Projekt-Root liegen                                                      |\n| **Live-Reload-Globs**            | siehe unten                | Ein Glob pro Zeile — Vite triggert ein Full-Reload bei Änderung passender Dateien                                    |\n\n---\n\n## Live-Reload\n\nDer Browser-Reload wird über [`vite-plugin-live-reload`](https://github.com/arnoson/vite-plugin-live-reload) ausgelöst. Default-Globs:\n\n```\nsrc/modules/**/*.php\nsrc/templates/**/*.php\nsrc/addons/project/fragments/**/*.php\nsrc/addons/project/lib/**/*.php\nsrc/assets/**/(*.svg|*.png|*.jpg|*.jpeg|*.webp|*.avif|*.gif|*.woff|*.woff2)\n.vite-reload-trigger\n```\n\nDie ersten fünf Globs decken **direkte Datei-Änderungen** ab — du speicherst eine PHP-Datei in deiner IDE → Reload.\n\n`.vite-reload-trigger` ist ein **Signal-File** für **Backend-getriebene Content-Änderungen**. `boot.php` registriert Handler auf ~30 REDAXO-Extension-Points:\n\n- **Artikel**: `ART_ADDED`, `ART_UPDATED`, `ART_DELETED`, `ART_MOVED`, `ART_COPIED`, `ART_STATUS`\n- **Kategorien**: `CAT_ADDED`, `CAT_UPDATED`, `CAT_DELETED`, `CAT_MOVED`, `CAT_STATUS`\n- **Slices**: `SLICE_ADDED`, `SLICE_UPDATED`, `SLICE_DELETED`, `SLICE_MOVE`\n- **Medien**: `MEDIA_ADDED`, `MEDIA_UPDATED`, `MEDIA_DELETED`\n- **Sprachen**: `CLANG_ADDED`, `CLANG_UPDATED`, `CLANG_DELETED`\n- **Templates**: `TEMPLATE_ADDED`, `TEMPLATE_UPDATED`, `TEMPLATE_DELETED`\n- **Module**: `MODULE_ADDED`, `MODULE_UPDATED`, `MODULE_DELETED`\n- **yform-Daten** (falls `yform` installiert): `YFORM_DATA_ADDED`, `YFORM_DATA_UPDATED`, `YFORM_DATA_DELETED`\n\nWird einer dieser EPs ausgelöst, `touch()`t der Handler die Datei `.vite-reload-trigger`. Vite erkennt die Änderung → Browser-Reload.\n\n\u003e **Warum nicht direkt `var/cache/addons/...` watchen?** Diese Verzeichnisse werden auch bei normaler Frontend-Navigation durch Lazy-Cache-Regeneration neu geschrieben — das würde laufend falsche Reloads triggern. Das Signal-File wird nur bei _echten_ Backend-Saves angefasst.\n\n---\n\n## HTTPS-Dev-Server\n\n```bash\nnpm run setup-https\n```\n\nDieser Befehl ruft mkcert auf und erzeugt lokale Zertifikate (`localhost+2-key.pem`, `localhost+2.pem`) im Projekt-Root. Anschließend in den Einstellungen _„HTTPS-Dev-Server aktivieren\"_ anhaken — beim nächsten `npm run dev` läuft Vite über HTTPS, das `.vite-hot`-File enthält `https://...`.\n\nmkcert installiert beim ersten Start eine lokale Root-CA in deinen System-Trust-Store (eine einmalige Sicherheitsabfrage). Auf macOS via Homebrew bzw. in Chrome / Firefox automatisch erkannt.\n\n---\n\n## Vite-Konfiguration erweitern (für Addon-Entwickler)\n\n`viterex-vite-plugin.js` ist im Stil des laravel-vite-plugins gebaut: ein Aufruf, alle Defaults werden injiziert, Override via Vites `mergeConfig`.\n\n### Pro Projekt — direkt in deiner `vite.config.js`\n\n```js\nimport { defineConfig } from 'vite'\nimport tailwindcss from '@tailwindcss/vite'\nimport viterex, {\n  fixTailwindFullReload\n} from './public/assets/addons/viterex_addon/viterex-vite-plugin.js'\n\nexport default defineConfig({\n  plugins: [\n    tailwindcss(),\n    fixTailwindFullReload(),\n    viterex({\n      input: ['src/admin/main.js'], // zusätzliche Einstiegspunkte\n      refresh: ['src/templates/**/*.php'] // engere Live-Reload-Globs\n    })\n  ],\n  build: { sourcemap: true } // alles hier überschreibt viterex-Defaults\n})\n```\n\n### Plugin-Optionen\n\n| Option         | Default                                    | Wirkung                                                                                                      |\n| -------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |\n| `input`        | `[css_entry, js_entry]` aus structure.json | Liste der Vite-Einstiegspunkte                                                                               |\n| `refresh`      | `true`                                     | `true` = Globs aus structure.json, `false` = Live-Reload aus, `Array` = explizite Globs                      |\n| `detectTls`    | `true`                                     | mkcert-Zertifikate auto-erkennen, wenn `https_enabled` aktiv                                                 |\n| `injectConfig` | `true`                                     | Build-/Server-/CSS-/Resolve-Config injizieren. **Escape-Hatch:** `false` lässt nur das Hot-File-Plugin aktiv |\n\n### Downstream-Addons (z.B. `redaxo-massif`)\n\nEigenes Helper-File unter `\u003caddon\u003e/assets/\u003cname\u003e-vite-plugin.js`, das `viterex()` umwickelt:\n\n```js\n// redaxo-massif/assets/massif-vite-plugin.js\nimport vue from '@vitejs/plugin-vue'\nimport viterex from '../viterex/viterex-vite-plugin.js'\n\nexport default function massif(userOptions = {}) {\n  return [\n    ...viterex({ refresh: false, ...userOptions }), // viterex zuerst\n    vue()\n  ]\n}\n```\n\nNutzer wechseln dann in ihrer `vite.config.js` einfach den Import + Plugin-Aufruf von `viterex` auf `massif`.\n\n---\n\n## Programmatische API für Downstream-Addons\n\nAndere REDAXO-Addons können auf zwei Wegen ihre eigenen Dateien zusätzlich zu ViteRex' Stubs ins Projekt-Root scaffolden — beide nutzen ViteRex' bewährte Path-Baking + Backup-on-Overwrite + struktur-bewusste Zielauflösung.\n\n### Direktaufruf — aus eigener `install.php` oder einem Settings-Handler\n\n```php\nuse Ynamite\\ViteRex\\StubsInstaller;\n\n$result = StubsInstaller::installFromDir(\n    __DIR__ . '/frontend',                  // Source-Verzeichnis des Downstream-Addons\n    [                                        // Map: Source-relativ → Ziel-relativ-zum-Root\n        'templates/Header/template.php' =\u003e '/src/templates/Header/template.php',\n        'modules/Swiper/input.php'      =\u003e '/src/modules/Swiper/input.php',\n        'assets/img/logo.svg'           =\u003e '/src/assets/img/logo.svg',\n    ],\n    overwrite: false,                        // true → Backup-on-overwrite (.bak.\u003cts\u003e)\n    packageDeps: [                           // Optional: npm-Dependency-Merge\n        'devDependencies' =\u003e ['swiper' =\u003e '^12.1.2', 'gsap' =\u003e '^3.14.2'],\n    ],\n);\n// Liefert: ['written' =\u003e [...], 'skipped' =\u003e [...], 'backedUp' =\u003e [...], 'packageDepsMerged' =\u003e 2]\n\n// Optional: Vite-Live-Reload-Globs erweitern (idempotent)\nStubsInstaller::appendRefreshGlobs([\n    'src/addons/myaddon/fragments/**/*.php',\n    'src/addons/myaddon/lib/**/*.php',\n]);\n```\n\n### Extension-Point-Hook — registriert sich auf ViteRex' „Stubs installieren\"-Flow\n\n```php\nrex_extension::register('VITEREX_INSTALL_STUBS', static function (rex_extension_point $ep) {\n    $overwrite = $ep-\u003egetParam('overwrite', false);\n    $myResult = Ynamite\\ViteRex\\StubsInstaller::installFromDir(\n        __DIR__ . '/frontend', $myStubsMap, $overwrite,\n    );\n    // Eigenes Resultat in subject mergen, damit ViteRex' Settings-Page beide auflistet\n    $subject = $ep-\u003egetSubject();\n    foreach (['written', 'skipped', 'backedUp'] as $k) {\n        $subject[$k] = array_merge($subject[$k] ?? [], $myResult[$k] ?? []);\n    }\n    return $subject;\n});\n```\n\nBeide Wege sind komplementär: der Direktaufruf passt für Auto-Install in `install.php`; der Hook fängt explizite Re-Installs aus ViteRex' eigener UI ab. Ein Addon kann beide nutzen — Direktaufruf für die initiale Auto-Install, Hook für nachträgliche Re-Scaffolds.\n\n**Hinweis zur Idempotenz**: Das Downstream-Addon trackt selbst, ob es schon scaffolded hat (z.B. via `rex_config('myaddon', 'scaffolded_at')`). `installFromDir()` selbst ist nicht idempotent — sie kopiert immer.\n\n---\n\n## Erweiterungs-Punkte (PHP)\n\n| Name                    | Subject                                                 | Verwendung                                                                           |\n| ----------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| `VITEREX_BADGE`         | `array` von HTML-Strings                                | Zusätzliche Panels im ViteRex-Badge rendern (z.B. Tailwind-Breakpoint-Indikator).    |\n| `VITEREX_PRELOAD`       | `array` von `\u003clink\u003e`-Strings                            | Custom Preload-Links einfügen (z.B. Webfonts im Dev). Parameter: `entries`, `dev`.   |\n| `VITEREX_INSTALL_STUBS` | `array` `{written, skipped, backedUp, gitignoreAction}` | Eigene Dateien parallel zu ViteRex' Stubs scaffolden. Parameter: `overwrite` (bool). |\n\nBeispiel — eigenes Badge-Panel:\n\n```php\nrex_extension::register('VITEREX_BADGE', function (rex_extension_point $ep) {\n    $panels = $ep-\u003egetSubject();\n    $panels[] = '\u003cdiv\u003eCustom Panel\u003c/div\u003e';\n    return $panels;\n});\n```\n\n---\n\n## ViteRex-Badge\n\nBei aktiver Backend-Session und Nicht-Prod-/Nicht-Staging-Umgebung wird ein Badge unten am Fenster eingeblendet (Frontend + Backend). Es zeigt:\n\n- **Stage**: `dev` / `staging` / `prod` mit Farb-Codierung\n- **Git-Branch**: aus `.git/HEAD` gelesen, mit Alert-Styling für Branches != `main` / `master`\n- **Vite-Status**: farbiger Punkt — an = Stage-Farbe + Glow, aus = grau — mit Tooltip auf Hover (`Vite @ \u003curl\u003e`)\n- **REDAXO-** und **ViteRex-Version**\n- **Cache-Clear-Button** (CSRF-geschützter POST gegen `viterex_clear_cache`)\n\nAndere Addons können via `VITEREX_BADGE`-Extension-Point eigene Panels hinzufügen.\n\n---\n\n## Dev-Server-Landing-Page\n\nBeim direkten Aufruf der Vite-Dev-URL (z.B. `https://127.0.0.1:5173`) zeigt der eingebaute `viterex:dev-index`-Plugin (in `viterex-vite-plugin.js`) eine kleine HTML-Seite mit dem Hinweis _„Vite läuft\"_ und einem Link zur eigentlichen Projekt-URL (aus `host_url` in `structure.json`). Verhindert die irritierende leere Seite, die Vite hier sonst serviert.\n\n---\n\n## block_peek-Integration\n\nWenn das [`block_peek`](https://github.com/FriendsOfREDAXO/block_peek)-Addon installiert ist, registriert ViteRex einen Handler auf dessen `BLOCK_PEEK_OUTPUT`-Extension-Point, der `REX_VITE`-Platzhalter im Block-Vorschau-Template auflöst. Damit funktioniert HMR + bundled Assets auch in den iframe-Vorschauen im Backend (wo der normale `OUTPUT_FILTER` aus Sicherheitsgründen schweigt — sonst würde er literale `REX_VITE`-Strings in Slice-Editoren ersetzen).\n\nDie Integration ist konditional — sie aktiviert sich nur, wenn `block_peek` als Addon verfügbar ist. Kein hartes Coupling im Code.\n\n---\n\n## SVG-Optimierung\n\nViteRex optimiert SVGs automatisch — sowohl Source-Dateien im Build als auch Mediapool-Uploads. Single Toggle in **ViteRex → Einstellungen → SVG-Optimierung**, default ON. Welche Engine läuft und wann sie läuft, hängt von der Oberfläche ab:\n\n| Surface          | Wann                                               | Engine                                           |\n| ---------------- | -------------------------------------------------- | ------------------------------------------------ |\n| Source-Assets    | `npm run dev` (server start) + `npm run build`     | SVGO (Node, via Vite-Plugin), 1:1 in-place       |\n| Vite copy-pipe   | `npm run build` (`viteStaticCopy` transform)       | SVGO                                             |\n| Mediapool        | `npm run build`                                    | SVGO (Vite-Plugin walked `\u003cmedia_dir\u003e`)          |\n| Mediapool        | Manuell: `bin/console viterex:optimize-svgs`       | SVGO wenn verfügbar, sonst `PhpOptimizer` (PHP)  |\n| Mediapool-Upload | `MEDIA_ADDED` / `MEDIA_UPDATED` (nur prod/staging) | `PhpOptimizer` (Node-frei für die Live-Umgebung) |\n\nIn **dev** ist der Mediapool-Upload-Hook ein No-op — kein SVGO-Shell-out bei jedem Test-Upload. Räume mit `npm run build` oder dem Console-Command auf, wenn du willst.\n\n**Sicherheits-Effekt fürs Mediapool**: `\u003cscript\u003e`-Tags und `on*`-Event-Handler werden bei jedem Prod/Staging-Upload entfernt — schliesst eine standardmässig vorhandene XSS-Lücke beim Hochladen von SVGs in Redaxo.\n\n**Cache**: Beide Pfade (Vite-Build + Console-Command) teilen sich `\u003ccache_dir\u003e/svg-optimized.json`. SHA1 der optimierten Bytes pro Datei; bereits optimale Files werden in Folge-Runs übersprungen. `bin/console viterex:optimize-svgs --force` ignoriert den Cache.\n\n**Idempotent / Fail-open**: SVGO-Output round-trippt unverändert; Cache verhindert dass das überhaupt bemerkt wird. Bei jedem Fehler bleibt die Datei unverändert.\n\n**npm-Dep**: `svgo` wird per `install.php` in die `package.json` des Projekts gemerged. Beim Upgrade von v3.2.x erscheint es automatisch in `devDependencies`; ein einmaliges `npm install` aktiviert die Optimierung. In der Lücke davor warnt das Vite-Plugin und macht nichts (kein Crash).\n\n### Console-Command\n\n```bash\nbin/console viterex:optimize-svgs              # walk + optimize\nbin/console viterex:optimize-svgs --dry-run    # list what would change\nbin/console viterex:optimize-svgs --force      # ignore cache, re-do everything\n```\n\nEngine-Wahl: SVGO wenn `npx svgo` auf PATH, sonst `PhpOptimizer`. Honors `svg_optimize_enabled` (bricht früh ab wenn off).\n\n### Inline-SVGs: Scope-Isolation gegen Class-Kollisionen\n\nWer mehrere SVGs auf derselben Seite via `Assets::inline('img/foo.svg')` einbindet (typisch: Icons, Illustrationen aus Figma/Illustrator), ist standardmässig kollisionsanfällig: SVG-`\u003cstyle\u003e`-Blöcke haben **document-level scope**, sobald die SVG inline im HTML steht. Zwei SVGs mit `.cls-1`-Selectoren (Standard-Export-Naming) bluten gegenseitig in alle Pfade auf der Seite, die zufällig dieselbe Klasse tragen — auch in unbeteiligte SVGs oder HTML-Elemente. Dasselbe gilt für `\u003cfilter id=\"x\"\u003e`, `\u003clinearGradient id=\"x\"\u003e`, `\u003csymbol id=\"x\"\u003e` und alle internen Referenzen darauf (`url(#x)`, `\u003cuse href=\"#x\"\u003e`).\n\n`Assets::inline()` löst das automatisch: jede inline-eingebundene SVG kriegt zur Laufzeit einen stabilen, datei-abgeleiteten Prefix (`\u003cpath-slug\u003e-…`) auf alle `id`/`class`-Attribute und alle internen Referenzen. Beispiel:\n\n```svg\n\u003c!-- src/assets/img/icon-foo.svg --\u003e\n\u003csvg\u003e\n  \u003cstyle\u003e.cls-1 { fill: red }\u003c/style\u003e\n  \u003cpath class=\"cls-1\" id=\"head\"/\u003e\n  \u003cuse href=\"#head\"/\u003e\n\u003c/svg\u003e\n```\n\n…wird beim Inline-Einbinden zu:\n\n```svg\n\u003csvg\u003e\n  \u003cstyle\u003e.img-icon-foo-cls-1 { fill: red }\u003c/style\u003e\n  \u003cpath class=\"img-icon-foo-cls-1\" id=\"img-icon-foo-head\"/\u003e\n  \u003cuse href=\"#img-icon-foo-head\"/\u003e\n\u003c/svg\u003e\n```\n\n**Was umgeschrieben wird:** `id=\"X\"`, `url(#X)`, `href=\"#X\"` / `xlink:href=\"#X\"` (nur Fragment-Refs, externe URLs bleiben unangetastet), sowie `.X`-Selectoren in `\u003cstyle\u003e`-Blöcken. Bei `class=\"X Y Z\"` werden **nur** Tokens umgeschrieben, die auch als `.X`-Selector im SVG-eigenen `\u003cstyle\u003e` definiert sind — externe Klassen (Tailwind-Utilities, Projekt-CSS, BEM) bleiben unangetastet, damit Host-Page-CSS weiterhin matcht. `#X`-Selectoren in `\u003cstyle\u003e` werden nur umgeschrieben, wenn `X` auch als echtes `id=\"X\"` im Dokument vorkommt — Hex-Farben wie `#fff` / `#abc` bleiben so unberührt.\n\n**Cache:** Das Ergebnis wird unter `rex_path::addonCache('viterex_addon', 'inline-svg/\u003csha1\u003e.svg')` gecached, gekeyed auf `path + content`. Die Prefixing-Kosten fallen nur einmal pro (Datei, Inhalt)-Paar an. Source-Files auf der Disk bleiben **unberührt** — der Prefix entsteht nur zur Inline-Zeit, sodass dieselbe Datei weiterhin als `\u003cimg src=\"…\"\u003e` oder `background-image: url()` funktioniert.\n\n**Opt-out per Datei:** Wer eine SVG bewusst mit shared `id`/`class`-Namen über mehrere Inlines hinweg verwendet (z. B. ein Sprite-Pattern mit cross-document Refs), kann das Prefixing für diese Datei abschalten:\n\n```svg\n\u003csvg\u003e\n  \u003c!-- viterex:no-prefix --\u003e\n  …\n\u003c/svg\u003e\n```\n\nDer Magic-Comment darf irgendwo im Dokument stehen. Findet ihn der Prefixer, wird die SVG unverändert ausgeliefert (kein Cache-Eintrag).\n\n**Globale Toggle-Bindung:** Wenn `svg_optimize_enabled` auf OFF steht, läuft auch das Inline-Prefixing nicht — `Assets::inline()` verhält sich dann wie vor v3.3.\n\n---\n\n## Stage-Erkennung \u0026 Debug-Modus\n\nViteRex erkennt drei Deployment-Stages:\n\n| Stage     | Erkennung                                       |\n| --------- | ----------------------------------------------- |\n| `prod`    | `ydeploy::getStage()` beginnt mit `\"prod\"`      |\n| `staging` | `ydeploy::getStage()` beginnt mit `\"stage\"`     |\n| `dev`     | alles andere (oder `ydeploy` nicht installiert) |\n\nWenn `ydeploy` installiert ist und nicht-prod erkannt wird, setzt ViteRex automatisch ein `\u003cmeta name=\"robots\" content=\"noindex, nofollow\"\u003e` über den `YREWRITE_SEO_TAGS`-Extension-Point.\n\nREDAXOs Debug-Modus wird auf Dev/Staging eingeschaltet, auf Prod ausgeschaltet — die Änderung wird nach `core/data/config.yml` persistiert (idempotent: ohne Disk-Write, wenn der Wert bereits stimmt), damit der `developer`-Addon und andere Konsumenten den richtigen Wert sehen.\n\n---\n\n## ydeploy-Helper\n\nWenn das [ydeploy](https://github.com/yakamara/ydeploy)-Addon installiert ist, blendet viterex_addon eine **Deploy**-Subpage im Backend ein (ViteRex → Deploy). Damit lassen sich Deployment-Hosts per Formular bearbeiten, statt `deploy.php` von Hand zu editieren.\n\nSo funktioniert's:\n\n- Eine Sidecar-Datei `deploy.config.php` im Projekt-Root hält die editierbaren Werte (Repository-URL, Liste der Hosts mit Name/Hostname/Port/User/Stage/Pfad).\n- `deploy.php` lädt die Sidecar innerhalb eines klar markierten Blocks per `require`:\n\n  ```php\n  // \u003e\u003e\u003e VITEREX:DEPLOY_CONFIG (do not edit by hand) \u003e\u003e\u003e\n  $cfg = require __DIR__ . '/deploy.config.php';\n  set('repository', $cfg['repository']);\n  foreach ($cfg['hosts'] as $h) {\n      host($h['name'])-\u003esetHostname($h['hostname'])\n          -\u003esetRemoteUser($h['user'])-\u003esetPort($h['port'])\n          -\u003eset('labels', ['stage' =\u003e $h['stage']])-\u003esetDeployPath($h['path']);\n  }\n  // \u003c\u003c\u003c VITEREX:DEPLOY_CONFIG \u003c\u003c\u003c\n  ```\n\n- **Erster Aufruf:** Die Seite versucht, Werte aus dem aktuellen `deploy.php` zu extrahieren und schreibt sie in die Sidecar (`deploy.php` bleibt dabei unverändert). Falls das Projekt ein `git remote get-url origin` hat, wird diese URL als Default-Repository verwendet. Formular prüfen und auf **Aktivieren** klicken, um `deploy.php` so umzuschreiben, dass es die Sidecar nutzt (vorher wird ein `.bak.\u003ctimestamp\u003e`-Backup erstellt).\n\n- **Spätere Saves:** Nur die Sidecar wird neu geschrieben; `deploy.php` bleibt unangetastet. Der Deployer liest die neuen Werte beim nächsten Lauf.\n\n- **Alles ausserhalb des Markierungsblocks** gehört dir — eigene Tasks, `add('shared_dirs', ...)`, `add('clear_paths', ...)`, Environment-Branches usw. Der Helper fasst das nicht an.\n\n- **Redundante `set('repository', ...)`-Aufrufe** anderswo in `deploy.php` (z. B. innerhalb eines `if ($isGit)`-Zweigs aus dem Installer-Scaffold) würden den Markierungsblock stillschweigend überschreiben — Deployer arbeitet beim `set` nach Last-Write-Wins. Beim Aktivieren erkennt der Helper solche Aufrufe und ersetzt sie durch `/* viterex: removed redundant ... — overridden by sidecar */`-Kommentare, damit der Wert aus dem Markierungsblock gewinnt. Der Originalcode bleibt im Kommentartext erhalten.\n\n- **Stage-Label:** Das Eingabefeld bietet als Vorschläge nur die Werte an, für die ydeploy ein Badge stylet (`staging`, `production`, `prod`, `live`, `test`, `testing`). Eigene Werte sind weiterhin erlaubt, das Badge bleibt dann ungestylt. Empfohlene Wahl für reibungsloses Verhalten in beiden Welten: `staging` und `production` — sie passen zu ydeploys CSS und zu den Prefix-Matchern in viterex_addon (`Server::isProductionDeployment` testet `prod*`, `Server::isStagingDeployment` testet `stage*`).\n\n- **Markierungsblock manuell bearbeiten ist riskant.** Wenn die Marker unvollständig oder verschwunden sind, weigert sich das nächste Aktivieren, neu zu schreiben, und bittet dich, ein Backup wiederherzustellen.\n\nDie Sidecar ist einfaches PHP, das ein Array zurückgibt — kein Parser, keine zusätzliche Abhängigkeit nötig. Du kannst sie committen oder über `.gitignore` ausschliessen — deine Wahl.\n\n---\n\n## Mitwirken\n\nDas Backend-Badge wird mit Vite gebaut. Wenn du Dateien unter `assets-src/` änderst, regeneriere die kompilierten Versionen unter `assets/badge/`:\n\n```bash\ncd viterex-addon\nnpm install   # einmalig\nnpm run build\n```\n\nDie `assets/`-Verzeichnis-Struktur wird mit-committet (Badge-Build + `viterex-vite-plugin.js`) und ist Teil des Releases. REDAXO kopiert beim Installieren den `assets/`-Tree automatisch nach `\u003cfrontend\u003e/assets/addons/viterex_addon/` — daher landet `viterex-vite-plugin.js` an der Stelle, von der die `vite.config.js` der Nutzer importiert.\n\n---\n\n## Bekannte Einschränkungen\n\n- **CSP / Nonces:** Im Dev-Modus emittiert der Output-Filter `\u003cscript type=\"module\"\u003e` ohne Nonce. Eine strikte CSP mit `script-src 'self'` blockiert HMR. Workaround: CSP im Dev lockern oder einen zusätzlichen Output-Filter mit `LATE`-Priorität registrieren, der die Tags um Nonce-Attribute erweitert.\n\n---\n\n## Vite+ und andere Toolchains\n\nEine separate Notiz zu [Vite+](https://viteplus.dev/) und der Frage „Sollten wir migrieren?\" findest du unter [`docs/vite-plus-evaluation.md`](docs/vite-plus-evaluation.md). Kurzfassung: ViteRex hält den Plugin-Code CLI-agnostisch — du kannst Vite+ heute schon selbst on-top installieren, indem du in deiner `package.json` die Scripts auf `vp` umstellst. Ein offizielles Migration-Statement gibt es noch nicht.\n\n---\n\n## Issues / Kontakt\n\nBug-Reports \u0026 Feature-Requests auf [GitHub](https://github.com/ynamite/viterex_addon/issues). Änderungen im [CHANGELOG.md](CHANGELOG.md).\n\n## Lizenz\n\n[MIT](LICENSE.md)\n\n## Credits\n\n- **Project Lead**: [Yves Torres](https://github.com/ynamite)\n- **Inspiriert von**: [laravel-vite-plugin](https://github.com/laravel/vite-plugin)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fynamite%2Fviterex_addon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fynamite%2Fviterex_addon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fynamite%2Fviterex_addon/lists"}