nodejs-php-fallback/react
React bindings for nodejs-php-fallback, offering a lightweight bridge between PHP applications and Node.js for rendering React components. Useful for Laravel/PHP projects that need server-side React output with a simple setup and minimal dependencies.
Install the wrapper (it pulls in the nodejs-php-fallback core, which in turn shells out to Node and npm on demand):
composer require nodejs-php-fallback/react
Before writing any application code, confirm two things:
vendor/nodejs-php-fallback/react/src/React.php first. The class is tiny (the whole package is a thin configuration of the base NodejsPhpFallback runner plus a babel-plugin-transform-react-jsx invocation and a PHP-side transformer). Its public surface — typically a transform()/compile() method plus inherited mode toggles (auto, node, php) — is the entire API. Ten minutes here saves you from guessing.PATH, not just your interactive shell). The base library auto-installs its npm dependencies into a working directory on first call, which means the first invocation needs network access and a writable directory.The first use case to validate is a smoke test that transforms a trivial component and prints the JS:
use NodejsPhpFallback\React;
$react = new React();
echo $react->transform('<Greeting name="Ada" />');
// React.createElement(Greeting, { name: "Ada" });
If that returns React.createElement(...), you have the node path working. Then force the fallback ($react->setMode('php') or the equivalent on the base class) and run the same snippet — this is the single most important test you can write, because it tells you immediately how far the PHP transformer can be trusted in your codebase.
Note what the package does not do: it transforms JSX to React.createElement calls. It does not execute React, and it does not produce HTML. Server-side rendering still requires a Node/ReactDOMServer step you own.
Treat it as a build step, not a request-time service. The realistic day-to-day pattern is an Artisan command or deploy hook that walks a source directory, transforms each file, and writes the result:
// app/Console/Commands/CompileJsx.php
foreach (File::allFiles(resource_path('js/components')) as $file) {
$out = $react->transform($file->getContents());
File::put(public_path('js/'.basename($file->getFilename(), '.jsx').'.js'), $out);
}
This is where the package earns its keep: no webpack/node toolchain in your deploy image, no package.json to maintain, just Composer.
Cache aggressively and key on content hash. Every call into the Node path spawns a process (hundreds of milliseconds); batch a directory in one command rather than transforming per request. For anything runtime-ish, memoize:
$key = 'jsx:'.md5($jsx);
return Cache::rememberForever($key, fn () => $react->transform($jsx));
Run both engines in CI. The only way to trust the PHP fallback is to diff its output against Babel's for your actual component corpus. A test that transforms every fixture in both modes and asserts equivalence — or at minimum asserts the PHP output still evaluates — catches the divergence before production does.
Pin the mode explicitly per environment. auto is convenient locally but non-deterministic in CI and containers. Set node in build environments (fail loudly if Node is missing) and php only where you've verified the subset of JSX used is within the fallback's capabilities.
Laravel wiring: bind a singleton React instance in a service provider so the resolved mode is configured once; expose compilation as php artisan jsx:compile and call it from your deploy script. If you're on a queue-driven CMS that stores JSX snippets, dispatch a job per snippet and write to the cache — never compile synchronously inside a request.
Pair with nodejs-php-fallback/babel if you also need plain ES transform; they share the base runner and the same Node installation, so the marginal cost is small.
execs Node with your input. Only ever feed it JSX from your own repository. Passing user-authored snippets through it is remote code execution waiting to happen.<>...</>), spread attributes, class properties, source maps, or anything Babel presets would downlevel. If your components use modern syntax, the fallback will silently produce broken JS — which is why the dual-engine CI test matters.HOME the PHP user can't write will all fail here. Warm the node_modules directory as a cached CI artifact and bake it into the image.PATH resolution for node/npm are the most common source of "works on my machine" failures with this family of packages.How can I help you explore Laravel packages today?