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.chVersionen
3.5.6
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
Fixed
- Scaffolded Tailwind
@sourceglobs 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 (spurioustailwind-clampwarnings at build time, e.g.
clamp-[text,…]). The stub now uses@import "tailwindcss" source(none)
with stylesheet-relative globs (incl.src/assets/jsfor Alpine class
getters), making scanning explicit-only and deterministic.
3.5.4
Fixed
- Shipped
stubs/biome.jsoncbroke biome in user projects. Biome's tree-wide config discovery found the stub undersrc/addons/viterex_addon/stubs/as a second root config and aborted before checking anything — and since the scaffoldedlintscript isbiome check && stylelint …, stylelint never ran either. The stub now ships asbiome.jsonc.stub(invisible to discovery) and is renamed tobiome.jsoncat install time. Same treatment forstylelint.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.jsonstub'sstylelint/prettierglobs 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 configuredassets_source_dirat 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.jsandstyle.cssnow 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
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
Fixed
Bogus host_url (http://.) in structure.json (Vite dev server answering with Access-Control-Allow-Origin: http://.). Two defects, both fixed:
Config::getHostUrl()usedrex_yrewrite::getDefaultDomain(), which returns yrewrite's synthetic catch-all (hostnull), not the configured domain. Its URL is built from$_SERVER, so any CLI context — console commands, an installer runningpackage:install— producedhttp://..getHostUrl()now picks the first real yrewrite domain (host set) and only then falls back to$_SERVER.structure.jsonwas only written on addon install and on saving the settings page, so yrewrite domains configured afterwards (e.g. an installer seeding the database afterpackage:install) never reached the file. It is now regenerated on every cache clear (CACHE_DELETEDextension point,LATEso yrewrite rebuilds its own data first) — a plainbin/console cache:clearor the dev badge's cache-clear button self-heals a stalehost_url.
3.5.1
Fixed
- One-request fatal during addon update (
Class "Ynamite\ViteRex\Csp" not foundinBadge.php): the old version's badgeOUTPUT_FILTERclosure lazy-loads the newBadge.phpafter files are swapped, before the autoloader knows aboutlib/Csp.php.install.phpnow eagerly requiresCspso the late-firing closure resolves it. Takes effect for updates to this release and later.
3.5.0
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 fromrex_response::getNonce()(core ≥5.15.0, with abin2hex(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. NewYnamite\ViteRex\Csphelper (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
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
Full Changelog: https://github.com/ynamite/viterex_addon/compare/3.4.0...3.4.1
3.4.0
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
Full Changelog: https://github.com/ynamite/viterex_addon/compare/3.3.0...3.3.1
3.3.0
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>/**/*.svgon dev-server start and onbuildStart
and rewrites each file 1:1 in place; theviteStaticCopytransform
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 ifexecis disabled or SVGO isn't installed. - Staging / prod →
mathiasreker/php-svg-optimizer ^8.5for 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 tostructure.jsonso 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.
- Dev stage → SVGO (Node) everywhere. The Vite plugin walks
StubsInstaller::syncPackageDeps()is now public (formerly
private mergePackageDeps()). Letsinstall.phpand downstream
addons push npm deps into the user'spackage.jsonwithout doing a
full stubs install. Additive, version-compare merge; idempotent.
install.phpuses it to addsvgo: ^4.0.0on every install/update,
so existing v3.2.x installs upgrading to v3.3.0 see SVGO appear in
theirpackage.jsonautomatically — they just runnpm install.IdPrefixerscope-isolation for inlined SVGs (lib/Svg/IdPrefixer.php,
wired intoAssets::inline()). Each inlined SVG gets itsid/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#fffare
protected by an id-set filter — only#Xselectors 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
onpath + 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 globalsvg_optimize_enabledtoggle
(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). OptimizerFactorydeleted (lib/Svg/OptimizerFactory.php,
plus its 5 tests). With the devMEDIA_*branch removed,SvgHook
always wantsPhpOptimizerand the new console command picks its
engine inline (SvgoCli::isAvailable() ? new SvgoCli() : new PhpOptimizer()).
The factory's$stageparameter no longer carried information.viterex:optimize-svgsconsole command (lib/Console/OptimizeSvgsCommand.php).
Walks<assets_source_dir>and<media_dir>, optimizes via SVGO
if available elsePhpOptimizer. Flags:--dry-run(list, don't
write),--force(ignore cache). Honorssvg_optimize_enabled.
The constructor takes an optionalOptimizerInterfacefor test
injection; coverage is via end-to-end smoke in the test install
rather than a unit test (mirrorsInstallStubsCommand's
no-unit-test precedent — backfill candidate for a future cleanup).- Vite build now walks
<media_dir>duringbuildStart(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.jsongainsmedia_dir+cache_dir(both derived
fromrex_path::*, not user config — no settings form fields,
noConfig::DEFAULTSentry, just emitted at sync time).
- *Dev-stage `MEDIA_
-
SVGO config centralized to
assets/svgo-config.mjs— single
source of truth for both the Vite plugin (importfrom sibling) and
the PHP shell-out path (SvgoClipasses the file via--config).
Previously the same config existed twice, as a JS object literal in
viterex-vite-plugin.jsand a heredoc string inSvgoCli.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 theIdPrefixerrewrite 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 fromprivateto
public staticso 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 toDEFAULTSwhen the stored
value isnull(which is whatrex_form_checkbox_elementwrites when
saving an unchecked box:setValue(null) → getSaveValue → null). For
default-OFF checkboxes likehttps_enabledthat's harmless — both
nulland 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()usesarray_key_exists(instead ofisset/??)
on the full namespace array to distinguish "explicitly set to null"
from "never written", honoring the user's intent. Both
lib/Media/SvgHook.phpandConfig::syncStructureJson()now read
svg_optimize_enabledandhttps_enabledthrough this helper. -
tests/CheckboxValueTest.php— pinsConfig::isCheckboxChecked()
across all six storage forms a checkbox can take inrex_config
(|1|,'1','','0',|0|,||). Any future regression of the
v3.0https_enabled=== '1'bug breaks tests immediately. -
Vite plugin defaults to ON when
structure.svg_optimize_enabledis
missing (structure.svg_optimize_enabled !== falseinstead of
=== true). Robust against stalestructure.json— e.g., if the
user upgraded from v3.2.x and PHP-FPM opcache was holding the old
Config.phpwhensyncStructureJsonlast 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
ofrex_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
viteStaticCopyno longer nests the source path underdest.
vite-plugin-static-copyv4 (the version users on the latest stubs
pull) preserves the matched file's directory tree underdestby
default — a regression from v3's flat-copy behavior. Without
intervention,src/assets/img/foo.svglanded at
<outDir>/assets/img/src/assets/img/foo.svginstead of
<outDir>/assets/img/foo.svg.resolveCopyTargets()now sets
rename: { stripBase: true }on every target so the basename joins
destdirectly. 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
Fixed
Server::isProductionDeployment()andServer::isStagingDeployment()no longer fatal withoutydeploy(lib/Server.php). Both methods calledrex_ydeploy::factory()directly with no class-availability guard, so any project that installedviterex_addonwithoutydeploygotClass "rex_ydeploy" not foundon the first call. The most visible victim was the backend dev-badge gate atboot.php:113(every backend page load with a logged-in user), but the same crash also fired fromServer::__construct → checkDebugMode()— meaning everyServer::factory()call fromOutputFilter,Preload,Assets, andBadge::get()was affected. Both methods now early-returnfalsewhenrex_addon::get('ydeploy')->isAvailable()is false, matching the behavior already documented inCLAUDE.mdand the convention used atboot.php:97(YREWRITE_SEO_TAGSregistration). With the guard pushed to the source, the call site atboot.php:113no 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
Fixed
- Static assets attached to a CSS entry are now preloaded (
lib/Preload.php). When Vite emits an entry likesrc/assets/css/style.csswhose manifest record has anassets: [...]siblings array (e.g.@font-facewoff2 fonts referenced from CSS, or images referenced viaurl()),Preload::walkManifestEntrywas returning early on any.css-extension entry — silently dropping every sibling preload tag. The early-return is meant to skip emitting amodulepreloadfor the CSS file itself (the stylesheet link is rendered byAssets::renderBlock), not to skip the asset loop further down. The CSS guard now scopes only the JS-only emissions (modulepreload,entry.css,imports/dynamicImportsrecursion);entry.assetsruns 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 existingarray_uniqueinbuild(). The bug only surfaced when a project shipped a standalone CSS entry whoseassetssiblings should be preloaded — JS entries that import CSS were unaffected because their fonts already surfaced via the JS chunk's ownassetsfield.
Internal
- PreloadTest (
tests/PreloadTest.php) covers the regression plus six adjacent paths: JS modulepreload +importswalking, JScsssiblings asas=stylepreload, image asset on a CSS entry, JS-entry imported asset, cross-entry dedup, and unknown-extension omission. To keep tests bootstrap-free (mirrorsOutputFilterTest),Preloadnow exposes an@internalstatic seamPreload::buildLinesForManifest(manifest, buildUrlPath, entries)that the instancebuild()delegates to. Public API and behavior at all call sites (Assets::renderBlock, theVITEREX_PRELOADextension point) are unchanged.
3.2.3
Fixed
viterex_addon.zipno longer leaks into the MyREDAXO package. The publish workflow created aviterex_addon.zipfor the GitHub release upload, butFriendsOfREDAXO/installer-action@1.2.0then 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. Addedviterex_addon.ziptopackage.yml'sinstaller_ignorelist so the action's globber skips it. The GitHub-release artifact (which already used-x "viterex_addon.zip"in its ownzipcommand) was always clean — only the MyREDAXO package was affected.
3.2.2
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.branchpanel is nowdisplay: nonebelowmax-width: 768px(assets-src/viterex-badge.module.css). Other badge panels (Redaxo + ViteRex version labels, stage indicator, Vite-running dot, clear-cache button) and anyVITEREX_BADGEextension-point panels (e.g.redaxo-massif's Tailwind breakpoint indicator) are unaffected. Thedata-git-branchattribute on the script tag remains present for future use (e.g. a tooltip).
3.2.1
Fixed
REX_VITEreplacement scoped to<head>(lib/OutputFilter.php). PreviouslyOutputFilter::rewriteHtmlreplaced everyREX_VITEoccurrence anywhere in the rendered HTML, including literal mentions inside<code>/<pre>blocks on documentation pages that themselves describe how to useviterex_addon. The filter now finds the first<head>...</head>block and replaces only the firstREX_VITE(orREX_VITE[src="…"]) inside it; subsequent placeholders and anyREX_VITEtext in<body>are left as literal text. Auto-insert before</head>is unchanged.
Notes for upgraders
- If you (unusually) had multiple
REX_VITEplaceholders 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.phpcovers the head-only scoping, body-untouched behavior, multiple-in-head, auto-insert, and missing-<head>edge cases. Run viacomposer test. Test infrastructure (tests/,phpunit.xml.dist,.phpunit.cache) is excluded from the release zip viapackage.ymlinstaller_ignoreand the publish workflow. - For testability, the pure transformation in
OutputFilteris split into a thin publicrewriteHtml()shim that delegates to a new@internal rewriteHtmlWithBlock(string, callable)method. Public API and behavior at all callers (frontendOUTPUT_FILTER,BLOCK_PEEK_OUTPUT) are unchanged.
3.2.0
Added
-
viterex:install-stubsSymfony Console command (lib/Console/InstallStubsCommand.php, registered viaconsole_commands:inpackage.yml). Programmatic counterpart of the AddOns → ViteRex → Settings → Install stubs button — reuses the sameYnamite\ViteRex\StubsInstaller::run()path, so output, backups, andVITEREX_INSTALL_STUBSextension-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
Fixed
- Restored
rex_developer_manager::setBasePath(rex_path::src())inboot.phpwhen thedeveloperaddon is available. The call was dropped during the v3 refactor along with the now-removedStructureclass; without it, the developer addon writes to its default location instead of the Redaxo source directory.
3.1.1
Full Changelog: https://github.com/ynamite/viterex_addon/compare/3.1.0...3.1.1
3.1.0
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 owninstall.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). Readsrex_config('viterex','refresh_globs'), idempotently appends only missing lines.VITEREX_INSTALL_STUBSextension point — fired from insideStubsInstaller::run()(the path triggered by viterex's "Install Stubs" button). Subject is the result array{written, skipped, backedUp, gitignoreAction}. Subscribers can append entries by callinginstallFromDir()themselves and merging the returned arrays into the subject. Params:overwrite(bool, from the user's checkbox).mergePackageDeps()private helper — wired intoinstallFromDirvia the$packageDepsargument. Merges npm dependencies into the user'spackage.jsonadditively, withversion_compareresolving conflicts (higher wins).
Internal
StubsInstaller::run()refactored to delegate file copying toinstallFromDir(). Behavior preserved;gitignoreActionstill set via the existingmergeGitignore()(now only run byrun(), not the genericinstallFromDir).- Hardcoded install-result message in
pages/settings.phpextracted to aviterex_install_resultlang key (lang/en_gb.lang,lang/de_de.lang). Now usesrex_i18n::rawMsg()like the rest of the page. - German translation polish in
lang/de_de.lang— leftover English fragments translated (Entry Points→Einstiegspunkte,Tooling→Werkzeuge,Web-served→Vom Webserver ausgeliefertes,Install stubs→Stubs installieren,JS-Entry/CSS-Entry→JS-Einstiegspunkt/CSS-Einstiegspunkt,Dev-Tooling-Configs→Dev-Tooling-Konfigurationen).
Documentation
README.mdrewritten in German with full feature coverage matching the English version (entry points, paths, dev settings, hot-file flow,REX_VITEplaceholder, dev badge, downstream-addon API). Earlier in the cycle, the English README was also revised for installation paths and settings.docs/vite-plus-evaluation.mdadded — evaluation of a potential Vite+ migration. Recommendation: monitor, no migration today.- Hero image
viterex.pngadded at repo root.
3.0.1
Full Changelog: https://github.com/ynamite/viterex_addon/compare/3.0.0...3.0.1
3.0.0
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 astructure.jsonthe 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 scaffoldedvite.config.js. - Laravel-vite-plugin-style API: scaffolded
vite.config.jsis ~10 lines.viterex()injects build/server/css/resolve via Vite'sconfig()hook; user overrides win via Vite'smergeConfig. Escape hatchviterex({ injectConfig: false })for full control. REX_VITEplaceholder 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-triggerthat 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_peekintegration —REX_VITEplaceholders work inside block_peek's preview iframes via aBLOCK_PEEK_OUTPUThandler.mkcertintegration —npm run setup-httpsgenerates local certs; ViteRex auto-detects them whenhttps_enabledis 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_BADGEextension point for downstream addons. - Multi-language: full
de_de+en_gbtranslations.
Installation
- Redaxo Installer (recommended): Backend → AddOns → Installer, search
viterex, download, activate. - Manual from GitHub: unpack into
redaxo/src/addons/viterex/(modern) oraddons/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 toREX_VITE[src="…"], or simply remove the placeholder and rely on auto-insert before</head>.Server::getAssetsUrl()/getImg()/getCss()/getFont()/getJs()/getAssetsPath()removed — replaced byAssets::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 directoryand 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.