limenius / reactbundle Goto Github PK
View Code? Open in Web Editor NEWClient and Server-side React.js rendering in a Symfony Bundle
License: MIT License
Client and Server-side React.js rendering in a Symfony Bundle
License: MIT License
Hi there,
Nice work! I was playing around with the bundle and it works pretty well.
I noticed the original React on Rails repo features Redux integration as well. I was wondering if you were already working on it. Otherwise, maybe I could be of any help implementing it :)
According to https://material-ui.com/guides/server-rendering/ in this bundle we are unable to generate css. Any ideas how to hack that?
Please add support for twig 2.x into composer.json
react-bundle: 5.1
symfony: 5.3.16
Installed react-bundle following the steps in the installation process - but when trying to use react_component
in Twig - the Symfony error "Unknown "react_component" function." is thrown
Basic code below.
Body in twig file
{{ react_component('TestApp' }}
app.js
``import ReactOnRails from 'react-on-rails';
import TestApp from '../src/JS/Components/Test';
ReactOnRails.register({ TestApp });``
TestApp
`const Test = () => {
console.log('Rendering Test');
return
export default Test;`
Hi! I would like to use a custom cache pool with ReactRenderExtension.
I see in the CacheCompilerPass the hardcoded line:
$appCache = $container->findDefinition('cache.app');
I would like to change the service definition and do a setCache
with my own cache pool service. Is it possible to override this in my projects service.yaml
? Something like service aliasing...?
Thanks!
An exception has been thrown during the rendering of a template ("Something went wrong evaluating JS code: result: "TypeError: Cannot read property 'replace' of undefined"")
Hi, do you had this error before? This error blocks me for two days, still don't know how to solve it, this is the only error message I got, no other information.
Maybe this is not a ReactBundle issue, but I don't know where else to ask.
Thanks.
I've dived a little bit into the code and didn't find a quick posibility to entirely disable serverside rendering. If I deploy my code to a server without V8 or node and enable only clientside-rendering PHPExecJS still needs a runtime for serverside rendering.
Is it possible to disable Serverside rendering entirely
Did I miss something? Where would you implement such thing?
Hi, i've some prb, and I was hoping you could help me :
When i use "react_component" twig function to render a component, all instruction like "debugger", "window", "document" or "onClick" in my component's doesn't work, and i've don't any idea why.
Have you some ideas about that ? Thanks in advance :)
Hello,
I'm new in react. I made an application (in analogy of your sandbox example) with server rendering. In prod environment it works as expected.
But in dev (app_dev.php) I got error.
[SERVER] stack: TypeError: Cannot set property 'params' of undefined
at exports.default (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:24201:24)
at createReactElement (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:21836:13)
at serverRenderReactComponent (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:24030:72)
at Object.serverRenderReactComponent (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:277:54)
at eval (eval at <anonymous> (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:57497:8), <anonymous>:4:23)
at eval (eval at <anonymous> (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:57497:8), <anonymous>:11:3)
at /tmp/nacmartin_phpexecjs58069148960831.10409992.js:57497:8
at /tmp/nacmartin_phpexecjs58069148960831.10409992.js:57503:14
at console.history (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:1:92)
at Object.<anonymous> (/tmp/nacmartin_phpexecjs58069148960831.10409992.js:1:110)
Also I see several warnings in console after error:
Warning: render(): Target node has markup rendered by React, but there are unrelated nodes as well. This is most commonly caused by white-space inserted around server-rendered markup.
Warning: [react-router] Location "/app_dev.php" did not match any routes
Maybe anybody can tell in which direction I should digg to fix error? Thanks.
Hi, guys.
First things first, thank you for this awesome Bundle.
Now let me explain my ideas and issues.
Right now I am working on a page that requires N react components in the same web page, in the twig part it's easy because I could call N time the react_component.
The problems I cannot produce independent jsx files, because if I call more that one time, the second call will overwrite the Register since that is how ReactOnRails.register works more information at shakacode/react_on_rails#630
So, I have to pack all components in one bundle and register all of them in one register and works.
What is the problem with this approach, well usually I have common components like the menu, notifications, etc.; and only change the primary operation like edit user, etc.
Having components separated and registered independent allow the browser cache to have those components and be reused in a further request during user navigation, increasing the performance. Now I have a cache per page, which don't reuse the elements shared in different pages.
Let me know if you understand my scenery, and if you could recommend ma way to resolve. Maybe I am missing something obvious.
Kind regards
Hello, there's a few days i'm working on this bundle and i definitively dont make it works like i want... My server side rendering is good, but the HTML generated is not recognized like it's said :
Client-side render will take the server-side rendered DOM, recognize it, and take control over it without rendering again the component until needed.
and if i choose to render only on client-side, my block is empty (where i should get my react component).
{{ react_component('RecipesAppRedux', {'rendering': 'client_side'}) }}
In a first time, i'm trying to display a button that can be incremented (with react hooks useState)
My HTML code generated with client_side only :
<div>
<script type="application/json" id="js-react-on-rails-context">
{"serverSide":false,"href":"http:\/\/www.localhost\/fr\/checkout\/customize","location":"\/fr\/checkout\/customize","scheme":"http","host":"www.localhost","port":80,"base":"","pathname":"\/fr\/checkout\/customize","search":null}
</script>
<script type="application/json" class="js-react-on-rails-component" data-component-name="RecipesAppRedux" data-dom-id="sfreact-reactRenderer5cc6f5c4ac9313.07783638">
[]
</script>
<div id="sfreact-reactRenderer5cc6f5c4ac9313.07783638">
</div>
</div>
My HTML code generated with both rendering :
<div>
<script type="application/json" id="js-react-on-rails-context">
{"serverSide":false,"href":"http:\/\/www.localhost\/fr\/checkout\/customize","location":"\/fr\/checkout\/customize","scheme":"http","host":"www.localhost","port":80,"base":"","pathname":"\/fr\/checkout\/customize","search":null}
</script>
<script type="application/json" class="js-react-on-rails-component" data-component-name="RecipesAppRedux" data-dom-id="sfreact-reactRenderer5cc6f67028c5a4.23079602">
[]
</script>
<div id="sfreact-reactRenderer5cc6f67028c5a4.23079602">
<div data-reactroot="">
<p>You clicked <!-- -->0<!-- --> times</p>
<button type="button">Click inc hook counter</button>
</div>
</div>
</div>
Do i have to do something special to deal with it ?
Ty
Right now we have to pass to the Twig tag a JSON serialized string with the props. It would be nice to be able to pass an array too.
as title say, i get an error here is the stack trace from php-fpm
[05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: "# Fatal error in ../../src/snapshot/startup-serializer.cc, line 125"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: "# Check failed: 0 == isolate->global_handles()->global_handles_count()."
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: "#"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: ""
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: "==== C stack trace ==============================="
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: ""
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8_libbase.so(v8::base::debug::StackTrace::StackTrace()+0x13) [0x7f4352a2ae53]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8_libplatform.so(+0xc87b) [0x7f4352a4787b]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8_libbase.so(V8_Fatal(char const*, int, char const*, ...)+0xdc) [0x7f4352a270ec]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8.so(+0x8e7c1a) [0x7f434859ac1a]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8.so(v8::SnapshotCreator::CreateBlob(v8::SnapshotCreator::FunctionCodeHandling)+0x77a) [0x7f4347f6a9ea]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /opt/v8/lib/libv8.so(v8::V8::CreateSnapshotDataBlob(char const*)+0x12b) [0x7f4347f6b0cb]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /usr/local/lib/php/extensions/no-debug-non-zts-20170718/v8js.so(+0xcdc7) [0x7f43487d7dc7]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(execute_ex+0x8008) [0x55cd1230f8f8]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(zend_execute+0x124) [0x55cd1230ff54]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(zend_execute_scripts+0xd3) [0x55cd1225f563]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(php_execute_script+0x2a8) [0x55cd121fab48]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(+0x14a41a) [0x55cd11ec241a]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1) [0x7f434ff9b2b1]"
php_1 | [05-Feb-2018 13:25:06] WARNING: [pool www] child 5 said into stderr: " php-fpm: pool www(_start+0x2a) [0x55cd11ec325a]"
you can saw the v8 source code who throw the error here https://github.com/v8/v8/blob/6.4.388/src/snapshot/startup-serializer.cc at line 125
note that i revert back my reactBundle version to 0.14.1 and my app now work well with v8js, but note that the react_render_array isnt present in 0.14.1 :(
i also tryed to run the symfony_react_sandbox on sf 4 who also use 2.1.0 and the same error is throw
the symfony_react_sandbox on sf 3 use ReactBundle 0.14.1 and working well
if you have a specific version of V8 for using 2.1.0 plz ignore this issue and describe it on doc ๐
note that i cant really test all v8 version as this take something like an hour to compile my V8js on my docker
In the file Resources/config/services.xml
:
<parameter key="limenius_react.context_provider.class">Limenius\ReactRenderer\Context\SymfonyContextProvider</parameter>
<parameter key="limenius_react.static_react_renderer.class">Limenius\ReactRenderer\Renderer\StaticReactRenderer</parameter>
But in composer.json
we require "limenius/react-renderer": "^3.0.0"
.
Error message:
In ReactRenderExtension.php line 35:
!!
!! Argument 2 passed to Limenius\ReactRenderer\Twig\ReactRenderExtension::__co
!! nstruct() must be an instance of Limenius\ReactRenderer\Renderer\StaticReac
!! tRenderer, instance of Limenius\ReactRenderer\Context\SymfonyContextProvide
!! r given
Hi, I'm struggling with asset versionning et SSR.
I would like to have both the cache key
and server_bundle_path
to be set accordingly to the content of the json_manifest_path
.
Here is the config/packages/framework.yaml
framework:
secret: '%env(APP_SECRET)%'
#default_locale: en
#csrf_protection: ~
#http_method_override: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
storage_id: session.storage.php_bridge
handler_id: ~
#esi: ~
#fragments: ~
php_errors:
log: true
assets:
json_manifest_path: '%kernel.project_dir%/web/dist/manifest.json'
cache:
# The app cache caches to the filesystem by default. Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
And here is the config/packages/limenius_react.yaml
limenius_react:
# Other options are "server_side" and "client_side"
#default_rendering: "both"
default_rendering: "both"
serverside_rendering:
cache:
enabled: true
# name of your app, it is the key of the cache where the snapshot will be stored.
key: "main.78de05ae.js"
# In case of error in server-side rendering, throw exception
fail_loud: false
# Replay every console.log message produced during server-side rendering
# in the JavaScript console
# Note that if enabled it will throw a (harmless) React warning
trace: false
# Mode can be `"phpexecjs"` (to execute Js from PHP using PhpExecJs),
# or `"external_server"` (to rely on an external node.js server)
# Default is `"phpexecjs"`
mode: "phpexecjs"
# Only used with mode `phpexecjs`
# Location of the server bundle, that contains React and React on Rails.
# null will default to `%kernel.root_dir%/Resources/webpack/server-bundle.js`
server_bundle_path: "%kernel.project_dir%/web/build/js/main.78de05ae.js"
# Only used with mode `external`
# Location of the unix socket to communicate with a dummy node.js server
# Such as the one in `Resources/node-server/server.js`
# null will default to `%kernel.root_dir%/Resources/node-server/node.sock
server_socket_path: null
Everytime the hash changes I have to edit the configuration. Is there a way to use the Asset Component, and Version Strategy to set both serverside_rendering.cache.key
and serverside_rendering.server_bundle_path
?
I tried to set a parameter inside the src/Kernel.php
, so I would use the values "%reactjs%"
and "%kernel.project_dir%/web/build/js/%reactjs%"
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
$container->setParameter('reactjs', 'main.78de05ae.js');
...
But so far I didn't find a way to retrieve the Version Strategy instance.
Hello; I got this message : << document.createElement is not function >>
when i try a server side rendering; so how can i get all javascript trace of this error?
react-on-rails moved away from hidden divs..
Use
<script type="application/json">
for props and store instead of hidden div #775
this bundle needs to be updated as well..
(I might be able to work on this next week if you like)
I recently saw there is a major update from 4.0 to 5.0, but I don't see any changelog for this.
Could you add a changelog file in the project ? @nacmartin
A major update means breaking changes. I can update without knowing the impact.
i have started using react-bundle with symfony...while using react_component('component_name', {'rendering':'client_side'}) it is showing the component without any issue while using server_side it is showing 504 gateway time out..i haved gone through the documentation and done the exact thing but still showing the same issue can i know how to resolve the issue.
#33 broke compatibility with default_rendering: "client_side"
configuration, as \Limenius\ReactRenderer\Twig\ReactRenderExtension::__construct()
blindly calls \Limenius\ReactRenderer\Renderer\StaticReactRenderer::setRenderer()
without checking if the renderer is null.
Everything works with server_side
or both
, or if you have a custom service defined for limenius_react.react_renderer
, but by default there is no guarantee of such a service existing.
Hello,
I am currently doing some POC with the bundle for future developments. My react my is really simple :
// main.js
import React from 'react'
import ReactOnRails from 'react-on-rails'
import DemoApp from './react/demoApp'
const DemoApp = ({foo, ...props}) => (
<h1>Hello world ! A react app ! {foo}</h1>
)
ReactOnRails.register({ DemoApp })
and my symfony view is quite simple too
{{ react_component('DemoApp', {
"props": {
"foo": "bar"
}
}) }}
<!-- main.js file built up by Encore -->
<script src="{{ asset('build/main.js') }}"></script>
This works great when the default_rendering
param is set as 'client_side'
, but when I switch it to 'client_side'
or 'both'
it throws the following exception :
An exception has been thrown during the rendering of a template ("PhpExecJs: Cannot autodetect any JavaScript runtime").
For now none of the past issue reported solved my problem.
I tried to install your Symfony React Sandbox Project on my machine, and I wasn't able to fetch vendors through composer because of my version of PHP : I am with PHP 7.0 and the vendors requires 7.1 to be installed.
Maybe your bundle require PHP version to be 7.1 ? (the project I am working on require 7.0 :( )
Thanks ;)
Hello,
I have an interest in your project for one of my own, however I'd like to work on Symfony 5, which your project is not compatible with. Are there any plans to make it compatible with it ? If so, do you have an idea as for when it will be available ?
Thanks
Currently there is no documentation or way to code split (as far as I could find) using the ReactBundle setup as shown in the tutorial.
I have tried using React Lazy as well as regular JS dynamic imports including different Webpack settings in both cases but the end result remains a single verisoned app.js file.
My theory is that the ReactOnRails.register()
function combines all components thus defeating the purpose of code splitting.
Could anyone point me in the right direction on how to approach this issue?
Is it possible or wait until react-on-rails ready react 18?
react-on-rails have moved some properties from script's textContent to its attributes in v7.0.0.
This bundle does not work with react-on-rails v7.0.0+
See #821 and shakacode/react_on_rails@251fa75#diff-2b02b66a19627ff0da5b8fed749a5742
I tried to install ReactBundle in Symfony 3.1.3 with the following command
$ composer require limenius/react-bundle:^0.9.0@dev
But twig function isn't available
$ bin/console debug:twig | grep react
Trying to move to Symfony 5.0. Symfony 4.4 gives deprecation warnings:
The "Symfony\Component\Config\Definition\Builder\TreeBuilder::root()" method called for the "limenius_react" configuration is deprecated since Symfony 4.3, pass the root name to the constructor instead.
A tree builder without a root node is deprecated since Symfony 4.2 and will not be supported anymore in 5.0.
Thank you!
Method "Symfony\Component\Config\Definition\ConfigurationInterface::getConfigTreeBuilder()" might add "TreeBuilder" as a native return type declaration in the future. Do the same in implementation "Limenius\ReactBundle\DependencyInjection\Configuration" now to avoid errors or add an explicit @return annotation to suppress this message.
Why did you choose to use a different shorthand for the default render values used in the services and the ones used when calling the twig function? Both only_serverside and server_side are used for the same thing. Same goes for only_clientside
and client_side
.
I started off doing it right but I mixed them up somewhere along the road and it took me 10 minutes to find out what was going wrong.. It might also be a good idea to throw here when none of the render methods are set to true..
i'm using your bundle since a while now, and i'm front of a problem that may will make me re-do my project without reactBundle that mean symfony for only API, node server for fetch api and render html (SSR).
Why ? simply cause there is actually no easy way to do a proper SEO for App using ReactBundle. Actually for using ReactRouter with a route Array who get, for exemple, data like Title, meta description etc ...
Server Side (php)
have to do the first SEO setup (like get locale from symfony then put in html lang="{locale}" )
For the title and desc, if someone using like me a one SF router for all (mean i set up routes in YAML config files (and think about let my manager write/read additional route from DB later) , then i redirect everything to this router as /:locale/:slug)
i have to pre-calculate wich route will be "normaly calculated for react router" to get the data from the route, then set up the title and desc or other meta from SSR.
Client Side (javascript)
in javascript side, i change the content of title or other meta with jquery if necessary (on route change, locale change etc).
with a solution like react_component_hash from react_on_rail, i would not have to pre-calculate from php wich route i should use for SEO as i would simply use the title/meta returned from javascript(serverside) with phpv8 or dummy node server. this solution would be more simplier and prevent error, as i'm not using the exact same function than react router for calculating wich route will be render from react router, that can lead to some miss-calculated route.
actually i have implemented almost function for php side from there to my router manager
https://github.com/gpolguere/path-to-regexp-php
you can see its a bit problematic, and i guess you should encounter the same problem with your own APP
so, the question is, does there is a simple way to just adding this react_component_hash ?
here is the exemple from react_on_rail https://github.com/shakacode/react_on_rails#generator-functions
for tip, i tryed before to do php pre-calculate route match, to use a little app, who use my redux store, where is stored the data from the actual route matched (javascript side) and render this little app like this in my tiwg template :
{{ redux_store('MySharedReduxStore', initialState ) }} // this store also pre-calculated the route matching via props send to it
<head>
{{ react_component(titleApp) }} // this return a <title>{title_from_redux_data}</title>
// could do the same for meta
<head>
<body>
{{ react_component(mainApp) }} // return content
</body>
but this not really working as this render the <title>routeTitle</title> in the body and put a
react_on_rail script where i would have direct html render of component and this is not the proper way to render this SEO component, same for meta or any lang tag in html
another downside too on using phpJs intead of a regular NodeJs server is that we cant Prefetch fromServerSide rendering. For resolve this prob, we have to send our data by initialProps of reduxStore, but that work only if the data required is accesible through our repository, this isnt working for fill our APP with api from other websites. Also, to know wich data should be send we have to know wich route will be render too, that lead to the same problem i encounter for SEO
thanks a lot for your work, this helped me a lot for learning react, and building a pretty cool symfony/react Project, as i'm not familiar at all with phpJs i guess i'll not helpfull for trying implement this great fonctionnality
I'm using phpexecjs together with v8js and disabling the cache of this bundle does not work.
This is my symfony 4 config for dev
limenius_react:
default_rendering: "both"
serverside_rendering:
mode: "phpexecjs"
cache:
enabled: false
For prod it's just
limenius_react:
default_rendering: "both"
serverside_rendering:
mode: "phpexecjs"
cache:
enabled: true
HTML gets heavily cached for some reason and everytime I change React components i have to delete the symfony cache (which is where this bundles caches aswell) and then it works.
I was wondering if there is any specific reason why it currently only supports a single JS as server bundle? What if I want to have two different pages that are independent? Like I could put them all into the same server bundle but that makes the JS way bigger then it needs to be and therefore I assume makes the JS parsing and execution slower (on the server).
Preferable I would like to build multiple independent server bundle js files and then select the one to use as part of the twig template call.
Exception is thrown when trying to set 'client_side' rendering.
Argument 1 passed to Limenius\ReactRenderer\Renderer\StaticReactRenderer::setRenderer() must be an instance of Limenius\ReactRenderer\Renderer\AbstractReactRenderer, null given, called in /var/www/tivent/vendor/limenius/react-renderer/src/Limenius/ReactRenderer/Twig/ReactRenderExtension.php on line 37
Config which caused error:
limenius_react:
default_rendering: "client_side"
serverside_rendering:
fail_loud: false
trace: true
mode: "phpexecjs"
server_bundle_path: "%kernel.project_dir%/var/webpack/server-bundle.js"
server_socket_path: null
Lib version: "limenius/react-bundle": "^3.0"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.