Skip to content

Fix server-side rendering in development mode #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions lib/react/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ class Railtie < ::Rails::Railtie
config.after_initialize do |app|
# Server Rendering
# Concat component_filenames together for server rendering
app.config.react.components_js = app.config.react.component_filenames.map do |filename|
app.assets[filename].to_s
end.join(";")
app.config.react.components_js = lambda {
app.config.react.component_filenames.map do |filename|
app.assets[filename].to_s
end.join(";")
}

do_setup = lambda do
cfg = app.config.react
React::Renderer.setup!( cfg.react_js.call, cfg.components_js,
React::Renderer.setup!( cfg.react_js, cfg.components_js,
{:size => cfg.size, :timeout => cfg.timeout})
end

Expand Down
17 changes: 13 additions & 4 deletions lib/react/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def self.setup!(react_js, components_js, args={})
@@react_js = react_js
@@components_js = components_js
@@pool.shutdown{} if @@pool
reset_combined_js!
@@pool = ConnectionPool.new(:size => args[:size]||10, :timeout => args[:timeout]||20) { self.new }
end

Expand All @@ -19,8 +20,8 @@ def self.render(component, args={})
end
end

def self.combined_js
@@combined_js ||= <<-CODE
def self.setup_combined_js
<<-CODE
var global = global || this;

var console = global.console || {};
Expand All @@ -30,12 +31,20 @@ def self.combined_js
}
});

#{@@react_js};
#{@@react_js.call};
React = global.React;
#{@@components_js};
#{@@components_js.call};
CODE
end

def self.reset_combined_js!
@@combined_js = setup_combined_js
end

def self.combined_js
@@combined_js
end

def context
@context ||= ExecJS.compile(self.class.combined_js)
end
Expand Down
22 changes: 22 additions & 0 deletions test/helper_files/TodoListWithUpdates.js.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/** @jsx React.DOM */

TodoList = React.createClass({
getInitialState: function() {
return({mounted: "nope"});
},
componentWillMount: function() {
this.setState({mounted: 'yep'});
},
render: function() {
return (
<ul>
<li>Updated</li>
<li id='status'>{this.state.mounted}</li>
{this.props.todos.map(function(todo, i) {
return (<Todo key={i} todo={todo} />)
})}
</ul>
)
}
})

2 changes: 2 additions & 0 deletions test/react_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class ReactTest < ActionDispatch::IntegrationTest

assert_response :success
assert_equal "'test_confirmation_token_react_content';\n", @response.body

React::Renderer.reset_combined_js!
end

end
37 changes: 37 additions & 0 deletions test/server_rendered_html_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'test_helper'
require 'fileutils'

class ServerRenderedHtmlTest < ActionDispatch::IntegrationTest
# Rails' asset pipeline has trouble picking up changes to files if they happen too fast.
# By sleeping for a little bit at certain points, we can make sure that rails notices the
# change in the file mtime, and calls our renderer setup functions appropriately
def wait_to_ensure_asset_pipeline_detects_changes
sleep(1)
end

test 'react server rendering reloads jsx after changes to the jsx files' do
file_with_updates = File.expand_path('../helper_files/TodoListWithUpdates.js.jsx', __FILE__)
file_without_updates = File.expand_path('../helper_files/TodoListWithoutUpdates.js.jsx', __FILE__)
app_file = File.expand_path('../dummy/app/assets/javascripts/components/TodoList.js.jsx', __FILE__)

FileUtils.cp app_file, file_without_updates
FileUtils.touch app_file

begin
get '/server/1'
refute_match 'Updated', response.body

wait_to_ensure_asset_pipeline_detects_changes
FileUtils.cp file_with_updates, app_file
FileUtils.touch app_file

get '/server/1'
assert_match 'Updated', response.body
ensure
# if we have a test failure, we want to make sure that we revert the dummy file
wait_to_ensure_asset_pipeline_detects_changes
FileUtils.mv file_without_updates, app_file
FileUtils.touch app_file
end
end
end
4 changes: 4 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@
if ActiveSupport::TestCase.method_defined?(:fixture_path=)
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
end

def wait_for_turbolinks_to_be_available
sleep(1)
end
4 changes: 4 additions & 0 deletions test/view_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ class ViewHelperTest < ActionDispatch::IntegrationTest
page.execute_script('history.back();')
assert page.has_content?('Hello Alice')

wait_for_turbolinks_to_be_available()

# Try Turbolinks javascript API.
page.execute_script('Turbolinks.visit("/pages/2");')
assert page.has_content?('Hello Alice')

wait_for_turbolinks_to_be_available()

page.execute_script('Turbolinks.visit("/pages/1");')
assert page.has_content?('Hello Bob')

Expand Down