webforge/symfony-vite-bundle
Symfony bundle that integrates the Vite front-end build tool into your app. Provides Twig helpers for rendering script and style tags, dev-server HMR support, and manifest-based production asset resolution, so hashed entrypoints work without manual configuration.
First, set expectations: webforge/symfony-vite-bundle is a Symfony bundle, not a Laravel package. If you are working exclusively in Laravel, you will not install this — your equivalent stack is laravel-vite-plugin plus the @vite Blade directive, and that already covers 90% of what this bundle does. Reach for this package when you are dropped into a Symfony codebase (contract work, inherited project, multi-framework monorepo) and need the same Vite wiring you take for granted in Laravel.
Minimal steps for that scenario:
composer require webforge/symfony-vite-bundle — Flex should auto-register it in config/bundles.php. If you are on a non-Flex skeleton, add Webforge\SymfonyViteBundle\WebforgeSymfonyViteBundle::class => ['all' => true] manually.manifest.json / entrypoints.json to live. The Twig extension class is the first file to open when behaviour is unclear.config/packages/webforge_vite.yaml (name may vary — check the README) with at minimum the Vite build directory and dev-server URL.vite.config.js at the project root with a build.manifest and build.outDir pointing into public/build, mirroring the Laravel setup you already know.@vite('resources/js/app.js') in Blade).Your first use case should be a single smoke test: one entry point, one Twig template, run npm run dev, confirm HMR, then run npm run build and confirm the page still loads from the manifest. Do not wire up multiple entry points or a CDN until that loop is green.
Treat Twig helpers as the @vite directive. Everywhere you would write @vite(['resources/css/app.css', 'resources/js/app.js']) in Blade, the bundle exposes one or more Twig functions that emit the script/link tags from the manifest. Centralise these in a base.html.twig layout so the entry list is defined once, exactly as you would keep it in a single Blade layout.
Dev vs. build is implicit, not explicit. Like laravel-vite-plugin, the bundle typically detects the dev server (hot file / server reachability) and swaps between inline module scripts and hashed manifest assets. Do not branch on APP_ENV in Twig yourself — that is the bundle's job and duplicating it is the fastest way to produce 404s in staging.
Keep one source of truth for paths. The Vite outDir, the bundle's configured build directory, and Symfony's public path must all agree. In Laravel this is handled by convention; here it is configuration, so put the build directory in a single env var (VITE_BUILD_DIR) and reference it from both vite.config.js and the bundle config.
Multiple entry points map cleanly. If your app has separate bundles (admin, storefront, auth), define one entry per surface in vite.config.js under build.rollupOptions.input and render the matching entry in each layout. This mirrors per-layout @vite calls in Laravel and keeps the manifest small.
Use the bundle's asset helper for anything Vite-processed. Static files that never go through Vite (favicons, uploaded media) should stay on Symfony's native asset() function. Mixing the two helper families on the same file is a common source of double-hashed URLs.
CI ordering matters. Put npm ci && npm run build before composer install --no-dev in your pipeline, and ensure public/build is a build artifact, not a committed directory. This is the same discipline as a Laravel deploy, but Symfony's cache warmup runs later and will happily bake a stale manifest path into the container if the build happens after cache:warmup.
Integration tip: share config through env vars. Vite's define block and Symfony's .env should both read from the same values (API base URL, feature flags) so client and server agree. Do not hardcode the dev server port in two places.
composer.json. Do not let ^ float it across a Symfony minor upgrade — a bundle this small has no compatibility matrix to protect you.debug:config for the bundle is your friend.:5173 while Symfony serves on :8000. You need server.cors configured in vite.config.js or the module scripts will be blocked — Laravel's plugin hides this from you, this bundle likely does not.bin/console cache:clear after editing webforge_vite.yaml. Twig caches compiled templates aggressively in prod, so a config change can appear to have no effect.asset() supports a base path / CDN prefix; confirm whether the bundle's helpers respect it, or whether you need to prefix URLs yourself. In Laravel this is transparent; here it may not be.@viteReactRefresh. If you are coming from Laravel with Inertia + React SSR, assume those helpers do not exist. Check the Twig extension's public methods for the actual surface area before designing around them.services.yaml rather than forking the bundle.json_pp public/build/.vite/manifest.json and compare the key the helper requests against the keys present. Nine times out of ten the entry name differs by a directory prefix (resources/js/app.js vs app.js).asset() remains available, you can always bypass the bundle for a single stubborn file. Keep that escape hatch small and documented — a template half-rendered by two systems is worse than either one alone.How can I help you explore Laravel packages today?