AddOn


viterex_addon

Beschreibung

ViteRex ist ein eigenständiges Redaxo-Addon, das ein modernes Vite-Frontend (Tailwind 4, Live-Reload, Hot-Module-Replacement) in **jede** Redaxo-Installation einbringt — ob klassische, moderne oder Theme-Addon Ordnerstruktur. Pfade konfigurierst du im Backend; auf Knopfdruck scaffolded das Addon `package.json`, `vite.config.js`, Dev-Tooling-Defaults, Beispiel-Entries und merged `.gitignore`-Einträge in dein Projekt-Root.

https://github.com/ynamite/viterex_addon/blob/main/README.md


github.com/ynamite/viterex_addon

Umsetzung

MASSIF Web Studio zum Profil

St. Christophstrasse 8 5400 Baden (Schweiz) www.massif.ch

Versionen

3.5.6

Für REDAXO
^5.13.0
Veröffentlicht am
08.09.2026
Require / PHP
>=8.3

Fixed

  • stubs/style.css: a glob inside a CSS comment closed it early. The
    commented-out @source "../../fragments/**/*.php"; contains */ (inside
    **/), so the comment ended after /** and left stray tokens in the
    scaffolded stylesheet. The hint now suggests the directory form
    @source "../../fragments";, which Tailwind scans recursively.

3.5.5

Für REDAXO
^5.13.0
Veröffentlicht am
19.08.2026
Require / PHP
>=8.3

Fixed

  • Scaffolded Tailwind @source globs were silently dead. The stub's
    @source "/src/…" paths resolve as absolute filesystem paths and matched
    nothing — Tailwind's default whole-project heuristic scan carried every
    project unnoticed, and also tokenized docs/markdown prose into bogus class
    candidates (spurious tailwind-clamp warnings at build time, e.g.
    clamp-[text,…]). The stub now uses @import "tailwindcss" source(none)
    with stylesheet-relative globs (incl. src/assets/js for Alpine class
    getters), making scanning explicit-only and deterministic.

3.5.4

Für REDAXO
^5.13.0
Veröffentlicht am
14.08.2026
Require / PHP
>=8.3

Fixed

  • Shipped stubs/biome.jsonc broke biome in user projects. Biome's tree-wide config discovery found the stub under src/addons/viterex_addon/stubs/ as a second root config and aborted before checking anything — and since the scaffolded lint script is biome check && stylelint …, stylelint never ran either. The stub now ships as biome.jsonc.stub (invisible to discovery) and is renamed to biome.jsonc at install time. Same treatment for stylelint.config.js, which stylelint's per-file upward config lookup could pick up for stub files.
  • Lint/format script globs scoped to the assets source dir. The package.json stub's stylelint/prettier globs were **/* — in a real install they matched core, addon, and vendored files (26k foreign errors in a reported project). They now carry a __VITEREX_ASSETS_SOURCE_DIR__ token replaced with the configured assets_source_dir at scaffold time.

Changed

  • Scaffolded biome + stylelint configs understand Tailwind 4 (@theme, @utility, @variant, --value()/--modifier() …), exclude core/addon/vendored/generated paths in both classic and modern layouts, and exclude machine-managed manifests (composer.json, package.json) from the format gate. Known smells in the massif starter libs are downgraded to warnings so they surface without gating.
  • Stub vite.config.js and style.css now pass the scaffolded lint gate.

Upgrade note for existing projects: your scaffolded biome.jsonc / stylelint.config.js / package.json are kept as-is; apply the new excludes and scoped globs manually or re-install stubs with overwrite.

3.5.3

Für REDAXO
^5.13.0
Veröffentlicht am
08.08.2026
Require / PHP
>=8.3

Fixed

