react-rails: SplitChunks and SSR: Cannot read property 'serverRender' of undefined
Steps to reproduce
- Enable SplitChunks.
- Try server-rendering a component.
Expected behavior
The component should be rendered on the page.
Actual behavior
- Rails was throwing the error:
ReferenceError: window is not defined
- I got past this by setting Webpack’s
globalObject
:environment.config.set( 'output.globalObject', "(typeof self !== 'undefined' ? self : this)" );
- I got past this by setting Webpack’s
- Now Rails is throwing the error:
#<ExecJS::ProgramError: TypeError: Cannot read property 'serverRender' of undefined>
Stack trace
Encountered error "#<ExecJS::ProgramError: TypeError: Cannot read property 'serverRender' of undefined>" when prerendering ssr/Button with {}
eval (eval at <anonymous> ((execjs):147:8), <anonymous>:6:45)
eval (eval at <anonymous> ((execjs):147:8), <anonymous>:18:13)
(execjs):147:8
(execjs):153:14
(execjs):1:102
Object.<anonymous> ((execjs):1:120)
Module._compile (internal/modules/cjs/loader.js:738:30)
Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)
Module.load (internal/modules/cjs/loader.js:630:32)
tryModuleLoad (internal/modules/cjs/loader.js:570:12)
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/execjs-2.7.0/lib/execjs/external_runtime.rb:39:in `exec'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/execjs-2.7.0/lib/execjs/external_runtime.rb:21:in `eval'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/server_rendering/exec_js_renderer.rb:39:in `render_from_parts'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/server_rendering/exec_js_renderer.rb:20:in `render'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/server_rendering/bundle_renderer.rb:40:in `render'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/server_rendering.rb:27:in `block in render'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/connection_pool-2.2.2/lib/connection_pool.rb:65:in `block (2 levels) in with'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/connection_pool-2.2.2/lib/connection_pool.rb:64:in `handle_interrupt'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/connection_pool-2.2.2/lib/connection_pool.rb:64:in `block in with'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/connection_pool-2.2.2/lib/connection_pool.rb:61:in `handle_interrupt'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/connection_pool-2.2.2/lib/connection_pool.rb:61:in `with'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/server_rendering.rb:26:in `render'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/rails/component_mount.rb:67:in `prerender_component'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/rails/component_mount.rb:34:in `block in react_component'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionview-5.1.6.1/lib/action_view/helpers/capture_helper.rb:39:in `block in capture'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionview-5.1.6.1/lib/action_view/helpers/capture_helper.rb:203:in `with_output_buffer'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionview-5.1.6.1/lib/action_view/helpers/capture_helper.rb:39:in `capture'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionview-5.1.6.1/lib/action_view/helpers/tag_helper.rb:272:in `content_tag'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/rails/component_mount.rb:50:in `react_component'
/Users/ryan.mcdonald/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/react-rails-2.4.7/lib/react/rails/view_helper.rb:21:in `react_component'
System configuration
Sprockets or Webpacker version: Webpacker 4.0.2 React-Rails version: 2.4.7 Rect_UJS version: 2.4.4 Rails version: 5.1 Ruby version: 2.5.1
It works perfectly fine when SplitChunks is not enabled. There is something happening where the ReactRailsUJS
object is being lost on the server, so this line fails.
This is the SplitChunks config that I’m using:
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: 3,
maxAsyncRequests: 5,
minSize: 30000,
name: false,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
minSize: 30000,
enforce: true,
},
},
},
runtimeChunk: true,
},
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 10
- Comments: 15 (4 by maintainers)
I found the issue and updated my sample repo with the solution that I found.
It looks like react-rails’s default
WebpackerManifestContainer
callsWebpacker.manifest.lookup
instead ofWebpacker.manifest.lookup_pack_with_chunks
when SplitChunks is enabled, so it never ends up executing theserver_rendering.js
which it needs in order to set theReactRailsUJS
global variable.WebpackerManifestContainer
should probably be updated to account for SplitChunks.Hey @RyanMcDonald, thanks so much for your example and the repro! Between the two, I got this working as well.
For anyone else who attempts this next, one other piece that I needed to do was add this:
Otherwise you’ll get a
window is not defined
error.I configured SplitChunks to ignore
server_rendering.js
, which seems to work fine:Same here. Rails 6. Neither monkey-patch nor chunk exclusion helped…
My understanding was that
server_rendering.js
needs to have vendor files included to function, presumably so it can render components with React DOM. Since that’s only used by the server and not shipped to clients, I haven’t been too worried about it. Although I don’t know if there are performance considerations, I suppose ultimately the server still needs to run that JS…I mentioned on the other post, I have an updated version of that snippet to also create a separate
vendor_react
bundle to allow for longer caching. The concept is still the same, blockingserver_rendering.js
from being chunked.We still just have one large application bundle, though. In future, I’d like to at least route-split the app JS with additional entry points, but haven’t gotten that working with the
react-rails
gem yet.@ericraio I checked and yes you can still use
javascript_packs_with_chunks_tag
. What’s happening is that the SSR will only useserver_rendering.js
to execute javascript on the page, and all of the chunked javascript files are ignored on the server side. That way, you still get the efficiency ofsplitChunks
for delivering assets to the client.