julien-lin/react-bundle-symfony

Bundle Symfony pour intΓ©grer React avec Vite, remplaΓ§ant Stimulus

Fund package maintenance!
julien-lin

Installs: 17

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.1.1 2025-12-22 19:30 UTC

This package is auto-updated.

Last update: 2025-12-22 19:30: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. TypeScript Support
  4. Advanced Usage
  5. Production Deployment
  6. Configuration
  7. API Reference
  8. Performance & Monitoring
  9. Security
  10. Troubleshooting
  11. 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.

TypeScript Support

ReactBundleSymfony supports TypeScript out of the box. You can write your React components in TypeScript (.tsx files) for full type safety.

Quick Setup

  1. Install TypeScript:
npm install --save-dev typescript @types/react @types/react-dom
  1. Create tsconfig.json:
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "jsx": "react-jsx",
    "strict": true,
    "moduleResolution": "bundler",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./assets/React/*"]
    }
  },
  "include": ["assets"]
}
  1. Rename files to .tsx:
  • assets/js/app.jsx β†’ assets/js/app.tsx
  • assets/React/Components/*.jsx β†’ assets/React/Components/*.tsx
  1. Use TypeScript in components:
// assets/React/Components/WeatherCard.tsx
import React from 'react';

interface WeatherCardProps {
  city: string;
  temperature: number;
  description: string;
}

const WeatherCard: React.FC<WeatherCardProps> = ({ city, temperature, description }) => {
  return (
    <div>
      <h2>{city}</h2>
      <p>{temperature}Β°C - {description}</p>
    </div>
  );
};

export default WeatherCard;

See TYPESCRIPT.md for complete TypeScript documentation.

Docker Quick Start

Get started with Docker in 5 minutes:

# 1. Install bundle
composer require julien-lin/react-bundle-symfony

# 2. Create docker-compose.yml (see QUICK_START_DOCKER.md)

# 3. Start services
docker-compose up -d

# 4. Start Vite dev server
docker-compose exec node npm run dev

See QUICK_START_DOCKER.md for complete Docker guide.

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

ReactBundleSymfony is designed as a modern replacement for Stimulus in Symfony applications.

Quick migration:

  1. Install ReactBundle: composer require julien-lin/react-bundle-symfony
  2. Convert Stimulus controllers to React components
  3. Replace data-controller="..." with {{ react_component(...) }}

See MIGRATION_STIMULUS.md for complete migration guide with examples.

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