fabricity / vite-bundle
A lightweight Symfony bundle that provides seamless Vite integration with automatic dev-server detection, manifest handling, and simple Twig helpers for loading compiled assets.
Package info
github.com/fabricity/vite-bundle
Type:symfony-bundle
pkg:composer/fabricity/vite-bundle
Requires
- php: >=8.4
- symfony/asset: ^6.4 || ^7.4 || ^8.0
- symfony/config: ^6.4 || ^7.4 || ^8.0
- symfony/dependency-injection: ^6.4 || ^7.4 || ^8.0
- symfony/framework-bundle: ^6.4 || ^7.4 || ^8.0
- symfony/http-client: ^6.4 || ^7.4 || ^8.0
- symfony/twig-bundle: ^6.4 || ^7.4 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.92
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.1
This package is auto-updated.
Last update: 2026-05-09 10:04:54 UTC
README
A lightweight Symfony bundle that integrates Vite into your Symfony application. It automatically detects the Vite dev server, reads the production manifest, and exposes simple Twig globals for loading compiled assets.
Features
- Automatic Vite dev server detection
- Production manifest (
manifest.json) parsing - Multiple independent build support (e.g.
frontend/backend) - Symfony Asset
VersionStrategyInterfaceintegration - Twig globals (
vite.dev,vite.devClient) for conditional script loading
Philosophy
This bundle resolves asset URLs through the Vite manifest and the Symfony Asset component — nothing more. It does
not auto-generate <script>, <link>, or <link rel="modulepreload"> tags for you.
This is intentional. You stay in full control of your HTML: which assets to preload, where to place scripts, whether to
add async, defer, crossorigin, or integrity attributes. The bundle gives you the correct URLs; you decide how to
load them.
Requirements
- PHP 8.4+
- Symfony 6.4, 7.4, or 8.0
Installation
composer require fabricity/vite-bundle
Register the bundle in config/bundles.php:
return [ // ... Fabricity\Bundle\ViteBundle\FabricityViteBundle::class => ['all' => true], ];
Vite Setup
Install Vite in your project:
npm install --save-dev vite
Create a vite.config.js at the root of your project:
import {defineConfig} from 'vite' export default defineConfig({ build: { manifest: true, outDir: 'public/build/frontend', rollupOptions: { input: 'assets/main.js', }, }, server: { origin: 'http://localhost:5173', }, })
Add the following scripts to your package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}
Run npm run dev during development and npm run build for production.
Configuration
Create config/packages/fabricity_vite.yaml:
fabricity_vite: # Path to your public directory (default: %kernel.project_dir%/public) public_dir: '%kernel.project_dir%/public' # Vite dev server URL (omit in production) server: 'http://localhost:5173' # One entry per Vite build output builds: frontend: build_dir: build/frontend # manifest_path defaults to .vite/manifest.json backend: build_dir: build/backend
Each entry under builds registers a Symfony Asset version strategy service named
fabricity_vite.version_strategy.<name>.
Multiple builds
You can define as many builds as you need. This is useful when you have separate Vite configs for different parts of your application.
Twig integration
The bundle registers a Twig extension that exposes a global vite variable:
| Variable | Type | Description |
|---|---|---|
vite.dev |
bool |
true when the Vite dev server is reachable |
vite.devClient |
string|null |
URL to the Vite HMR client (/@vite/client) |
Use it in your base template to conditionally load the dev client:
{% if vite.dev %}
<script type="module" src="{{ vite.devClient }}"></script>
{% endif %}
Asset version strategy
Register the bundle's version strategy on a Symfony Asset package in config/packages/assets.yaml:
framework: assets: packages: frontend: version_strategy: 'fabricity_vite.version_strategy.frontend' backend: version_strategy: 'fabricity_vite.version_strategy.backend'
Then use the standard Symfony asset() helper in Twig:
{# In dev mode: points to http://localhost:5173/src/main.js #} {# In prod mode: resolves via manifest to /build/frontend/assets/main-abc123.js #} <script type="module" src="{{ asset('src/main.js', 'frontend') }}"></script> <link rel="stylesheet" href="{{ asset('src/main.css', 'frontend') }}">
CSS co-located with JS
When Vite bundles CSS alongside a JS entry point, you can reference the CSS file using its .css extension even though
it is listed under a .js key in the manifest:
<link rel="stylesheet" href="{{ asset('src/app.css', 'frontend') }}">
The bundle automatically resolves src/app.css → src/app.js → css[0] from the manifest.
Full example
{# templates/base.html.twig #} <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="{{ asset('src/main.css', 'frontend') }}"> </head> <body> {% block body %}{% endblock %} {% if vite.dev %} <script type="module" src="{{ vite.devClient }}"></script> {% endif %} <script type="module" src="{{ asset('src/main.js', 'frontend') }}"></script> </body> </html>
License
MIT — see LICENSE.