julien-lin / react-bundle-symfony
Bundle Symfony pour intΓ©grer React avec Vite, remplaΓ§ant Stimulus
Fund package maintenance!
julien-lin
Installs: 13
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/julien-lin/react-bundle-symfony
Requires
- php: >=8.2
- symfony/console: ^6.0|^7.0
- symfony/framework-bundle: ^6.0|^7.0
- symfony/process: ^6.0|^7.0
- symfony/twig-bundle: ^6.0|^7.0
- symfony/yaml: ^8.0
- twig/twig: ^3.0|^4.0
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/php-code-coverage: ^12.5
- phpunit/phpunit: ^12.5
- squizlabs/php_codesniffer: ^4.0
README
Enterprise-grade Symfony bundle for seamless React + Vite integration
A lightweight, secure, and high-performance bundle that brings modern React development to Symfony, replacing Stimulus with production-ready components.
Languages: π¬π§ English | π«π· FranΓ§ais
π Why ReactBundle v2.0?
β
Production-Ready - 152 tests, 88% coverage, 100% security hardening
β
Performance Monitored - Built-in metrics, logging, and observability
β
Enterprise Security - XSS protection, command injection prevention, SSRF validation
β
Zero Configuration - Works out of the box with Symfony Flex
β
Modern Tooling - Vite-powered HMR for blazing-fast development
β
Highly Testable - Comprehensive test suite with edge case coverage
π Support the project
If this bundle saves you time, consider becoming a sponsor to support ongoing development and maintenance of this open-source project.
β‘ Quick Start (5 minutes)
1. Install via Composer
composer require julien-lin/react-bundle-symfony
Composer automatically installs npm dependencies via Symfony Flex.
2. Create React folder structure
mkdir -p assets/React/Components touch assets/React/index.js
3. Configure assets/React/index.js
// Export all your React components here // export { default as MyComponent } from './Components/MyComponent';
4. Configure assets/js/app.jsx
import React from 'react'; import { createRoot } from 'react-dom/client'; import * as ReactComponents from '../React'; // Auto-mount React components by data attribute document.querySelectorAll('[data-react-component]').forEach(element => { const componentName = element.dataset.reactComponent; const props = JSON.parse(element.dataset.props || '{}'); const Component = ReactComponents[componentName]; if (Component) { createRoot(element).render(<Component {...props} />); } });
5. Use in Twig templates
{% extends 'base.html.twig' %}
{% block content %}
{{ react_component('YourComponent', {
title: 'Hello React',
message: 'Welcome to production-ready React in Symfony'
}) }}
{% endblock %}
{% block javascripts %}
{{ vite_entry_script_tags('app') }}
{% endblock %}
6. Build and run
# Development (with HMR) php bin/console react:build --dev # Production php bin/console react:build --prod
β Done! Your React component is live.
π Table of Contents
- Installation
- Core Features
- Advanced Usage
- Production Deployment
- Configuration
- API Reference
- Performance & Monitoring
- Security
- Troubleshooting
- Contributing
π¦ Installation
Via Composer
composer require julien-lin/react-bundle-symfony
The Composer installation script will automatically install npm dependencies.
Configuration
-
The bundle registers automatically via Symfony Flex.
-
Configure the bundle in
config/packages/react.yaml:
react: build_dir: 'build' assets_dir: 'assets'
- If npm dependencies were not automatically installed:
cd vendor/julien-lin/react-bundle-symfony
npm install
- Create the file structure in your Symfony project (if it doesn't already exist):
# Create the folder for your React components mkdir -p assets/React/Components # Create the index.js file to export your components touch assets/React/index.js
- Configure
assets/React/index.js(entry point for your components):
/** * Entry point for all React components in the project * Export all your components created in React/Components/ here */ // Example: // export { default as MyComponent } from './Components/MyComponent'; // Add your exports here as you go
- Configure
assets/js/app.jsx(must import from../React):
import React from 'react'; import { createRoot } from 'react-dom/client'; // Import all your components from the index import * as ReactComponents from '../React'; // ... rest of the code (usually already configured)
Usage
Prerequisites: File Structure
Before using the bundle, make sure you have the following structure in your Symfony project:
assets/
βββ React/
β βββ Components/ # Create your components here
β βββ index.js # Export your components here
βββ js/
βββ app.jsx # Entry point (already configured)
In your Twig templates
{% extends '@React/react_base.html.twig' %}
{% block body %}
{# Use react_component with the exact name of your component #}
{{ react_component('MyComponent', {
title: 'My title',
message: 'My message',
count: 42,
items: ['item1', 'item2']
}) }}
{% endblock %}
{% block javascripts %}
{{ vite_entry_script_tags('app') }}
{% endblock %}
Important: The component name in react_component() must match exactly the name used in the export of assets/React/index.js.
Build assets
Development with HMR
php bin/console react:build --dev
Production
php bin/console react:build
Bundle structure
ReactBundle/
βββ src/
β βββ ReactBundle.php # Main class
β βββ DependencyInjection/ # Configuration
β βββ Service/ # Services
β βββ Twig/ # Twig extensions
β βββ Command/ # Symfony commands
β βββ Composer/ # Composer scripts
βββ Resources/
β βββ config/
β β βββ services.yaml
β βββ views/ # Twig templates
βββ composer.json
βββ package.json
βββ vite.config.js
Recommended structure in your Symfony project
Create your React components in your Symfony project, not in the bundle:
your-symfony-project/
βββ assets/
β βββ React/
β β βββ Components/ # Your React components here
β β β βββ MyComponent.jsx
β β β βββ Navbar.jsx
β β β βββ ...
β β βββ index.js # Centralized export of all components
β βββ js/
β βββ app.jsx # Entry point (imports from React/)
βββ public/
β βββ build/ # Assets compiled by Vite
βββ config/
βββ packages/
βββ react.yaml # Bundle configuration
Create a new React component
Quick workflow
1. Create the file β assets/React/Components/MyComponent.jsx
2. Export in index.js β assets/React/index.js
3. Rebuild assets β php bin/console react:build
4. Use in Twig β {{ react_component('MyComponent', {...}) }}
Step 1: Create the component file
Create your component in assets/React/Components/YourComponent.jsx:
import React from 'react'; const YourComponent = ({ title, message, onAction }) => { return ( <div style={{ padding: '20px', border: '1px solid #ccc' }}> <h2>{title}</h2> <p>{message}</p> {onAction && ( <button onClick={onAction}>Action</button> )} </div> ); }; export default YourComponent;
Step 2: Export the component in index.js
Add the export in assets/React/index.js:
// ... other existing exports // Your new component export { default as YourComponent } from './Components/YourComponent';
Important: The name used in the export (YourComponent) must match exactly the name you will use in Twig.
Step 3: Use the component in a Twig template
In your Twig template:
{% extends '@React/react_base.html.twig' %}
{% block body %}
{# Use the exact export name #}
{{ react_component('YourComponent', {
title: 'My title',
message: 'My personalized message'
}) }}
{% endblock %}
{% block javascripts %}
{{ vite_entry_script_tags('app') }}
{% endblock %}
Step 4: Rebuild assets
After creating or modifying a component:
# In development (with HMR) php bin/console react:build --dev # In production php bin/console react:build
Complete example
1. Create assets/React/Components/ProductCard.jsx
import React from 'react'; const ProductCard = ({ name, price, image, onAddToCart }) => { return ( <div style={{ border: '1px solid #ddd', borderRadius: '8px', padding: '20px', textAlign: 'center' }}> <img src={image} alt={name} style={{ width: '100%', borderRadius: '4px', marginBottom: '10px' }} /> <h3>{name}</h3> <p style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#ff6b6b' }}> ${price} </p> <button onClick={onAddToCart} style={{ padding: '10px 20px', backgroundColor: '#ff6b6b', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > Add to cart </button> </div> ); }; export default ProductCard;
2. Export in assets/React/index.js
// ... other exports export { default as ProductCard } from './Components/ProductCard';
3. Use in Twig
{% extends '@React/react_base.html.twig' %}
{% block body %}
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;">
{% for product in products %}
{{ react_component('ProductCard', {
name: product.name,
price: product.price,
image: product.image,
onAddToCart: '() => alert("Added to cart!")'
}) }}
{% endfor %}
</div>
{% endblock %}
{% block javascripts %}
{{ vite_entry_script_tags('app') }}
{% endblock %}
Important notes
- β
Create your components in
assets/React/Components/(in your project, not in the bundle) - β
Export them in
assets/React/index.jswith the exact name you will use in Twig - β
Name is case-sensitive:
ProductCardβproductcardβProductcard - β Props are passed as JSON: use simple types (string, number, boolean, array, object)
- β
JavaScript functions can be passed as strings (e.g.,
'() => alert("test")') - β
Rebuild after each modification:
php bin/console react:build(or--devfor HMR)
Migration from Stimulus
- Identify your Stimulus controllers
- Create equivalent React components
- Replace
data-controller="..."with{{ react_component(...) }} - Test individually
Advanced configuration
Customize Vite server
In config/packages/react.yaml:
react: build_dir: 'build' assets_dir: 'assets'
Environment variables
You can define VITE_SERVER_URL in your .env to customize the Vite server URL in development:
VITE_SERVER_URL=http://localhost:5173
Or in config/packages/react.yaml:
react: vite_server: 'http://localhost:5173'
Troubleshooting
Components are not displaying
- Check that
{{ vite_entry_script_tags('app') }}is present in your template - Check the browser console for JavaScript errors
- Make sure assets are compiled:
php bin/console react:build - Check that manifest.json exists in
public/build/.vite/
"Component not found" error
- Check that the component is exported in
assets/React/index.jsof your Symfony project - Check that the name in the export matches exactly the name used in Twig (case-sensitive)
- Check that the component file exists in
assets/React/Components/ - Check that you have rebuilt the assets:
php bin/console react:build - Check the browser console to see the list of available components
HMR is not working
- Check that the Vite server is started:
php bin/console react:build --dev - Check that port 3000 (or the configured one) is not in use
- Check the configuration in
vite.config.js - Check that
VITE_SERVER_URLis correctly configured
npm/Node.js errors
- Check that Node.js >= 18.0.0 is installed:
node --version - Check that npm is installed:
npm --version - If you use nvm, make sure the environment is correctly loaded
Path errors (Windows)
- The bundle now supports Windows with
DIRECTORY_SEPARATOR - If you encounter problems, check folder permissions
- Make sure paths in
vite.config.jsare correct
Adding npm Packages
To add npm packages (like react-icons, axios, etc.) to your project:
-
Install the package in your Symfony project root (not in the bundle):
npm install react-icons
-
Import and use it in your components:
import { FaGithub } from 'react-icons/fa';
-
Rebuild assets:
php bin/console react:build
π Full guide: See ADDING_NPM_PACKAGES.md for detailed instructions and examples.
Support
- Complete documentation: see
QUICKSTART.md - Installation guide: see
INSTALLATION.md - Adding npm packages: see
ADDING_NPM_PACKAGES.md - Report a bug: GitHub Issues
- Become a sponsor: GitHub Sponsors
License
MIT