diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb
index b567a9f6..3a10b1c8 100644
--- a/lib/react/rails/railtie.rb
+++ b/lib/react/rails/railtie.rb
@@ -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
diff --git a/lib/react/renderer.rb b/lib/react/renderer.rb
index 52141548..bc60c086 100644
--- a/lib/react/renderer.rb
+++ b/lib/react/renderer.rb
@@ -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
@@ -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 || {};
@@ -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
diff --git a/test/helper_files/TodoListWithUpdates.js.jsx b/test/helper_files/TodoListWithUpdates.js.jsx
new file mode 100644
index 00000000..b3950c95
--- /dev/null
+++ b/test/helper_files/TodoListWithUpdates.js.jsx
@@ -0,0 +1,22 @@
+/** @jsx React.DOM */
+
+TodoList = React.createClass({
+ getInitialState: function() {
+ return({mounted: "nope"});
+ },
+ componentWillMount: function() {
+ this.setState({mounted: 'yep'});
+ },
+ render: function() {
+ return (
+
+ - Updated
+ - {this.state.mounted}
+ {this.props.todos.map(function(todo, i) {
+ return ()
+ })}
+
+ )
+ }
+})
+
diff --git a/test/react_test.rb b/test/react_test.rb
index c78243e6..81166ab0 100644
--- a/test/react_test.rb
+++ b/test/react_test.rb
@@ -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
diff --git a/test/server_rendered_html_test.rb b/test/server_rendered_html_test.rb
new file mode 100644
index 00000000..67ee758f
--- /dev/null
+++ b/test/server_rendered_html_test.rb
@@ -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
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 77725df8..125699b3 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -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
diff --git a/test/view_helper_test.rb b/test/view_helper_test.rb
index e80796de..81c74b0f 100644
--- a/test/view_helper_test.rb
+++ b/test/view_helper_test.rb
@@ -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')