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

2.0.0 2025-12-07 14:19 UTC

This package is auto-updated.

Last update: 2025-12-07 14:21:19 UTC


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.

GitHub PHP Version Symfony Tests Coverage Production Ready GitHub Sponsors

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

  1. Installation
  2. Core Features
  3. Advanced Usage
  4. Production Deployment
  5. Configuration
  6. API Reference
  7. Performance & Monitoring
  8. Security
  9. Troubleshooting
  10. Contributing

πŸ“¦ Installation

Via Composer

composer require julien-lin/react-bundle-symfony

The Composer installation script will automatically install npm dependencies.

Configuration

  1. The bundle registers automatically via Symfony Flex.

  2. Configure the bundle in config/packages/react.yaml:

react:
    build_dir: 'build'
    assets_dir: 'assets'
  1. If npm dependencies were not automatically installed:
cd vendor/julien-lin/react-bundle-symfony
npm install
  1. 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
  1. 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
  1. 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.js with 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 --dev for HMR)

Migration from Stimulus

  1. Identify your Stimulus controllers
  2. Create equivalent React components
  3. Replace data-controller="..." with {{ react_component(...) }}
  4. 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.js of 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_URL is 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.js are correct

Adding npm Packages

To add npm packages (like react-icons, axios, etc.) to your project:

  1. Install the package in your Symfony project root (not in the bundle):

    npm install react-icons
  2. Import and use it in your components:

    import { FaGithub } from 'react-icons/fa';
  3. 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