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 ( + + ) + } +}) + 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')