Stale host_url (http://localhost) in structure.json after a seeded install (Vite dev server answering with Access-Control-Allow-Origin: http://localhost). The 3.5.2 fix regenerated the file on every cache clear, but Config::getHostUrl() read the domain from rex_yrewrite::getDomains() — static state built at boot from yrewrite's cached config.php. When the database is seeded after that cache was generated (create-viterex: package:install → seed → cache:clear), the CLI cache-clear process still saw zero domains and wrote localhost; only the next cache clear picked up the domain — and a dev server started in between kept the wrong CORS origin until restarted.

getHostUrl() now queries the rex_yrewrite_domain table directly (source of truth, always current), normalizing rows the same way yrewrite does (new pure helper Config::hostUrlFromDomainRows(), unit-tested).

3.5.2

Für REDAXO
^5.13.0
Veröffentlicht am
07.08.2026
Require / PHP
>=8.3

Fixed

Bogus host_url (http://.) in structure.json (Vite dev server answering with Access-Control-Allow-Origin: http://.). Two defects, both fixed:

  • Config::getHostUrl() used rex_yrewrite::getDefaultDomain(), which returns yrewrite's synthetic catch-all (host null), not the configured domain. Its URL is built from $_SERVER, so any CLI context — console commands, an installer running package:install — produced http://.. getHostUrl() now picks the first real yrewrite domain (host set) and only then falls back to $_SERVER.
  • structure.json was only written on addon install and on saving the settings page, so yrewrite domains configured afterwards (e.g. an installer seeding the database after package:install) never reached the file. It is now regenerated on every cache clear (CACHE_DELETED extension point, LATE so yrewrite rebuilds its own data first) — a plain bin/console cache:clear or the dev badge's cache-clear button self-heals a stale host_url.

3.5.1

Für REDAXO
^5.13.0
Veröffentlicht am
23.07.2026
Require / PHP
>=8.3

Fixed

  • One-request fatal during addon update (Class "Ynamite\ViteRex\Csp" not found in Badge.php): the old version's badge OUTPUT_FILTER closure lazy-loads the new Badge.php after files are swapped, before the autoloader knows about lib/Csp.php. install.php now eagerly requires Csp so the late-firing closure resolves it. Takes effect for updates to this release and later.

3.5.0

Für REDAXO
^5.13.0
Veröffentlicht am
16.06.2026
Require / PHP
>=8.3

Added

  • CSP nonce support. Every tag ViteRex emits — <script type="module">, <link rel="stylesheet">, and the relevant <link rel="modulepreload"> / <link rel="preload" as="style"> tags, plus the dev badge — now carries the per-request nonce from rex_response::getNonce() (core ≥5.15.0, with a bin2hex(random_bytes(16)) fallback on older cores). A project-defined strict CSP (script-src 'self' 'nonce-…'; style-src 'self' 'nonce-…') now works with ViteRex assets out of the box. Stamping is always-on (a stray nonce is inert without a CSP) and requires no configuration. New Ynamite\ViteRex\Csp helper (nonce(), attr()). ViteRex deliberately does not build or send the CSP header — the policy is page-global and remains the project's responsibility. Dev/HMR remains best-effort (Vite injects its own runtime tags ViteRex cannot reach); production is fully clean.

3.4.2

Für REDAXO
^5.13.0
Veröffentlicht am
29.05.2026
Require / PHP
>=8.3

Version 3.4.2
**

  • Remove unused imports from boot.php

Full Changelog: https://github.com/ynamite/viterex_addon/compare/3.4.1...3.4.2

3.4.1

Für REDAXO
^5.13.0
Veröffentlicht am
22.05.2026
Require / PHP
>=8.3

3.4.0

Für REDAXO
^5.13.0
Veröffentlicht am
08.05.2026
Require / PHP
>=8.3

Behoben

Tailwind-Utility-Klassen auf Inline-SVGs werden nicht mehr zerprefixed

Der IdPrefixer (lib/Svg/IdPrefixer.php) hat bisher jeden Token in einem class="..."-Attribut auf SVG-Elementen mit dem dateinamen-abgeleiteten Namespace versehen — auch wenn die Klasse gar nicht im <style>-Block der SVG definiert war. Aus class="fill-blue-500 hover:fill-blue-700" wurde class="img-foo-fill-blue-500 img-foo-hover:fill-blue-700", und Tailwinds externe Utility-CSS hat nicht mehr gematcht.

Neu: Auto-Scope. Der Prefixer sammelt aus allen <style>-Blöcken die Klassennamen, die als Selektoren auftauchen, in ein Set. Nur Tokens aus class="...", die in diesem Set vorkommen, werden geprefixed. Lokale <style>-Klassendefinitionen werden weiterhin gescoped (sind per Konstruktion im Set enthalten); externe Klassen (Tailwind, Projekt-CSS, BEM) bleiben unangetastet, damit Host-Page-CSS sie weiterhin matcht. Spiegelbildlich zum bereits existierenden $idSet-Mechanismus, der Hex-Farben in <style> davor schützt, als ID-Selektoren behandelt zu werden.

Die Headline-Garantie — zwei SVGs mit gleichen .cls-1-Definitionen kollidieren beim gemeinsamen Inline-Einbetten nicht — bleibt unverändert: lokal in <style> deklarierte Klassen werden weiterhin pro SVG eindeutig gescoped.

Cache-Invalidation: Der Cache-Key in Assets::inline() enthält jetzt IdPrefixer::VERSION (aktuell 2), sodass v3.3.x-Cache-Einträge (überprefixed) beim ersten Inline-Aufruf nach dem Upgrade automatisch verworfen werden. Alte Dateien bleiben als verwaister Cache-Müll liegen — der Cache ist unkritisch und wird beim Deinstallieren des Addons komplett entfernt.

Bekannte Einschränkung: Attribut-Selektoren wie [class~="foo"] werden nicht geparsed. Klassen, die ausschliesslich darüber erreichbar sind, müssen zusätzlich als reine .foo-Regel in <style> definiert werden, damit der Auto-Scope sie erkennt.

deriveStablePrefix()liefert nicht mehr denviterex-`-Prefix

Commit 9d259f1 (post-3.3.1) hat den viterex--Namespace aus den Docblock-Beispielen, der README und dem Unit-Test entfernt — die Funktion selbst hat aber weiterhin 'viterex-' . \$slug zurückgegeben. testStablePrefixDerivation ist seitdem auf main gegen eine Funktion gelaufen, die mit keiner ihrer drei Quellen mehr übereingestimmt hat. Die Funktion liefert jetzt den blanken Slug (img/icon-foo.svg → img-icon-foo).

Hinzugefügt

Optionaler ?bool \$backup-Parameter in StubsInstaller::installFromDir()

Default true — bestehende Dateien werden weiterhin nach <datei>.bak.<timestamp> gesichert, bevor sie überschrieben werden (bisheriges Verhalten). Auf false setzen, wenn ein Downstream-Addon einen eigenen Update-Flow hat und keine Backup-Schwemme produzieren möchte. Rückwärtskompatibel.

Intern

Vier neue Tests in tests/Svg/IdPrefixerTest.php decken die Auto-Scope-Regel ab: nur externe Klassen bleiben unverändert, gemischt lokal + extern wird teilweise geprefixed, Tailwind-4-Tokens mit Escaped-Colon (hover:fill-blue-700) bleiben durchgängig unangetastet, mehrere <style>-Blöcke speisen alle in das Set ein. testPrefixesClassAttributes updated — die alte Fixture (kein <style>, nur class="cls-1") würde unter der neuen Regel nicht mehr geprefixed. Vollständige Suite: 100 Tests, alle grün.


Voller Changelog: CHANGELOG.md

3.3.1

Für REDAXO
^5.13.0
Veröffentlicht am
08.05.2026
Require / PHP
>=8.3

3.3.0

Für REDAXO
^5.13.0
Veröffentlicht am
05.05.2026
Require / PHP
>=8.3

Breaking — minimum PHP bumped to 8.3

The addon now requires PHP >=8.3 (was >=8.1), to enable the new
mathiasreker/php-svg-optimizer runtime dependency. Active Redaxo
installs have largely moved to 8.3+ since its November 2023 release;
sites still on 8.1/8.2 should pin to v3.2.x.

Added

  • Automatic SVG cleanup & optimization (lib/Svg/, lib/Media/SvgHook.php,
    assets/viterex-vite-plugin.js). Engine selection follows
    Server::getDeploymentStage():
    • Dev stage → SVGO (Node) everywhere. The Vite plugin walks
      <assets_source_dir>/**/*.svg on dev-server start and on buildStart
      and rewrites each file 1:1 in place; the viteStaticCopy transform
      optimizes SVGs en route to the build output. Media-pool uploads run
      through SVGO via shell-out (npx --no-install svgo) when available,
      with PHP-side fallback if exec is disabled or SVGO isn't installed.
    • Staging / prodmathiasreker/php-svg-optimizer ^8.5 for the
      media-pool runtime path only. Other SVGs are assumed already optimized
      in the deploy artifact (dev did it before commit).
    • Default ON (svg_optimize_enabled='1'); single toggle in ViteRex →
      Settings → "SVG optimization". Mirrored to structure.json so the
      Vite plugin honors it on the Node side.
    • Fail-open contract: any failure (malformed SVG, missing tooling,
      write error) returns the original bytes unchanged. Idempotent —
      second optimization pass round-trips identically.
    • Security side-effect for media-pool uploads: <script> tags and
      on* event handlers are stripped, closing an XSS path that exists
      by default in any Redaxo install accepting SVG uploads.
  • StubsInstaller::syncPackageDeps() is now public (formerly
    private mergePackageDeps()). Lets install.php and downstream
    addons push npm deps into the user's package.json without doing a
    full stubs install. Additive, version-compare merge; idempotent.
    install.php uses it to add svgo: ^4.0.0 on every install/update,
    so existing v3.2.x installs upgrading to v3.3.0 see SVGO appear in
    their package.json automatically — they just run npm install.
  • IdPrefixer scope-isolation for inlined SVGs (lib/Svg/IdPrefixer.php,
    wired into Assets::inline()). Each inlined SVG gets its id/class
    attributes and internal references (url(#X), <use href="#X">,
    xlink:href="#X", <style> selectors) prefixed with a stable,
    filename-derived namespace (viterex-<path-slug>-…). Without this,
    two SVGs sharing .cls-1-style classes (typical Figma/Illustrator
    export) cross-bleed because their <style> blocks have document-level
    scope when inlined into HTML. Hex colour literals like #fff are
    protected by an id-set filter — only #X selectors that match a real
    id="X" in the document get rewritten. Result is cached at
    rex_path::addonCache('viterex_addon', 'inline-svg/<sha1>.svg') keyed
    on path + content, so the rewrite cost is paid once per (file,
    content) pair. Disk files stay generic (unchanged) — the prefix is
    applied only at inline time, not in the source-mutation pass, so the
    same source file remains usable as <img src> / background-image.
    Per-file opt-out via the magic comment <!-- viterex:no-prefix -->
    anywhere in the SVG. Honors the global svg_optimize_enabled toggle
    (off → no prefixing).

Internal

  • Simplification follow-up (2026-05-05):

    • *Dev-stage `MEDIA_hook is now a no-op.** Devs don't want SVGO firing on every test upload. The Vite build (npm run build) and the newviterex:optimize-svgsconsole command sweep the media pool when devs are ready. Production / staging behavior is unchanged: every uploaded SVG runs throughPhpOptimizer, which stripsandon*handlers as a security side-effect. The "is dev" check requires ydeploy to be installed AND report 'dev'— without ydeploy,Server::getDeploymentStage()falls through to'dev'by default, so a bare=== 'dev'` check would
      silently disable the security stripping on prod installs that
      haven't installed ydeploy. Default: when ydeploy is absent, run
      the optimizer (the safe choice).
    • OptimizerFactory deleted (lib/Svg/OptimizerFactory.php,
      plus its 5 tests). With the dev MEDIA_* branch removed, SvgHook
      always wants PhpOptimizer and the new console command picks its
      engine inline (SvgoCli::isAvailable() ? new SvgoCli() : new PhpOptimizer()).
      The factory's $stage parameter no longer carried information.
    • viterex:optimize-svgs console command (lib/Console/OptimizeSvgsCommand.php).
      Walks <assets_source_dir> and <media_dir>, optimizes via SVGO
      if available else PhpOptimizer. Flags: --dry-run (list, don't
      write), --force (ignore cache). Honors svg_optimize_enabled.
      The constructor takes an optional OptimizerInterface for test
      injection; coverage is via end-to-end smoke in the test install
      rather than a unit test (mirrors InstallStubsCommand's
      no-unit-test precedent — backfill candidate for a future cleanup).
    • Vite build now walks <media_dir> during buildStart (NOT
      configureServer, so dev-server start stays fast). Same SVGO
      invocation as the existing assets walk.
    • Shared optimization cache (<cache_dir>/svg-optimized.json).
      Both the Vite plugin and the console command read/write the same
      JSON sidecar — sha1 of post-optimization content keyed by
      project-relative path. Files matching the recorded sha1 are
      skipped (already in optimal form). Helper: lib/Svg/OptimizationCache.php,
      fail-open on corrupted JSON, 6 unit tests.
    • structure.json gains media_dir + cache_dir (both derived
      from rex_path::*, not user config — no settings form fields,
      no Config::DEFAULTS entry, just emitted at sync time).
  • SVGO config centralized to assets/svgo-config.mjs — single
    source of truth for both the Vite plugin (import from sibling) and
    the PHP shell-out path (SvgoCli passes the file via --config).
    Previously the same config existed twice, as a JS object literal in
    viterex-vite-plugin.js and a heredoc string in SvgoCli.php, kept
    in sync by hand and a comment. The two definitions silently drifted
    during testing of v3.3.0; this fix removes the possibility entirely.
    Bonus: any future per-file extensions (e.g., scoped overrides) can
    splice into the canonical config from either runtime without
    serialization/translation.

  • New PHP test suite under tests/Svg/ (27 cases) covering each
    optimizer impl, the factory's stage-driven resolution + SVGO-fallback
    branches, malformed-input fail-open, idempotency, the canonical
    config file's existence + shape, and the IdPrefixer rewrite rules
    (id/class attrs, url(), <use>/xlink:href, <style> selectors,
    hex-colour false-positive guard, opt-out comment, stable prefix
    derivation, and the headline two-SVG no-collision scenario). Adds 3
    testable seams: OptimizerFactory::for($stage, $enabled, ?$svgoAvailable)
    takes the SVGO-availability check as an injectable parameter so the
    fallback path is unit-testable without environment setup;
    SvgoCli::resetAvailabilityCache() (@internal) clears the per-request
    cache; Config::isCheckboxChecked() was promoted from private to
    public static so the SvgHook can decode the toggle without duplicating
    the |1|/|0| parsing logic.

  • Config::isEnabled() — new helper for reading default-ON checkbox
    toggles. Config::get() falls through to DEFAULTS when the stored
    value is null (which is what rex_form_checkbox_element writes when
    saving an unchecked box: setValue(null) → getSaveValue → null). For
    default-OFF checkboxes like https_enabled that's harmless — both
    null and the seeded '0' resolve to "off". For default-ON checkboxes
    it would silently flip the user's explicit "off" save back to "on" on
    every read. isEnabled() uses array_key_exists (instead of isset/??)
    on the full namespace array to distinguish "explicitly set to null"
    from "never written", honoring the user's intent. Both
    lib/Media/SvgHook.php and Config::syncStructureJson() now read
    svg_optimize_enabled and https_enabled through this helper.

  • tests/CheckboxValueTest.php — pins Config::isCheckboxChecked()
    across all six storage forms a checkbox can take in rex_config
    (|1|, '1', '', '0', |0|, ||). Any future regression of the
    v3.0 https_enabled === '1' bug breaks tests immediately.

  • Vite plugin defaults to ON when structure.svg_optimize_enabled is
    missing
    (structure.svg_optimize_enabled !== false instead of
    === true). Robust against stale structure.json — e.g., if the
    user upgraded from v3.2.x and PHP-FPM opcache was holding the old
    Config.php when syncStructureJson last ran.

  • ydeploy-helper sidecar moved out of project root
    (lib/Deploy/Sidecar.php). Sidecar::path() now resolves to
    rex_path::addonData('viterex_addon', 'deploy.config.php') instead
    of rex_path::base('deploy.config.php'), keeping deploy state inside
    the addon's data directory instead of leaking into the project root.
    v3.2.6 was never tagged, so no users are affected by the path change.

Fixed

  • viteStaticCopy no longer nests the source path under dest.
    vite-plugin-static-copy v4 (the version users on the latest stubs
    pull) preserves the matched file's directory tree under dest by
    default — a regression from v3's flat-copy behavior. Without
    intervention, src/assets/img/foo.svg landed at
    <outDir>/assets/img/src/assets/img/foo.svg instead of
    <outDir>/assets/img/foo.svg. resolveCopyTargets() now sets
    rename: { stripBase: true } on every target so the basename joins
    dest directly. No-op on v3. Bug existed independent of the new SVG
    optimization toggle but surfaced during v3.3 testing because the
    copied SVGs were the obvious thing to inspect.

3.2.5

Für REDAXO
^5.13.0
Veröffentlicht am
02.05.2026
Require / PHP
>=8.1

Fixed

  • Server::isProductionDeployment() and Server::isStagingDeployment() no longer fatal without ydeploy (lib/Server.php). Both methods called rex_ydeploy::factory() directly with no class-availability guard, so any project that installed viterex_addon without ydeploy got Class "rex_ydeploy" not found on the first call. The most visible victim was the backend dev-badge gate at boot.php:113 (every backend page load with a logged-in user), but the same crash also fired from Server::__construct → checkDebugMode() — meaning every Server::factory() call from OutputFilter, Preload, Assets, and Badge::get() was affected. Both methods now early-return false when rex_addon::get('ydeploy')->isAvailable() is false, matching the behavior already documented in CLAUDE.md and the convention used at boot.php:97 (YREWRITE_SEO_TAGS registration). With the guard pushed to the source, the call site at boot.php:113 no longer needs its own ydeploy check, and future callers don't have to know about the dependency. getDeploymentStage() continues to fall through to 'dev' when neither flag is true — unchanged behavior, now actually reachable on ydeploy-less installs.

3.2.4

Für REDAXO
^5.13.0
Veröffentlicht am
01.05.2026
Require / PHP
>=8.1

Fixed

  • Static assets attached to a CSS entry are now preloaded (lib/Preload.php). When Vite emits an entry like src/assets/css/style.css whose manifest record has an assets: [...] siblings array (e.g. @font-face woff2 fonts referenced from CSS, or images referenced via url()), Preload::walkManifestEntry was returning early on any .css-extension entry — silently dropping every sibling preload tag. The early-return is meant to skip emitting a modulepreload for the CSS file itself (the stylesheet link is rendered by Assets::renderBlock), not to skip the asset loop further down. The CSS guard now scopes only the JS-only emissions (modulepreload, entry.css, imports/dynamicImports recursion); entry.assets runs for both CSS and JS entries and emits the appropriate <link rel="preload" as="font|image|video|audio" …> tags. Cross-entry dedup is preserved by the existing array_unique in build(). The bug only surfaced when a project shipped a standalone CSS entry whose assets siblings should be preloaded — JS entries that import CSS were unaffected because their fonts already surfaced via the JS chunk's own assets field.

Internal

  • PreloadTest (tests/PreloadTest.php) covers the regression plus six adjacent paths: JS modulepreload + imports walking, JS css siblings as as=style preload, image asset on a CSS entry, JS-entry imported asset, cross-entry dedup, and unknown-extension omission. To keep tests bootstrap-free (mirrors OutputFilterTest), Preload now exposes an @internal static seam Preload::buildLinesForManifest(manifest, buildUrlPath, entries) that the instance build() delegates to. Public API and behavior at all call sites (Assets::renderBlock, the VITEREX_PRELOAD extension point) are unchanged.

3.2.3

Für REDAXO
^5.13.0
Veröffentlicht am
30.04.2026
Require / PHP
>=8.1

Fixed

  • viterex_addon.zip no longer leaks into the MyREDAXO package. The publish workflow created a viterex_addon.zip for the GitHub release upload, but FriendsOfREDAXO/installer-action@1.2.0 then built its own MyREDAXO package by zipping the entire working directory (archive.glob('**', { cwd, skip/ignore: installer_ignore + redaxo defaults })). Redaxo's default ignore list does not include *.zip, so the GitHub-release zip was getting bundled into the MyREDAXO upload — a self-referential nested archive that ended up inside every install. Added viterex_addon.zip to package.yml's installer_ignore list so the action's globber skips it. The GitHub-release artifact (which already used -x "viterex_addon.zip" in its own zip command) was always clean — only the MyREDAXO package was affected.

3.2.2

Für REDAXO
^5.13.0
Veröffentlicht am
30.04.2026
Require / PHP
>=8.1

Fixed

  • Dev badge no longer overflows on mobile. The git-branch panel inside the badge could push the total width past narrow viewports — particularly with long branch names like feature/<descriptive-slug>. The .branch panel is now display: none below max-width: 768px (assets-src/viterex-badge.module.css). Other badge panels (Redaxo + ViteRex version labels, stage indicator, Vite-running dot, clear-cache button) and any VITEREX_BADGE extension-point panels (e.g. redaxo-massif's Tailwind breakpoint indicator) are unaffected. The data-git-branch attribute on the script tag remains present for future use (e.g. a tooltip).

3.2.1

Für REDAXO
^5.13.0
Veröffentlicht am
30.04.2026
Require / PHP
>=8.1

Fixed

  • REX_VITE replacement scoped to <head> (lib/OutputFilter.php). Previously OutputFilter::rewriteHtml replaced every REX_VITE occurrence anywhere in the rendered HTML, including literal mentions inside <code> / <pre> blocks on documentation pages that themselves describe how to use viterex_addon. The filter now finds the first <head>...</head> block and replaces only the first REX_VITE (or REX_VITE[src="…"]) inside it; subsequent placeholders and any REX_VITE text in <body> are left as literal text. Auto-insert before </head> is unchanged.

Notes for upgraders

  • If you (unusually) had multiple REX_VITE placeholders inside <head> to load different entries, only the first is now replaced. Combine them via the pipe-separated form: REX_VITE[src="src/main.css|src/main.js"].

Internal

  • PHPUnit added as require-dev (phpunit/phpunit ^10.5). tests/OutputFilterTest.php covers the head-only scoping, body-untouched behavior, multiple-in-head, auto-insert, and missing-<head> edge cases. Run via composer test. Test infrastructure (tests/, phpunit.xml.dist, .phpunit.cache) is excluded from the release zip via package.yml installer_ignore and the publish workflow.
  • For testability, the pure transformation in OutputFilter is split into a thin public rewriteHtml() shim that delegates to a new @internal rewriteHtmlWithBlock(string, callable) method. Public API and behavior at all callers (frontend OUTPUT_FILTER, BLOCK_PEEK_OUTPUT) are unchanged.

3.2.0

Für REDAXO
^5.13.0
Veröffentlicht am
29.04.2026
Require / PHP
>=8.1

Added

  • viterex:install-stubs Symfony Console command (lib/Console/InstallStubsCommand.php, registered via console_commands: in package.yml). Programmatic counterpart of the AddOns → ViteRex → Settings → Install stubs button — reuses the same Ynamite\ViteRex\StubsInstaller::run() path, so output, backups, and VITEREX_INSTALL_STUBS extension-point dispatch are identical. Intended for automated install flows that scaffold a project without a browser session (e.g. create-viterex).

    php bin/console viterex:install-stubs            # write only missing files (idempotent)
    php bin/console viterex:install-stubs --overwrite # back up existing (.bak.<timestamp>) and replace
    php bin/console viterex:install-stubs -v          # also list the written file paths

Roadmap note

v3.2 was originally planned for SVG optimization; that work moves to v3.3. v3.2.0 ships the viterex:install-stubs CLI command instead, because create-viterex needs it to scaffold package.json before the Install dependencies pipeline step. SVG optimization (vite-plugin-svgr for templates / CSS / JS, MEDIA_ADD EP for media-pool uploads) is still on the roadmap — see CLAUDE.md.

3.1.3

Für REDAXO
^5.13.0
Veröffentlicht am
28.04.2026
Require / PHP
>=8.1

Fixed

  • Restored rex_developer_manager::setBasePath(rex_path::src()) in boot.php when the developer addon is available. The call was dropped during the v3 refactor along with the now-removed Structure class; without it, the developer addon writes to its default location instead of the Redaxo source directory.

3.1.1

Für REDAXO
^5.13.0
Veröffentlicht am
28.04.2026
Require / PHP
>=8.1

3.1.0

Für REDAXO
^5.13.0
Veröffentlicht am
28.04.2026
Require / PHP
>=8.1

Version 3.1.0
**

Programmatic API additions for downstream addons (e.g. redaxo-massif). No breaking changes.

Added

  • StubsInstaller::installFromDir($sourceDir, $stubsMap, $overwrite, $packageDeps) — public, reusable file-installer. Downstream addons call it from their own install.php / Settings handlers to push files into the user's project, reusing viterex_addon's path-baking, backup-on-overwrite, and structure-aware target resolution.
  • StubsInstaller::appendRefreshGlobs($lines) — public helper for downstream addons that need Vite to live-reload on additional paths (e.g. their own fragments/lib directories). Reads rex_config('viterex','refresh_globs'), idempotently appends only missing lines.
  • VITEREX_INSTALL_STUBS extension point — fired from inside StubsInstaller::run() (the path triggered by viterex's "Install Stubs" button). Subject is the result array {written, skipped, backedUp, gitignoreAction}. Subscribers can append entries by calling installFromDir() themselves and merging the returned arrays into the subject. Params: overwrite (bool, from the user's checkbox).
  • mergePackageDeps() private helper — wired into installFromDir via the $packageDeps argument. Merges npm dependencies into the user's package.json additively, with version_compare resolving conflicts (higher wins).

Internal

  • StubsInstaller::run() refactored to delegate file copying to installFromDir(). Behavior preserved; gitignoreAction still set via the existing mergeGitignore() (now only run by run(), not the generic installFromDir).
  • Hardcoded install-result message in pages/settings.php extracted to a viterex_install_result lang key (lang/en_gb.lang, lang/de_de.lang). Now uses rex_i18n::rawMsg() like the rest of the page.
  • German translation polish in lang/de_de.lang — leftover English fragments translated (Entry PointsEinstiegspunkte, ToolingWerkzeuge, Web-servedVom Webserver ausgeliefertes, Install stubsStubs installieren, JS-Entry / CSS-EntryJS-Einstiegspunkt / CSS-Einstiegspunkt, Dev-Tooling-ConfigsDev-Tooling-Konfigurationen).

Documentation

  • README.md rewritten in German with full feature coverage matching the English version (entry points, paths, dev settings, hot-file flow, REX_VITE placeholder, dev badge, downstream-addon API). Earlier in the cycle, the English README was also revised for installation paths and settings.
  • docs/vite-plus-evaluation.md added — evaluation of a potential Vite+ migration. Recommendation: monitor, no migration today.
  • Hero image viterex.png added at repo root.

3.0.1

Für REDAXO
^5.13.0
Veröffentlicht am
27.04.2026
Require / PHP
>=8.1

3.0.0

Für REDAXO
^5.13.0
Veröffentlicht am
27.04.2026
Require / PHP
>=8.1

ViteRex 3.0.0 — Standalone Redaxo Addon

Breaking release. v1.x users: see Migration.

ViteRex is now a fully standalone Redaxo addon, installable in any Redaxo setup (classic, modern/ydeploy, or with the theme addon). Configuration lives in the Redaxo backend; on a button click the addon scaffolds a complete Vite + Tailwind 4 frontend pipeline into your project root.

Highlights

  • Backend CRUD form for all paths and dev settings (entries, public dir, build dir, URL prefix, source dir, static-copy dirs, HTTPS, live-reload globs). Persisted to rex_config, mirrored to a structure.json the Vite plugin reads.
  • "Install Stubs" button scaffolds package.json, vite.config.js, .env.example, dev-tooling configs, and entry stubs into the project root. Optional "Overwrite existing" checkbox creates timestamped backups before replacing — never silently destroys user code.
  • Tailwind 4 by default: @tailwindcss/vite, @tailwindcss/forms, @tailwindcss/typography, tailwind-clamp. Don't want it? Delete two lines from the scaffolded vite.config.js.
  • Laravel-vite-plugin-style API: scaffolded vite.config.js is ~10 lines. viterex() injects build/server/css/resolve via Vite's config() hook; user overrides win via Vite's mergeConfig. Escape hatch viterex({ injectConfig: false }) for full control.
  • REX_VITE placeholder with optional [src="…"] attribute (pipe-separated for multiple entries). Auto-inserts before </head> when no placeholder is found in the rendered HTML.
  • PHP helpers for static assets referenced from templates: Assets::url('img/logo.png'), Assets::path(), Assets::inline().
  • Reliable live-reload: PHP extension-point handlers on ~30 Redaxo content-save events (ART_*, CAT_*, SLICE_*, MEDIA_*, TEMPLATE_*, MODULE_*, etc.) touch() a single signal file <base>/.vite-reload-trigger that Vite watches. Reloads fire only on actual admin saves — no more spurious reloads from cache regeneration.
  • Hot-file dev detection at <base>/.vite-hot (single source of truth across structures); replaces the per-request HTTP probe.
  • block_peek integrationREX_VITE placeholders work inside block_peek's preview iframes via a BLOCK_PEEK_OUTPUT handler.
  • mkcert integrationnpm run setup-https generates local certs; ViteRex auto-detects them when https_enabled is on in Settings.
  • Friendly Vite-server landing page — visiting the Vite dev URL directly shows a styled "Vite is running, your site is at " page instead of a blank screen.
  • Badge: stage indicator (dev/staging/prod), Vite-running dot with tooltip showing the dev URL on hover, Clear-cache button (CSRF-protected POST), VITEREX_BADGE extension point for downstream addons.
  • Multi-language: full de_de + en_gb translations.

Installation

  • Redaxo Installer (recommended): Backend → AddOns → Installer, search viterex, download, activate.
  • Manual from GitHub: unpack into redaxo/src/addons/viterex/ (modern) or addons/viterex/ (classic), then install + activate in the backend.

After activation: open AddOns → ViteRex → Settings, review the defaults (modern-friendly out of the box; for classic/theme adjust Public directory and Build output directory), save, then click Install Stubs.

a id="migration-from-v1x"> Migration from v1.x

  • Assets::get() removed — templates that called <?= $assets['js'] ?> / $assets['css'] / $assets['preload'] should switch to REX_VITE[src="…"], or simply remove the placeholder and rely on auto-insert before </head>.
  • Server::getAssetsUrl() / getImg() / getCss() / getFont() / getJs() / getAssetsPath() removed — replaced by Assets::url(), Assets::path(), Assets::inline().
  • Auto-detection of classic / modern / theme structure removed — paths are now configured via the backend Settings form. Defaults match modern (ydeploy); adjust Public directory and related fields once for classic/theme.
  • PHP >= 8.1, Vite ^8, Node >= 20.19.

Requirements

  • Redaxo ^5.13.0
  • PHP >= 8.1
  • Node >= 20.19 (Vite 8 requirement) for the frontend pipeline

Documentation

Full docs in README.md — covers the REX_VITE placeholder, PHP helpers, CRUD settings reference, extending the Vite plugin (Laravel-style), block_peek integration, and a testing checklist.

Issues / Feedback

Bug reports and feature requests on GitHub Issues.