Request: Support For JSS-in-CSS in Server-Rendered Components
See original GitHub issueJSS-in-CSS libraries are becoming more and more popular (e.g. styled-components with 18,000 stars at the moment). These libraries work by dynamically generating styles from within components and attaching these styles to the page via a dynamically generated (and updated) <style>
tag. This works great out of the box for non-server-rendered components, however for server-rendered components this poses a problem, because in addition to the rendered HTML, the rendered styles also need to be attached to the page. Currently react-rails offers no API for this, and assumes that a component will return only its own rendered HTML from react_component()
.
There is a workaround of sorts as outline by @bakunyo in #864 which involves returning the rendered styles inside a <style>
tag alongside the component’s HTML, then dynamically moving the <style>
tag to the document <head>
before the component is hydrated (which would otherwise result in the unexpected styles being discarded). For obvious reasons this is a very hacky fix and far from ideal.
It seems to me that some kind of additional API needs to exist to allow a component to render a <style>
tag to the <head>
of the document. Given that ReactRailsUJS.serverRender
currently returns a string, could it also support returning an Array containing the component string as the first value and the styles as the second? If this second argument is present it could be rendered to the <head>
via a helper.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:14
- Comments:8 (2 by maintainers)
Top GitHub Comments
Here’s another experimental solution. It does not require creating custom helpers, or parsing strings. You just add an initializer into your rails app, which changes react-rails config. However it does use subclassing to provide modified classes to the configuration. Should work with both controller and view rendering. Feel free to use this as a basis for an official solution, or let me know if this is flawed somehow, would be super helpful. 👍
I’ve created a new helper based on @bakunyo’s workaround that makes the usage a little more DRY:
Then you can just call this in the ERB like this:
I would say that it would probably be better to extend
react_component
to include an option similar toprerender: true
likestyle_block: :head
which would invoke thecontent_for
when present.With this, I think the only missing piece is somehow ensuring that ExecJS can return an array of strings, or a Ruby object that can be parsed for a
body
andstyle
portion, with similar respective support forReactRailsUJS.serverRender
to allow us to return the DOM body and styles in a separated manner. That way, we can skip theslice!
which is the only thing that seems hacky to me.My ExecJS experience is limited (as much as my time) but I can try and make a PR for this later this summer if the approach above looks good.