diff --git a/.travis.yml b/.travis.yml index b4726ce8e..8ef2c7056 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,14 +10,16 @@ rvm: - jruby-9.0.1.0 gemfile: + # These have webpacker: + - gemfiles/rails_4.2_sprockets_4.gemfile + - gemfiles/rails_5_no_sprockets_webpacker.gemfile + # These don't have webpacker: - gemfiles/rails_3.2.gemfile - gemfiles/rails_4.0.5.gemfile - gemfiles/rails_4.0_with_therubyracer.gemfile - gemfiles/rails_4.1.gemfile - gemfiles/rails_4.2_sprockets_2.gemfile - gemfiles/rails_4.2_sprockets_3.gemfile - - gemfiles/rails_4.2_sprockets_4.gemfile - - gemfiles/rails_5_no_sprockets_webpacker.gemfile - gemfiles/rails_5_no_sprockets.gemfile - gemfiles/rails_5_sprockets_4.gemfile diff --git a/lib/react/server_rendering/webpacker_manifest_container.rb b/lib/react/server_rendering/webpacker_manifest_container.rb index 5cac670eb..57fbad26f 100644 --- a/lib/react/server_rendering/webpacker_manifest_container.rb +++ b/lib/react/server_rendering/webpacker_manifest_container.rb @@ -2,13 +2,17 @@ module React module ServerRendering + CLIENT_REQUIRE = %r{__webpack_require__\(.*webpack-dev-server\/client\/index\.js.*\n} + # Get a compiled file from Webpacker class WebpackerManifestContainer def find_asset(logical_path) asset_path = Webpacker::Manifest.lookup(logical_path) # raises if not found if asset_path.start_with?("http") - # TODO: this includes webpack-dev-server code which causes ExecJS to 💥 + # this includes `webpack-dev-server/client/index.js` code which causes ExecJS to 💥 dev_server_asset = open(asset_path).read + dev_server_asset.sub!(CLIENT_REQUIRE, '//\0') + dev_server_asset else full_path = File.join( # TODO: using `.parent` here won't work for nonstandard configurations diff --git a/test/dummy/app/javascript/components/GreetingMessage.js b/test/dummy/app/javascript/components/GreetingMessage.js index 387550df0..02a0c123b 100644 --- a/test/dummy/app/javascript/components/GreetingMessage.js +++ b/test/dummy/app/javascript/components/GreetingMessage.js @@ -16,7 +16,7 @@ module.exports = React.createClass({ }, render: function() { return React.DOM.div({}, - React.DOM.div({}, this.state.greeting, ' ', this.props.name), + React.DOM.div({}, this.state.greeting, ' from Webpacker ', this.props.name ), React.DOM.button({onClick: this.goodbye}, 'Goodbye') ); } diff --git a/test/react/rails/pages_controller_test.rb b/test/react/rails/pages_controller_test.rb index 45faf15ae..34d96d1e2 100644 --- a/test/react/rails/pages_controller_test.rb +++ b/test/react/rails/pages_controller_test.rb @@ -25,4 +25,15 @@ class PagesControllerTest < ActionController::TestCase assert_includes(response.body, "Hello") end end + + WebpackerHelpers.when_webpacker_available do + test "it mounts components from the dev server" do + WebpackerHelpers.with_dev_server do + get :show, id: 1, prerender: true + assert_match /Hello from Webpacker/, response.body + get :show, id: 1, prerender: true, greeting: "Howdy" + assert_match /Howdy from Webpacker/, response.body + end + end + end end diff --git a/test/react/rails/webpacker_test.rb b/test/react/rails/webpacker_test.rb index 1bc9b13d8..0d0a3cc62 100644 --- a/test/react/rails/webpacker_test.rb +++ b/test/react/rails/webpacker_test.rb @@ -13,7 +13,7 @@ class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest WebpackerHelpers.clear_webpacker_packs end - test 'it mounts pages from the pack' do + test 'it mounts components from the pack' do visit '/pack_component' assert page.has_content?('Export Default') assert page.has_content?('Named Export') diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index 585ce4d25..d4aec6403 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -18,55 +18,14 @@ class WebpackerManifestContainerTest < ActiveSupport::TestCase end def test_it_loads_from_webpack_dev_server - webpack_dev_server = fork do - Dir.chdir("test/dummy") do - exec "RAILS_ENV=development ./bin/webpack-dev-server " - end + WebpackerHelpers.with_dev_server do + container = React::ServerRendering::WebpackerManifestContainer.new + js_file = container.find_asset("application.js") + # Main file: + assert_includes js_file, "ReactRailsUJS.loadContext(ctx)" + # Bundled dependencies: + assert_includes js_file, "ExportDefaultComponent" end - - detected_dev_server = false - 60.times do |i| - begin - # Make sure that the manifest has been updated: - Webpacker::Manifest.load("./test/dummy/public/packs/manifest.json") - webpack_manifest = Webpacker::Manifest.instance.data - example_asset_path = webpack_manifest.values.first - if example_asset_path.nil? - puts "Manifest is blank, all manifests:" - Dir.glob("./test/dummy/public/packs/*.json").each do |f| - puts f - puts File.read(f) - end - next - end - assert_includes example_asset_path, "http://localhost:8080" - # Make sure the dev server is up: - open("http://localhost:8080/application.js") - detected_dev_server = true - break - rescue StandardError => err - puts err.message - ensure - sleep 0.5 - puts i - end - end - - # If we didn't hook up with a dev server after 10s, - # fail loudly. - assert detected_dev_server - - container = React::ServerRendering::WebpackerManifestContainer.new - js_file = container.find_asset("application.js") - # Main file: - assert_includes js_file, "ReactRailsUJS.loadContext(ctx)" - # Bundled dependencies: - assert_includes js_file, "ExportDefaultComponent" - ensure - Process.kill(9, webpack_dev_server) - Process.wait - # Remove the dev-server packs: - WebpackerHelpers.clear_webpacker_packs end end end diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index b95f48171..b0a82e6aa 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -34,4 +34,81 @@ def compile_if_missing def clear_webpacker_packs FileUtils.rm_rf(PACKS_DIRECTORY) end + + # Start a webpack-dev-server + # Call the block + # Make sure to clean up the server + def with_dev_server + # Start the server in a forked process: + webpack_dev_server = Dir.chdir("test/dummy") do + spawn "RAILS_ENV=development ./bin/webpack-dev-server " + end + + detected_dev_server = false + + # Wait for it to start up, make sure it's there by connecting to it: + 30.times do |i| + begin + # Make sure that the manifest has been updated: + Webpacker::Manifest.load("./test/dummy/public/packs/manifest.json") + webpack_manifest = Webpacker::Manifest.instance.data + example_asset_path = webpack_manifest.values.first + if example_asset_path.nil? + # Debug helper + # puts "Manifest is blank, all manifests:" + # Dir.glob("./test/dummy/public/packs/*.json").each do |f| + # puts f + # puts File.read(f) + # end + next + end + # Make sure the dev server is up: + open("http://localhost:8080/application.js") + if !example_asset_path.start_with?("http://localhost:8080") + raise "Manifest doesn't include absolute path to dev server" + end + + detected_dev_server = true + break + rescue StandardError => err + puts err.message + ensure + sleep 0.5 + # debug counter + # puts i + end + end + + # If we didn't hook up with a dev server after waiting, fail loudly. + if !detected_dev_server + raise "Failed to start dev server" + end + + # Call the test block: + yield + ensure + # Kill the server process + # puts "Killing webpack dev server" + check_cmd = "lsof -i :8080 -S" + 10.times do + # puts check_cmd + status = `#{check_cmd}` + # puts status + remaining_pid_match = status.match(/\n[a-z]+\s+(\d+)/) + if remaining_pid_match + remaining_pid = remaining_pid_match[1] + # puts "Remaining #{remaining_pid}" + kill_cmd = "kill -9 #{remaining_pid}" + # puts kill_cmd + `#{kill_cmd}` + sleep 0.5 + else + break + end + end + + # Remove the dev-server packs: + WebpackerHelpers.clear_webpacker_packs + # puts "Killed." + end end