Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

React Bundle Laravel Package

limenius/react-bundle

Symfony bundle for rendering React components, with optional server-side rendering via Node or V8Js. It integrates React with Twig and Symfony's asset system, adds a Twig render function, and supports hot module replacement during development for a smooth frontend workflow.

View on GitHub
Deep Wiki
Context7

Getting Started

First, calibrate expectations: limenius/react-bundle is a Symfony bundle, not a Laravel package. v5.1.0 adds Symfony 6 compatibility, which makes it viable on a modern PHP 8.1+ Symfony stack — but it still ships no service provider, facade, Blade directive, or config/*.php. composer require limenius/react-bundle inside a Laravel app will pull Symfony components that Laravel already provides under different contracts, and nothing will auto-register. A Laravel developer therefore has two realistic on-ramps:

  1. You are actually working in a Symfony app (legacy service, acquired codebase, or a small SSR microservice you own). Then: composer require limenius/react-bundle, register Limenius\ReactBundle\LimeniusReactBundle in config/bundles.php, add a config/packages/limenius_react.yaml with default_rendering: client_side to start, run php bin/console assets:install, and use {{ react_component('Hello', {props: {name: 'world'}}) }} in a Twig template. Load the bundle's react_ujs-style client script (or your own mount script) to hydrate data-react-class / data-react-props wrapper divs.
  2. You are in Laravel and want the capability, not the package. Port the architecture, not the code: a long-lived Node renderer process exposing POST /render {component, props}, a Laravel ReactRenderService calling it, and a Blade component that emits the same data-react-class/data-react-props wrapper plus a small Vite-mounted hydrate script. Or run the Symfony app as an SSR-only sidecar and call it from Laravel.

Where to look first in the repo: Twig/ReactExtension.php for the react_component signature and options, Renderer/ReactRenderer.php for the transport (external Node server vs. php_exec_js/v8js), DependencyInjection/Configuration.php for the real config keys, and Resources/public/js/react_ujs.js for the client-side mount contract. The README is the fastest path to a working Twig example.

The first useful use case is an SEO/first-paint-critical island: SSR a product card, comment thread, or search widget into an otherwise server-rendered page, then hydrate on the client. Start with client_side, flip individual components to both once the Node renderer is healthy.

Implementation Patterns

  • Global default plus per-call override. Set default_rendering: client_side so the Node dependency is not on the hot path, then opt into server rendering per component via the options argument to react_component (rendering: 'both' / 'server_side'). Treat SSR as a deliberate cost, not a default.
  • Use the rendering object when you need the pieces. react_component returns an object whose getContent() (markup) and getProps() (serialized props) you can consume separately — useful for embedding JSON in a <script> tag for large payloads or for wrapping markup in your own layout.
  • External renderer pool, not per-request spawn. Run 1–N Node processes (pm2/systemd/Supervisor) and list them as the renderer servers; the bundle load-balances across them. This is the only mode that survives production traffic. Keep php_exec_js/v8js for local experiments only — it needs the PECL v8js extension and a Node API subset that will bite you.
  • Cache SSR markup, but key it honestly. Enable the bundle cache for anonymous, deterministic props. Disable or bypass it for anything user-scoped. A cached SSR fragment rendered with another user's props is a data leak, not a perf win.
  • Props are a JSON contract. Pass scalars, arrays, and plain objects only — never Eloquent models, closures, or resources. Normalize with API Resources/transformers on the Laravel side, convert dates to ISO strings, and keep payloads small (the props end up in an HTML attribute).
  • Laravel bridge pattern. A ReactRenderService using Http::timeout(2)->post($rendererUrl, [...]) with a circuit breaker and a fallback to client-only markup; a Blade component <x-react component="ProductCard" :props="$props" :ssr="true" /> emitting the wrapper div; a Vite entry that reads the data attributes and calls createRoot(...).render() or hydrateRoot. This mirrors exactly what the bundle's Twig extension + react_ujs do.
  • Islands, not SPA. Use this only for embedded components in server-rendered pages. If the whole page is React, use Inertia or a separate SPA; the SSR bundle adds little there.
  • Keep the renderer and browser builds in lockstep. Same React version, same component bundle hash. Version your renderer endpoint (/render/v3) and restart the Node pool on deploy so stale SSR bundles never serve old markup.
  • Testing. Mock the renderer HTTP client in PHPUnit/Pest for the PHP layer; snapshot the Node renderer's HTML output separately; add one headless-browser test that checks hydration produces no mismatch warnings.

Gotchas and Tips

  • Framework mismatch is still the headline. v5.1.0 modernizes the Symfony side (Symfony 6 support, so PHP 8.1+ and current Symfony components), but there is no Laravel integration and no indication of one. Budget the bridge work yourself; don't expect php artisan vendor:publish to produce anything useful.
  • Read the release line as "narrowly maintained," not "actively developed." A single compatibility bump tells you the maintainer keeps it installable, not that the renderer, client script, or docs are being modernized. Pin the version, and check whether the shipped react_ujs-style script knows about createRoot/hydrateRoot — if not, write your own mount file rather than patching vendor code.
  • Symfony 6 is the ceiling named in the notes. If you're on Symfony 7, assume untested/unsupported until a release says otherwise — which reinforces running it as a pinned sidecar rather than something you upgrade in lockstep with a host app.
  • SSR has no browser. window, document, localStorage, matchMedia, and layout measurements don't exist server-side. Guard them behind useEffect or typeof window !== 'undefined'. This is the number-one runtime failure with any PHP-driven React SSR, including this one.
  • Hydration mismatches are silent until they aren't. SSR markup and the first client render must use identical props and component trees. In React 17 you get warnings and a re-render; in React 18 you can lose DOM state. Random values, Date.now(), and locale-dependent formatting are common culprits.
  • Props serialization and escaping. Props are embedded in HTML; re-implementations that forget this are an XSS vector. Very large props bloat the DOM attribute — move them to a <script type="application/json"> and pass an ID instead.
  • Renderer errors can degrade silently. Depending on the rendering mode, a dead Node process yields empty markup rather than an exception. Log raw renderer responses, enable the bundle's trace option for server-side stack traces, and alert on empty-content responses in production.
  • Process and connection hygiene. Long-lived Node pools need health checks, request timeouts, and restarts on deploy. Under Laravel Octane your PHP workers are long-lived too — make sure the HTTP client, timeouts, and circuit breaker are Octane-safe and don't hold per-request state.
  • The replaceable renderer service is the extension point. If you're bridging from Laravel or swapping transport to a Unix socket/queue, implement the renderer interface rather than editing the bundle. The Twig extension is where you'd add helper functions; the config tree tells you which knobs are actually supported.
  • The real takeaway for a Laravel team: copy the design (config-driven rendering mode, renderer abstraction, per-component SSR opt-in, cache keyed on props), not the Symfony wiring. That's a day or two of work versus fighting a dormant bundle across framework boundaries.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console