React-rails: Server-side rendering is not working with sprockets-rails 3.0

Created on 16 Jan 2016  路  53Comments  路  Source: reactjs/react-rails

In sprockets-rails 3.0 Rails.application.assets is disabled when config.assets.compile=false (https://github.com/rails/sprockets-rails/pull/220).
And React::ServerRendering::SprocketsRenderer is failing on production environment at this line, with undefined method '[]' for nil:NilClass

Most helpful comment

I can confirm that I only had to add Rails.application.config.assets.precompile += %w( react-server.js components.js ) in config/initalizers/assets.rb to get server side rendering work on Heroku.

All 53 comments

OK, there is an opened pull-request https://github.com/reactjs/react-rails/pull/430/files

Could you give that branch a try? Let me know if it works for you -- it looks good to me but I'd like a second opinion before I merge it!

I need this too :( I will test your PR very soon @rmosolgo ! Thanks for your work!!

This would be super helpful!

Could you give that branch a try? Let me know if it works for you -- it looks good to me but I'd like a second opinion before I merge it!

@rmosolgo yep, it works!
Sorry, it doesn't, I forgot to enable server side rendering.

It fails at this line https://github.com/reactjs/react-rails/pull/430/files#diff-543f6fa05678c006b8d4baa5cd4b517cR13, not being able to find react-server.js (even if react-server was added to the config.assets.precompile and being precompiled)

+1

+1

Could you try react-rails 1.6.0? It includes #430 which was my first try at fixing this

I can confirm that I have this issue in production with 1.6.0 when server-side rendering is used.

ActionView::Template::Error (No compiled asset for react-server.js, was it precompiled?):

Ok, thanks, let me try to track that down!

Ohh strange. When it creates the manifest, the manifest has production/react-server instead of react-server. Then, SprocketsRenderer fails to find react-server since it has a different logical path.

I found a workaround:

  1. Add a JS file, server_rendering.js
  2. Make sure server_rendering.js is compiled (Rails.application.config.assets.precompile += %w( server_rendering.js ))
  3. Add to server_rendering.js:

js //= require react-server //= require components // Require everything needed for server rendering

  1. Specify _only_ server_rendering.js for server rendering:

ruby config.react.server_renderer_options = { files: ["server_rendering.js"], # files to load for prerendering }

This way, it bundles react-server into server_rendering.js, it doesn't look it up when you try to render a page!

I'll look for a proper fix tonight or tomorrow!

We didn't want the react-server code to end up in the components.js since that's delivered to browser clients. So we created a components-server.js file containing:

//= require react-server

And then added that components-server.js file to the server_rendering_options:

config.react.server_renderer_options = {
    files: ["components-server.js", "components.js"], # files to load for prerendering
  }

This seemed to fix the prerendering asset location error above. However, we then were getting an error because of an additional sprockets 3 incompatibility. PR for that is here https://github.com/reactjs/react-rails/pull/478

It seems that #471 fixes this issue. The only thing that needs to be done is to add server_rendering.js to the Rails.application.config.assets.precompile list.

Maybe i should add that to rails generate react:install, but add --skip-server-rendering if you don't want the JS manifest & initializer

Sounds good)

i'm using gem 'react-rails', "~> 1.6.0" but am still encountering the above error. eg:

http://cl.ly/1m2y3B1N3f1j

any ideas?

This patch isn't merged yet because it'll be a breaking change.

Did you try the workaround described here? https://github.com/reactjs/react-rails/issues/443#issuecomment-180544359

Updates: ok ive tried the above workaround but it doesnt seem to work. I've also tried some workaround on my own, ie: http://cl.ly/2c3O3s343Y3k but to no avail too.

I've also upgraded to gem 1.6.1

doesnt seem to work

Can you elaborate? For example, did you get an error? What was the message & stack trace?

Also, did you restart your development server after changing the configurations?

The workaround didn't help me either.

2016-03-03T19:42:59.810190+00:00 app[web.1]: Completed 500 Internal Server Error in 13ms (ActiveRecord: 0.6ms)
2016-03-03T19:42:59.812302+00:00 app[web.1]:
2016-03-03T19:42:59.812312+00:00 app[web.1]: ActionView::Template::Error (No compiled asset for react-server.js, was it precompiled?):
2016-03-03T19:42:59.812313+00:00 app[web.1]:     33:   %fieldset.form__fieldset
2016-03-03T19:42:59.812314+00:00 app[web.1]:     34:     %legend.form__legend
2016-03-03T19:42:59.812314+00:00 app[web.1]:     35:       Releases
2016-03-03T19:42:59.812316+00:00 app[web.1]:     36:     = react_component 'MultiFieldForm', {parent: 'system', component: 'Release', fields: @system.releases.to_json}, { prerender: true }

Weird! It shouldn't even be looking for react-server anymore since we override that value with

  config.react.server_renderer_options = {
    files: ["server_rendering.js"], # files to load for prerendering
  }

:crying_cat_face:

(Usually, it's the default provided here: https://github.com/reactjs/react-rails/blob/master/lib/react/server_rendering/sprockets_renderer.rb#L18)

just to be clear: I put the config.react.server_renderer_options in my application.rb

i'm getting this as well with

rails 4.2.6
ruby 2.2.3p173
sprockets 3.5.2
ActionView::Template::Error (No compiled asset for react-server.js, was it precompiled?):
    2: .card-login-container
    3:   .card.card-login
    4:     = react_component('LoginForm', { login_url: create_session_path }, { prerender: true })
  app/views/sessions/new.html.haml:4:in `_app_views_sessions_new_html_haml___2128502748164763252_70237860093020'

@brettjurgens could you share your file setup? That is, which files do you pass to config.react.server_renderer_options & what do they //= require?

@rmosolgo my bad it works, ignore me :smile:

Same here. Here's the Heroku log:

ActionView::Template::Error (No compiled asset for react-server.js, was it precompiled?):
     4: %p
     5:   The time is now: #{Time.now}
     6:
     7: = react_component('HelloFromReact', {name: 'RAP'}, {prerender: true})
  app/views/dashboard/index.html.haml:7:in `_app_views_dashboard_index_html_haml___3362025122456778176_70295050466140'

Heroku's running on:

ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
Rails 4.2.6
gem 'react-rails', '~> 1.6'

+1
I'm also get the same problem

ActionView::Template::Error (No compiled asset for react-server.js, was it precompiled?):
    1: = react_component('Products', {}, { prerender: true })
  app/views/products/index.html.haml:1:
in `_app_views_products_index_html_haml__2224966273559460328_68268360'

gem 'react-rails', '~> 1.6', '>= 1.6.2'

Just to follow up on this after a month or so, ive updated to the latest version,

gem 'react-rails', '~>1.7.1'

and followed @rmosolgo advice of creating the server_rendering.js work around, and it works! No more "no compiled asset for react-server.js" error.

Confirming that the workaround works with 1.7.1.

I tried to get a component that uses moment.js in its getInitialState() to pre-render once I set this up and also added //= require moment to server_rendering.js, but I still got an error:

Encountered error "ReferenceError: moment is not defined" when prerendering Calendar

Anything else I need to do to get that to work?

hmm did u put //= require moment above your component definition? some code samples might be useful

Does server_rendering.js go in /assets/javascripts/server_rendering.js?

We're getting...

ActionView::Template::Error: No compiled asset for server_rendering.js, was it precompiled?
No compiled asset for components.js, was it precompiled?

@krazyjakee did you add server_rendering.js into the asset precompile list?

@alcedo yes, it is definitely there.

@krazyjakee

my server_rendering.js goes into /assets/javascripts/server_rendering.js

and this is the content of it, if its of any help.

//= require react
//= require react-server
//= require react_bootstrap
//= require components

@alcedo mine was...

//= require react-server
//= require react_ujs
//= require components

I'll tweak it and get back to you. Thanks!

no problem. and i think you probably wont need react_ujs, since its only used on client side.

Did the workaround!

But now I get the same error with server_rendering.js

RuntimeError (No compiled asset for server_rendering.js, was it precompiled?):

Rails 4.2.6
ruby 2.3.1p112
sprockets 3.6.2
react-rails 1.8.0

To confirm, did you add server_rendering.js to your list of precompiled assets, something like

Rails.application.config.assets.precompile += %w(server_rendering.js)

?

Yes! Did all the steps you provided!
It's strange because it works in development mode and worked in production until some days ago. And it seems a lot of people is having the same issue. Perhaps any conflict with other dependency gems?

I'm still trying to find out!

until some days ago

woah, how strange?! did anything else change in your app at that time?

I'm trying to figure out! Looking through the commits, updated some code and added only a few gems, but nothing related to React itself.
Added pundit gem and pointed another one (validates_cpf_cnpj) to a Github fork repo.

But I don't believe these changes are related with this rendering issue.

@rafaelv90 I'm experiencing the same thing, worked fine in production, still works in dev but today stopped working in production.

stopped working in production

was it after a redeploy? or, it just started :boom:ing while running?

@rmosolgo after redeploy. I have 2 production servers, one I use as staging. When I pushed up to staging it broke today. When I push the existing working production server code to staging (an exact production replica) it starts throwing the "was it precompiled" error.

Is the diff for that redeploy small enough to list the changes? For example:

  • Any gem updates?
  • Ruby version update?
  • Application code update?
  • Application configuration update?
  • Server administration changes?

@rmosolgo The production code mirrored on staging worked, my mistake was viewing the log, it was a process of the prior build, learned something new about EY.

I also found that when deploying on EngineYard the assets won't re-precomplie if the assets.rb is changed, only if the assets .js/.css are changed, or its in the EY config to always precomplie.

Solution that worked for me
Adding the assets to the precomplie, then touching the .js asset allowed it to precomplie and work.
Rails.application.config.assets.precompile += %w( react-server.js components.js )

Unfortunately I was not able to locate the differences that suddenly required the react-server.js components.js to be listed in the precomplie, I did check the gemlock files of both codebases and they are identical.

Thanks for sharing your findings!!

I can confirm that I only had to add Rails.application.config.assets.precompile += %w( react-server.js components.js ) in config/initalizers/assets.rb to get server side rendering work on Heroku.

Guys, in my scenario I use separated manifest files for loading dependencies and react components for main interface and admin interface.

My files are divided as following:

application.js:

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require maskedinput
//= require jquery.fancybox
//= require getstream
//= require react
//= require react_ujs
//= require react-rails-hot-loader
//= require components

server_rendering_components.js:

//= require react
//= require react-server
//= require components

components.js:

//= require accounting.min
//= require moment-with-locales.min
//= require autosuggest
//= require_tree ./react

moment.locale('pt-br');

admin.js:

//= require react
//= require react_ujs
//= require react-rails-hot-loader
//= require admin_components

server_rendering_admin_components.js:

//= require react
//= require react-server
//= require admin_components

admin_components.js:

//= require_tree ./admin-react

config/environments/{development.rb,production.rb}"

config.react.server_renderer_options = {
    files: ['server_rendering_components.js, server_rendering_admin_components.js']
  }

config/initializers/assets.rb:

Rails.application.config.assets.precompile += %w( admin.js admin.css server_rendering_components.js components.js server_rendering_admin_components.js admin_components.js )

I just keep getting this error:

React::ServerRendering::PrerenderError - Encountered error "ReferenceError: ReactDOMServer is not defined" when prerendering _ComponentName_

What I'm doing wrong?

Nevermind guys, I just fix the files object to correction:

Instead of:

config.react.server_renderer_options = {
    files: ['server_rendering_components.js, server_rendering_admin_components.js']
 }

Corrected for this:

config.react.server_renderer_options = {
    files: ['server_rendering_components.js', 'server_rendering_admin_components.js']
 }

Sounds like we have a couple of options here. Soon I'll merge #471 and remove the confusing defaults. Thanks for sharing your solutions!

Was this page helpful?
0 / 5 - 0 ratings