From 010c14bd57c212215ee73cb8a91a2e4384877ae0 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Tue, 4 Apr 2017 16:48:49 -0400 Subject: [PATCH 01/10] feat(ServerRendering) add WebpackerManifestContainer --- .../server_rendering/sprockets_renderer.rb | 38 ++++++++++++------- .../webpacker_manifest_container.rb | 21 ++++++++++ .../yaml_manifest_container.rb | 2 +- test/react/rails/webpacker_test.rb | 1 - .../webpacker_manifest_container_test.rb | 14 +++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 lib/react/server_rendering/webpacker_manifest_container.rb create mode 100644 test/react/server_rendering/webpacker_manifest_container_test.rb diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index ed43c20bd..d79a2677a 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -1,5 +1,6 @@ require "react/server_rendering/environment_container" require "react/server_rendering/manifest_container" +require "react/server_rendering/webpacker_manifest_container" require "react/server_rendering/yaml_manifest_container" module React @@ -57,19 +58,7 @@ class << self # # @return [#find_asset(logical_path)] An object that returns asset contents by logical path def asset_container - @asset_container ||= if self.class.asset_container_class.present? - self.class.asset_container_class.new - elsif assets_precompiled? && ManifestContainer.compatible? - ManifestContainer.new - elsif assets_precompiled? && YamlManifestContainer.compatible? - YamlManifestContainer.new - else - EnvironmentContainer.new - end - end - - def assets_precompiled? - !::Rails.application.config.assets.compile + @asset_container ||= asset_container_class.new end private @@ -97,6 +86,29 @@ def render_function(opts) def prepare_props(props) props.is_a?(String) ? props : props.to_json end + + def assets_precompiled? + !::Rails.application.config.assets.compile + end + + def asset_container_class + if self.class.asset_container_class.present? + self.class.asset_container_class + elsif assets_precompiled? + if WebpackerManifestContainer.compatible? + WebpackerManifestContainer + elsif ManifestContainer.compatible? + ManifestContainer + elsif YamlManifestContainer.compatible? + YamlManifestContainer + else + # Even though they are precompiled, we can't find them :S + EnvironmentContainer + end + else + EnvironmentContainer + end + end end end end diff --git a/lib/react/server_rendering/webpacker_manifest_container.rb b/lib/react/server_rendering/webpacker_manifest_container.rb new file mode 100644 index 000000000..254e8d30b --- /dev/null +++ b/lib/react/server_rendering/webpacker_manifest_container.rb @@ -0,0 +1,21 @@ +module React + module ServerRendering + # Get a compiled file from Webpacker + class WebpackerManifestContainer + def find_asset(logical_path) + asset_path = Webpacker::Manifest.lookup(logical_path) # raises if not found + full_path = File.join( + # TODO: using `.parent` here won't work for nonstandard configurations + Webpacker::Configuration.output_path.parent, + asset_path + ) + # TODO: webpacker-dev-server points these at localhost:8080 + File.read(full_path) + end + + def self.compatible? + defined?(Webpacker) + end + end + end +end diff --git a/lib/react/server_rendering/yaml_manifest_container.rb b/lib/react/server_rendering/yaml_manifest_container.rb index 8f5634cf8..9d51cb79b 100644 --- a/lib/react/server_rendering/yaml_manifest_container.rb +++ b/lib/react/server_rendering/yaml_manifest_container.rb @@ -1,6 +1,6 @@ module React module ServerRendering - # Get asset content by reading the compiled file from disk using the generated maniftest.yml file + # Get asset content by reading the compiled file from disk using the generated manifest.yml file # # This is good for Rails production when assets are compiled to public/assets # but sometimes, they're compiled to other directories (or other servers) diff --git a/test/react/rails/webpacker_test.rb b/test/react/rails/webpacker_test.rb index 2f278f38d..90f1f70a2 100644 --- a/test/react/rails/webpacker_test.rb +++ b/test/react/rails/webpacker_test.rb @@ -1,6 +1,5 @@ require 'test_helper' - WebpackerHelpers.when_webpacker_available do class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest include Capybara::DSL diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb new file mode 100644 index 000000000..ae5d36146 --- /dev/null +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -0,0 +1,14 @@ +require "test_helper" + +WebpackerHelpers.when_webpacker_available do + class WebpackerManifestContainerTest < ActiveSupport::TestCase + test "it loads JS from the webpacker container" 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 + end +end From 15d5d2dc783005bb799e3bed1b162c126471cb86 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Wed, 5 Apr 2017 11:38:59 -0400 Subject: [PATCH 02/10] feat(WebpackerManifestContainer) use webpack-dev-server if detected --- .../server_rendering/sprockets_renderer.rb | 6 +-- .../webpacker_manifest_container.rb | 22 +++++---- test/react/rails/webpacker_test.rb | 1 + .../webpacker_manifest_container_test.rb | 45 +++++++++++++++++++ test/support/webpacker_helpers.rb | 15 ++++--- 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index d79a2677a..b6d693606 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -94,10 +94,10 @@ def assets_precompiled? def asset_container_class if self.class.asset_container_class.present? self.class.asset_container_class + elsif WebpackerManifestContainer.compatible? + WebpackerManifestContainer elsif assets_precompiled? - if WebpackerManifestContainer.compatible? - WebpackerManifestContainer - elsif ManifestContainer.compatible? + if ManifestContainer.compatible? ManifestContainer elsif YamlManifestContainer.compatible? YamlManifestContainer diff --git a/lib/react/server_rendering/webpacker_manifest_container.rb b/lib/react/server_rendering/webpacker_manifest_container.rb index 254e8d30b..5cac670eb 100644 --- a/lib/react/server_rendering/webpacker_manifest_container.rb +++ b/lib/react/server_rendering/webpacker_manifest_container.rb @@ -1,20 +1,26 @@ +require "open-uri" + module React module ServerRendering # Get a compiled file from Webpacker class WebpackerManifestContainer def find_asset(logical_path) asset_path = Webpacker::Manifest.lookup(logical_path) # raises if not found - full_path = File.join( - # TODO: using `.parent` here won't work for nonstandard configurations - Webpacker::Configuration.output_path.parent, - asset_path - ) - # TODO: webpacker-dev-server points these at localhost:8080 - File.read(full_path) + if asset_path.start_with?("http") + # TODO: this includes webpack-dev-server code which causes ExecJS to 💥 + dev_server_asset = open(asset_path).read + else + full_path = File.join( + # TODO: using `.parent` here won't work for nonstandard configurations + Webpacker::Configuration.output_path.parent, + asset_path + ) + File.read(full_path) + end end def self.compatible? - defined?(Webpacker) + !!defined?(Webpacker) end end end diff --git a/test/react/rails/webpacker_test.rb b/test/react/rails/webpacker_test.rb index 90f1f70a2..1bc9b13d8 100644 --- a/test/react/rails/webpacker_test.rb +++ b/test/react/rails/webpacker_test.rb @@ -6,6 +6,7 @@ class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest setup do Capybara.current_driver = Capybara.javascript_driver + WebpackerHelpers.compile end teardown do diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index ae5d36146..92e304db1 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -1,14 +1,59 @@ require "test_helper" +require "open-uri" WebpackerHelpers.when_webpacker_available do class WebpackerManifestContainerTest < ActiveSupport::TestCase + setup do + WebpackerHelpers.clear_webpacker_packs + end + test "it loads JS from the webpacker container" do + WebpackerHelpers.compile + 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 + + def test_it_loads_from_webpack_dev_server + webpack_dev_server = fork do + Dir.chdir("test/dummy") do + exec "./bin/webpack-dev-server RAILS_ENV=development" + end + end + + detected_dev_server = false + 20.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 + 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 + sleep 0.5 + 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 end end end diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index d6b8eaa4b..7b454df81 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -6,16 +6,19 @@ def available? def when_webpacker_available if available? - clear_webpacker_packs - Dir.chdir("./test/dummy") do - Rake::Task['webpacker:compile'].invoke - end - # Reload cached JSON manifest: - Webpacker::Manifest.load yield end end + def compile + clear_webpacker_packs + Dir.chdir("./test/dummy") do + Rake::Task['webpacker:compile'].invoke + end + # Reload cached JSON manifest: + Webpacker::Manifest.load + end + def clear_webpacker_packs packs_directory = File.expand_path("../dummy/public/packs", __FILE__) FileUtils.rm_rf(packs_directory) From 51ec36c56cecd378e56c531b0c5bb2dfeef92c7f Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Thu, 6 Apr 2017 15:13:27 -0400 Subject: [PATCH 03/10] feat(ServerRendering) watch app/javascripts; improve UJS for server rendering --- lib/assets/javascripts/react_ujs.js | 11 +++- lib/react/rails/railtie.rb | 5 ++ .../server_rendering/exec_js_renderer.rb | 2 +- react_ujs/dist/react_ujs.js | 11 +++- react_ujs/index.js | 6 ++ react_ujs/src/getConstructor/fromGlobal.js | 5 +- react_ujs/yarn.lock | 16 ++--- .../app/controllers/server_controller.rb | 1 + .../app/javascript/components/TodoList.js | 21 +++++++ .../components/TodoListWithConsoleLog.js | 25 ++++++++ .../javascript/components/WithSetTimeout.js | 10 +++ .../app/javascript/packs/server_rendering.js | 5 ++ test/dummy/app/views/server/show.html.erb | 2 +- test/helper_files/TodoListWithUpdates.js | 10 +++ .../server_rendering/exec_js_renderer_test.rb | 3 +- .../sprockets_renderer_test.rb | 11 ++-- test/server_rendered_html_test.rb | 61 ++++++++++++++----- test/support/webpacker_helpers.rb | 5 +- 18 files changed, 172 insertions(+), 38 deletions(-) create mode 100644 test/dummy/app/javascript/components/TodoList.js create mode 100644 test/dummy/app/javascript/components/TodoListWithConsoleLog.js create mode 100644 test/dummy/app/javascript/components/WithSetTimeout.js create mode 100644 test/dummy/app/javascript/packs/server_rendering.js create mode 100644 test/helper_files/TodoListWithUpdates.js diff --git a/lib/assets/javascripts/react_ujs.js b/lib/assets/javascripts/react_ujs.js index 3480af23a..ee4723978 100644 --- a/lib/assets/javascripts/react_ujs.js +++ b/lib/assets/javascripts/react_ujs.js @@ -125,15 +125,16 @@ module.exports = function(ujs) { // Assume className is simple and can be found at top-level (window). // Fallback to eval to handle cases like 'My.React.ComponentName'. // Also, try to gracefully import Babel 6 style default exports +var topLevel = typeof window === "undefined" ? this : window; + module.exports = function(className) { var constructor; - var topLevel = typeof window === "undefined" ? this : window; // Try to access the class globally first constructor = topLevel[className]; // If that didn't work, try eval if (!constructor) { - constructor = eval.call(topLevel, className); + constructor = eval(className); } // Lastly, if there is a default attribute try that @@ -308,6 +309,12 @@ if (typeof window !== "undefined") { detectEvents(ReactRailsUJS) } +// It's a bit of a no-no to populate the global namespace, +// but we really need it! +// We need access to this object for server rendering, and +// we can't do a dynamic `require`, so we'll grab it from here: +this.ReactRailsUJS = ReactRailsUJS + module.exports = ReactRailsUJS diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index ee3e50445..bd75eb1f5 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -20,6 +20,10 @@ class Railtie < ::Rails::Railtie # Changing files with these extensions in these directories will cause the server renderer to reload: config.react.server_renderer_directories = ["/app/assets/javascripts/"] config.react.server_renderer_extensions = ["jsx"] + if defined?(Webpacker) + config.react.server_renderer_directories << "app/javascript" + config.react.server_renderer_extensions << "js" + end # View helper implementation: config.react.view_helper_implementation = nil # Defaults to ComponentMount @@ -30,6 +34,7 @@ class Railtie < ::Rails::Railtie memo[app_dir] = config.react.server_renderer_extensions memo end + app.reloaders << ActiveSupport::FileUpdateChecker.new([], reload_paths) do React::ServerRendering.reset_pool end diff --git a/lib/react/server_rendering/exec_js_renderer.rb b/lib/react/server_rendering/exec_js_renderer.rb index 0afba4d35..bc8ef7552 100644 --- a/lib/react/server_rendering/exec_js_renderer.rb +++ b/lib/react/server_rendering/exec_js_renderer.rb @@ -41,7 +41,7 @@ def render_from_parts(before, main, after) def main_render(component_name, props, prerender_options) render_function = prerender_options.fetch(:render_function, "renderToString") - "ReactRailsUJS.serverRender('#{render_function}', #{component_name}, #{props})" + "this.ReactRailsUJS.serverRender('#{render_function}', '#{component_name}', #{props})" end def compose_js(before, main, after) diff --git a/react_ujs/dist/react_ujs.js b/react_ujs/dist/react_ujs.js index 3480af23a..ee4723978 100644 --- a/react_ujs/dist/react_ujs.js +++ b/react_ujs/dist/react_ujs.js @@ -125,15 +125,16 @@ module.exports = function(ujs) { // Assume className is simple and can be found at top-level (window). // Fallback to eval to handle cases like 'My.React.ComponentName'. // Also, try to gracefully import Babel 6 style default exports +var topLevel = typeof window === "undefined" ? this : window; + module.exports = function(className) { var constructor; - var topLevel = typeof window === "undefined" ? this : window; // Try to access the class globally first constructor = topLevel[className]; // If that didn't work, try eval if (!constructor) { - constructor = eval.call(topLevel, className); + constructor = eval(className); } // Lastly, if there is a default attribute try that @@ -308,6 +309,12 @@ if (typeof window !== "undefined") { detectEvents(ReactRailsUJS) } +// It's a bit of a no-no to populate the global namespace, +// but we really need it! +// We need access to this object for server rendering, and +// we can't do a dynamic `require`, so we'll grab it from here: +this.ReactRailsUJS = ReactRailsUJS + module.exports = ReactRailsUJS diff --git a/react_ujs/index.js b/react_ujs/index.js index 5934ac0eb..8a6dfa9a4 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -109,4 +109,10 @@ if (typeof window !== "undefined") { detectEvents(ReactRailsUJS) } +// It's a bit of a no-no to populate the global namespace, +// but we really need it! +// We need access to this object for server rendering, and +// we can't do a dynamic `require`, so we'll grab it from here: +this.ReactRailsUJS = ReactRailsUJS + module.exports = ReactRailsUJS diff --git a/react_ujs/src/getConstructor/fromGlobal.js b/react_ujs/src/getConstructor/fromGlobal.js index 90ddb2cf2..5c4aa3ff0 100644 --- a/react_ujs/src/getConstructor/fromGlobal.js +++ b/react_ujs/src/getConstructor/fromGlobal.js @@ -1,15 +1,16 @@ // Assume className is simple and can be found at top-level (window). // Fallback to eval to handle cases like 'My.React.ComponentName'. // Also, try to gracefully import Babel 6 style default exports +var topLevel = typeof window === "undefined" ? this : window; + module.exports = function(className) { var constructor; - var topLevel = typeof window === "undefined" ? this : window; // Try to access the class globally first constructor = topLevel[className]; // If that didn't work, try eval if (!constructor) { - constructor = eval.call(topLevel, className); + constructor = eval(className); } // Lastly, if there is a default attribute try that diff --git a/react_ujs/yarn.lock b/react_ujs/yarn.lock index e3e3e5c46..52133cbf3 100644 --- a/react_ujs/yarn.lock +++ b/react_ujs/yarn.lock @@ -993,8 +993,8 @@ ms@0.7.2: resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" nan@^2.3.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" + version "2.6.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.1.tgz#8c84f7b14c96b89f57fbc838012180ec8ca39a01" node-libs-browser@^2.0.0: version "2.0.0" @@ -1252,8 +1252,8 @@ randombytes@^2.0.0, randombytes@^2.0.1: resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" rc@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.0.tgz#c7de973b7b46297c041366b2fd3d2363b1697c66" + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" dependencies: deep-extend "~0.4.0" ini "~1.3.0" @@ -1275,7 +1275,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.4: +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" dependencies: @@ -1447,12 +1447,12 @@ stream-browserify@^2.0.1: readable-stream "^2.0.2" stream-http@^2.3.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.3.tgz#4c3ddbf9635968ea2cfd4e48d43de5def2625ac3" + version "2.7.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.1.0" + readable-stream "^2.2.6" to-arraybuffer "^1.0.0" xtend "^4.0.0" diff --git a/test/dummy/app/controllers/server_controller.rb b/test/dummy/app/controllers/server_controller.rb index f72d1952c..de3cb5af8 100644 --- a/test/dummy/app/controllers/server_controller.rb +++ b/test/dummy/app/controllers/server_controller.rb @@ -1,5 +1,6 @@ class ServerController < ApplicationController def show + @component_name = params[:component_name] || "TodoList" @todos = %w{todo1 todo2 todo3} end diff --git a/test/dummy/app/javascript/components/TodoList.js b/test/dummy/app/javascript/components/TodoList.js new file mode 100644 index 000000000..1a7512604 --- /dev/null +++ b/test/dummy/app/javascript/components/TodoList.js @@ -0,0 +1,21 @@ +var React = require("react") + +module.exports = React.createClass({ + getInitialState: function() { + return({mounted: "nope"}); + }, + componentWillMount: function() { + this.setState({mounted: 'yep'}); + }, + render: function() { + return ( +
    +
  • {this.state.mounted}
  • + {this.props.todos.map(function(todo, i) { + return (
  • {todo}
  • ) + })} +
  • From Webpacker
  • +
+ ) + } +}) diff --git a/test/dummy/app/javascript/components/TodoListWithConsoleLog.js b/test/dummy/app/javascript/components/TodoListWithConsoleLog.js new file mode 100644 index 000000000..1d4268693 --- /dev/null +++ b/test/dummy/app/javascript/components/TodoListWithConsoleLog.js @@ -0,0 +1,25 @@ +var React = require("react") + +module.exports = React.createClass({ + getInitialState: function() { + console.log('got initial state'); + return({mounted: "nope"}); + }, + componentWillMount: function() { + console.warn('mounted component'); + this.setState({mounted: 'yep'}); + }, + render: function() { + var x = 'foo'; + console.error('rendered!', x); + return ( +
    +
  • Console Logged
  • +
  • {this.state.mounted}
  • + {this.props.todos.map(function(todo, i) { + return (
  • {todo}
  • ) + })} +
+ ) + } +}) diff --git a/test/dummy/app/javascript/components/WithSetTimeout.js b/test/dummy/app/javascript/components/WithSetTimeout.js new file mode 100644 index 000000000..2adf058e3 --- /dev/null +++ b/test/dummy/app/javascript/components/WithSetTimeout.js @@ -0,0 +1,10 @@ +var React = require("react") +module.exports = React.createClass({ + componentWillMount: function () { + setTimeout(function () {}, 1000) + clearTimeout(0) + }, + render: function () { + return I am rendered! + } +}) diff --git a/test/dummy/app/javascript/packs/server_rendering.js b/test/dummy/app/javascript/packs/server_rendering.js new file mode 100644 index 000000000..5962708d2 --- /dev/null +++ b/test/dummy/app/javascript/packs/server_rendering.js @@ -0,0 +1,5 @@ +// By default, this pack is loaded for server-side rendering. +// It must expose react_ujs as `ReactRailsUJS` and prepare a require context. +var componentRequireContext = require.context("components", true) +var ReactRailsUJS = require("react_ujs") +ReactRailsUJS.loadContext(componentRequireContext) diff --git a/test/dummy/app/views/server/show.html.erb b/test/dummy/app/views/server/show.html.erb index 679857399..168559a75 100644 --- a/test/dummy/app/views/server/show.html.erb +++ b/test/dummy/app/views/server/show.html.erb @@ -1 +1 @@ -<%= react_component "TodoList", {todos: @todos}, {prerender: true} %> +<%= react_component @component_name, {todos: @todos}, {prerender: true} %> diff --git a/test/helper_files/TodoListWithUpdates.js b/test/helper_files/TodoListWithUpdates.js new file mode 100644 index 000000000..1b9233803 --- /dev/null +++ b/test/helper_files/TodoListWithUpdates.js @@ -0,0 +1,10 @@ +var React = require("react") +module.exports = React.createClass({ + render: function() { + return ( +
    +
  • Updated
  • +
+ ) + } +}) diff --git a/test/react/server_rendering/exec_js_renderer_test.rb b/test/react/server_rendering/exec_js_renderer_test.rb index 7aa4c405e..f45f881e7 100644 --- a/test/react/server_rendering/exec_js_renderer_test.rb +++ b/test/react/server_rendering/exec_js_renderer_test.rb @@ -5,7 +5,7 @@ var React = { createElement: function() {}, } -var ReactRailsUJS = { +this.ReactRailsUJS = { serverRender: function() { return 'serverRender was called' }, @@ -50,7 +50,6 @@ def @renderer.after_render(name, props, opts) assert_no_match(/assigned_after_render/, error.message) end - test '#after_render is called after #before_render' do def @renderer.before_render(name, props, opts) "var beforeRenderVar = 'assigned_before_render'" diff --git a/test/react/server_rendering/sprockets_renderer_test.rb b/test/react/server_rendering/sprockets_renderer_test.rb index bb954e082..d202d2e5d 100644 --- a/test/react/server_rendering/sprockets_renderer_test.rb +++ b/test/react/server_rendering/sprockets_renderer_test.rb @@ -77,12 +77,15 @@ class SprocketsRendererTest < ActiveSupport::TestCase assert_match(/console.error.apply\(console, \["setTimeout #{message}"\]\);$/, result) end - test '.new accepts additional code to add to the JS context' do - additional_code = File.read(File.expand_path("../../../helper_files/WithoutSprockets.js", __FILE__)) + if !WebpackerHelpers.available? + # This doesn't work with webpacker since finding components is based on filename + test '.new accepts additional code to add to the JS context' do + additional_code = File.read(File.expand_path("../../../helper_files/WithoutSprockets.js", __FILE__)) - additional_renderer = React::ServerRendering::SprocketsRenderer.new(code: additional_code) + additional_renderer = React::ServerRendering::SprocketsRenderer.new(code: additional_code) - assert_match(/drink more caffeine<\/span>/, additional_renderer.render("WithoutSprockets", {label: "drink more caffeine"}, nil)) + assert_match(/drink more caffeine<\/span>/, additional_renderer.render("WithoutSprockets", {label: "drink more caffeine"}, nil)) + end end test '.new accepts any filenames' do diff --git a/test/server_rendered_html_test.rb b/test/server_rendered_html_test.rb index 2aa174ed9..41c4af05b 100644 --- a/test/server_rendered_html_test.rb +++ b/test/server_rendered_html_test.rb @@ -10,10 +10,22 @@ def wait_to_ensure_asset_pipeline_detects_changes sleep(1) end + setup do + if WebpackerHelpers.available? + WebpackerHelpers.compile + end + 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__) + if WebpackerHelpers.available? + file_with_updates = File.expand_path('../helper_files/TodoListWithUpdates.js', __FILE__) + file_without_updates = File.expand_path('../helper_files/TodoListWithoutUpdates.js', __FILE__) + app_file = File.expand_path('../dummy/app/javascript/components/TodoList.js', __FILE__) + else + 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__) + end FileUtils.cp app_file, file_without_updates FileUtils.touch app_file @@ -25,7 +37,11 @@ def wait_to_ensure_asset_pipeline_detects_changes FileUtils.cp file_with_updates, app_file FileUtils.touch app_file - wait_to_ensure_asset_pipeline_detects_changes + if WebpackerHelpers.available? + WebpackerHelpers.compile + else + wait_to_ensure_asset_pipeline_detects_changes + end get '/server/1' assert_match(/Updated/, response.body) @@ -37,21 +53,36 @@ def wait_to_ensure_asset_pipeline_detects_changes end end - test 'it reloads when new jsx files are added' do + test 'it reloads when new jsx files are added to the asset pipeline' do begin - get '/server/1' - refute_match(/Overwritten List/, response.body) + assert_raises(ActionView::Template::Error) { + get '/server/1?component_name=NewList' + } - # Make it alphabetically last so it will override the preceeding one: - new_file_path = File.expand_path('../dummy/app/assets/javascripts/components/ZZ_NewComponent.js.jsx', __FILE__) - File.write new_file_path, <<-JS - var TodoList = function() { return "Overwritten List" } - JS + if WebpackerHelpers.available? + new_file_path = '../dummy/app/javascript/components/NewList.js' + new_file_contents = <<-JS + var React = require("react") + module.exports = function() { return "New List" } + JS + else + new_file_path = '../dummy/app/assets/javascripts/components/ZZ_NewComponent.js.jsx' + new_file_contents = <<-JS + var NewList = function() { return "New List" } + JS + end - wait_to_ensure_asset_pipeline_detects_changes + new_file_path = File.expand_path(new_file_path, __FILE__) + File.write new_file_path, new_file_contents - get '/server/1' - assert_match(/Overwritten List/, response.body) + if WebpackerHelpers.available? + WebpackerHelpers.compile + else + wait_to_ensure_asset_pipeline_detects_changes + end + + get '/server/1?component_name=NewList' + assert_match(/New List/, response.body) ensure FileUtils.rm_rf(new_file_path) wait_to_ensure_asset_pipeline_detects_changes diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index 7b454df81..f7099af53 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -13,7 +13,10 @@ def when_webpacker_available def compile clear_webpacker_packs Dir.chdir("./test/dummy") do - Rake::Task['webpacker:compile'].invoke + capture_io do + Rake::Task['webpacker:compile'].reenable + Rake::Task['webpacker:compile'].invoke + end end # Reload cached JSON manifest: Webpacker::Manifest.load From 295e6ca4194c3504c7a133ffa56440b728aac476 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Thu, 6 Apr 2017 17:56:53 -0400 Subject: [PATCH 04/10] fix(ServerRendering) improve webpacker + V8 server rendering --- react_ujs/index.js | 2 +- .../javascript/components/GreetingMessage.js | 23 ++++++++ test/dummy/app/javascript/components/Todo.js | 6 ++ .../app/javascript/packs/server_rendering.js | 2 +- .../sprockets_renderer_test.rb | 58 +++++++++++-------- 5 files changed, 66 insertions(+), 25 deletions(-) create mode 100644 test/dummy/app/javascript/components/GreetingMessage.js create mode 100644 test/dummy/app/javascript/components/Todo.js diff --git a/react_ujs/index.js b/react_ujs/index.js index 8a6dfa9a4..3cc3ead60 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -113,6 +113,6 @@ if (typeof window !== "undefined") { // but we really need it! // We need access to this object for server rendering, and // we can't do a dynamic `require`, so we'll grab it from here: -this.ReactRailsUJS = ReactRailsUJS +self.ReactRailsUJS = ReactRailsUJS module.exports = ReactRailsUJS diff --git a/test/dummy/app/javascript/components/GreetingMessage.js b/test/dummy/app/javascript/components/GreetingMessage.js new file mode 100644 index 000000000..387550df0 --- /dev/null +++ b/test/dummy/app/javascript/components/GreetingMessage.js @@ -0,0 +1,23 @@ +var React = require("react") + +module.exports = React.createClass({ + getInitialState: function() { + var initialGreeting = 'Hello'; + if (typeof global !== "undefined" && global.ctx && global.ctx.greeting) { + initialGreeting = global.ctx.greeting + } + + return { + greeting: initialGreeting + } + }, + goodbye: function() { + this.setState({greeting: 'Goodbye'}); + }, + render: function() { + return React.DOM.div({}, + React.DOM.div({}, this.state.greeting, ' ', this.props.name), + React.DOM.button({onClick: this.goodbye}, 'Goodbye') + ); + } +}); diff --git a/test/dummy/app/javascript/components/Todo.js b/test/dummy/app/javascript/components/Todo.js new file mode 100644 index 000000000..5c16713df --- /dev/null +++ b/test/dummy/app/javascript/components/Todo.js @@ -0,0 +1,6 @@ +var React = require("react") +module.exports = React.createClass({ + render: function() { + return React.createElement("li", null, this.props.todo) + } +}) diff --git a/test/dummy/app/javascript/packs/server_rendering.js b/test/dummy/app/javascript/packs/server_rendering.js index 5962708d2..fe6fbdd16 100644 --- a/test/dummy/app/javascript/packs/server_rendering.js +++ b/test/dummy/app/javascript/packs/server_rendering.js @@ -1,5 +1,5 @@ // By default, this pack is loaded for server-side rendering. // It must expose react_ujs as `ReactRailsUJS` and prepare a require context. var componentRequireContext = require.context("components", true) -var ReactRailsUJS = require("react_ujs") +var ReactRailsUJS = require("../../../../../react_ujs/index") ReactRailsUJS.loadContext(componentRequireContext) diff --git a/test/react/server_rendering/sprockets_renderer_test.rb b/test/react/server_rendering/sprockets_renderer_test.rb index d202d2e5d..f2793255a 100644 --- a/test/react/server_rendering/sprockets_renderer_test.rb +++ b/test/react/server_rendering/sprockets_renderer_test.rb @@ -4,7 +4,12 @@ class SprocketsRendererTest < ActiveSupport::TestCase CALLBACKS = [:before_render, :after_render] + webpacker_compiled = false setup do + if WebpackerHelpers.available? && !webpacker_compiled + WebpackerHelpers.compile + webpacker_compiled = true + end @renderer = React::ServerRendering::SprocketsRenderer.new({}) end @@ -62,8 +67,14 @@ class SprocketsRendererTest < ActiveSupport::TestCase err = assert_raises React::ServerRendering::PrerenderError do @renderer.render("NonExistentComponent", {}, nil) end - assert_match(/ReferenceError/, err.to_s) - assert_match(/NonExistentComponent/, err.to_s, "it names the component") + + if WebpackerHelpers.available? + assert_includes err.message, "Cannot find module './NonExistentComponent'" + else + assert_match(/ReferenceError/, err.to_s) + assert_match(/NonExistentComponent/, err.to_s, "it names the component") + end + assert_match(/\n/, err.to_s, "it includes the multi-line backtrace") end @@ -86,35 +97,36 @@ class SprocketsRendererTest < ActiveSupport::TestCase assert_match(/drink more caffeine<\/span>/, additional_renderer.render("WithoutSprockets", {label: "drink more caffeine"}, nil)) end - end - test '.new accepts any filenames' do - limited_renderer = React::ServerRendering::SprocketsRenderer.new(files: ["react-server.js", "react_ujs.js", "components/Todo.js"]) - assert_match(/get a real job<\/li>/, limited_renderer.render("Todo", {todo: "get a real job"}, nil)) - err = assert_raises React::ServerRendering::PrerenderError do - limited_renderer.render("TodoList", {todos: []}, nil) + # These use cases don't apply to Webpacker since the require.context comes from a pack: + test '.new accepts any filenames' do + limited_renderer = React::ServerRendering::SprocketsRenderer.new(files: ["react-server.js", "react_ujs.js", "components/Todo.js"]) + assert_match(/get a real job<\/li>/, limited_renderer.render("Todo", {todo: "get a real job"}, nil)) + err = assert_raises React::ServerRendering::PrerenderError do + limited_renderer.render("TodoList", {todos: []}, nil) + end + assert_match(/ReferenceError/, err.to_s, "it doesnt load other files") end - assert_match(/ReferenceError/, err.to_s, "it doesnt load other files") - end - test '#render returns html when config.assets.compile is false' do - begin - legacy_rendering_files = ["react-server.js", "react_ujs.js", "components.js"] - Rails.application.config.assets.precompile += legacy_rendering_files + test '#render returns html when config.assets.compile is false' do + begin + legacy_rendering_files = ["react-server.js", "react_ujs.js", "components.js"] + Rails.application.config.assets.precompile += legacy_rendering_files - precompile_assets + precompile_assets - Rails.application.config.assets.compile = false + Rails.application.config.assets.compile = false - @renderer = React::ServerRendering::SprocketsRenderer.new(files: legacy_rendering_files) + @renderer = React::ServerRendering::SprocketsRenderer.new(files: legacy_rendering_files) - result = @renderer.render("Todo", {todo: "write tests"}, nil) - assert_match(//, result) - assert_match(/data-react-checksum/, result) - ensure - Rails.application.config.assets.compile = true + result = @renderer.render("Todo", {todo: "write tests"}, nil) + assert_match(//, result) + assert_match(/data-react-checksum/, result) + ensure + Rails.application.config.assets.compile = true - clear_precompiled_assets + clear_precompiled_assets + end end end end From ed89ebff9c0829df13d8039cd7846df436ae3406 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 09:49:25 -0400 Subject: [PATCH 05/10] Fix rake for webpacker --- test/test_helper.rb | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 9da299b86..3e13e78e9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -64,16 +64,22 @@ def asset.fresh?(env); false; end def precompile_assets capture_io do - ENV['RAILS_GROUPS'] = 'assets' # required for Rails 3.2 - Rake::Task['assets:precompile'].reenable + # Changing directories is required because: + # - assets:precompile runs webpacker:compile when availabled + # - webpacker:compile depends on `./bin/webpack`, so `.` must be the app root + Dir.chdir("./test/dummy") do - if Rails::VERSION::MAJOR == 3 - Rake::Task['assets:precompile:all'].reenable - Rake::Task['assets:precompile:primary'].reenable - Rake::Task['assets:precompile:nondigest'].reenable - end + ENV['RAILS_GROUPS'] = 'assets' # required for Rails 3.2 + Rake::Task['assets:precompile'].reenable + + if Rails::VERSION::MAJOR == 3 + Rake::Task['assets:precompile:all'].reenable + Rake::Task['assets:precompile:primary'].reenable + Rake::Task['assets:precompile:nondigest'].reenable + end - Rake::Task['assets:precompile'].invoke + Rake::Task['assets:precompile'].invoke + end end if Rails.application.respond_to?(:assets_manifest) From e581a5f66d291f5eccdaa35268bd7aab1fbe6335 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 11:10:36 -0400 Subject: [PATCH 06/10] Ensure webpacker compiled --- test/react/rails/component_mount_test.rb | 1 + test/react/rails/controller_lifecycle_test.rb | 1 + test/react/rails/pages_controller_test.rb | 4 ++++ test/react/rails/react_rails_ujs_test.rb | 1 + .../webpacker_manifest_container_test.rb | 6 ++++++ test/support/webpacker_helpers.rb | 12 ++++++++++-- test/test_helper.rb | 2 ++ 7 files changed, 25 insertions(+), 2 deletions(-) diff --git a/test/react/rails/component_mount_test.rb b/test/react/rails/component_mount_test.rb index d603f98de..3c14a6c48 100644 --- a/test/react/rails/component_mount_test.rb +++ b/test/react/rails/component_mount_test.rb @@ -3,6 +3,7 @@ when_sprockets_available do class ComponentMountTest < ActionDispatch::IntegrationTest setup do + WebpackerHelpers.compile_if_missing @helper = React::Rails::ComponentMount.new end diff --git a/test/react/rails/controller_lifecycle_test.rb b/test/react/rails/controller_lifecycle_test.rb index 2b5c236fc..983f602d0 100644 --- a/test/react/rails/controller_lifecycle_test.rb +++ b/test/react/rails/controller_lifecycle_test.rb @@ -24,6 +24,7 @@ def react_component(*args) class ControllerLifecycleTest < ActionDispatch::IntegrationTest def setup + WebpackerHelpers.compile_if_missing @previous_helper_implementation = React::Rails::ViewHelper.helper_implementation_class React::Rails::ViewHelper.helper_implementation_class = DummyHelperImplementation end diff --git a/test/react/rails/pages_controller_test.rb b/test/react/rails/pages_controller_test.rb index 89a7743a0..45faf15ae 100644 --- a/test/react/rails/pages_controller_test.rb +++ b/test/react/rails/pages_controller_test.rb @@ -1,6 +1,10 @@ require 'test_helper' class PagesControllerTest < ActionController::TestCase + setup do + WebpackerHelpers.compile_if_missing + end + test 'renders successfully' do get :show, id: 1 assert_equal(200, response.status) diff --git a/test/react/rails/react_rails_ujs_test.rb b/test/react/rails/react_rails_ujs_test.rb index 77135068a..9aefcff9f 100644 --- a/test/react/rails/react_rails_ujs_test.rb +++ b/test/react/rails/react_rails_ujs_test.rb @@ -6,6 +6,7 @@ class ReactRailsUJSTest < ActionDispatch::IntegrationTest setup do Capybara.current_driver = Capybara.javascript_driver + WebpackerHelpers.compile_if_missing end test 'ujs object present on the global React object and has our methods' do diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index 92e304db1..65c2517f6 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -31,13 +31,19 @@ def test_it_loads_from_webpack_dev_server 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? + 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 diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index f7099af53..74990a909 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -1,4 +1,6 @@ module WebpackerHelpers + PACKS_DIRECTORY = File.expand_path("../dummy/public/packs", __FILE__) + module_function def available? defined?(Webpacker) @@ -11,6 +13,7 @@ def when_webpacker_available end def compile + return if !available? clear_webpacker_packs Dir.chdir("./test/dummy") do capture_io do @@ -22,8 +25,13 @@ def compile Webpacker::Manifest.load end + def compile_if_missing + if !File.exist?(PACKS_DIRECTORY) + compile + end + end + def clear_webpacker_packs - packs_directory = File.expand_path("../dummy/public/packs", __FILE__) - FileUtils.rm_rf(packs_directory) + FileUtils.rm_rf(PACKS_DIRECTORY) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 3e13e78e9..a1425d8b2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -20,6 +20,8 @@ require(f) end +WebpackerHelpers.clear_webpacker_packs + Capybara.javascript_driver = :poltergeist Capybara.app = Rails.application From c542b1e43f5ab404b979824bd177114dd76f3b49 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 11:39:54 -0400 Subject: [PATCH 07/10] Add debug output --- .../server_rendering/webpacker_manifest_container_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index 65c2517f6..8e910f411 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -32,6 +32,10 @@ def test_it_loads_from_webpack_dev_server 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 File.read(f) + end next end assert_includes example_asset_path, "http://localhost:8080" From 07b70315f8b16e5cbaaa375e7219ca1840b2b178 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 12:19:08 -0400 Subject: [PATCH 08/10] improve debug info, extend wait --- .../server_rendering/webpacker_manifest_container_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index 8e910f411..5efdff3ee 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -25,7 +25,7 @@ def test_it_loads_from_webpack_dev_server end detected_dev_server = false - 20.times do |i| + 60.times do |i| begin # Make sure that the manifest has been updated: Webpacker::Manifest.load("./test/dummy/public/packs/manifest.json") @@ -34,6 +34,7 @@ def test_it_loads_from_webpack_dev_server 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 From cab006de906952d26530ce9ed7d61f4ca35ce765 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 13:11:45 -0400 Subject: [PATCH 09/10] fix clear path, fix env var --- .../react/server_rendering/webpacker_manifest_container_test.rb | 2 +- test/support/webpacker_helpers.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index 5efdff3ee..e2537be88 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -20,7 +20,7 @@ class WebpackerManifestContainerTest < ActiveSupport::TestCase def test_it_loads_from_webpack_dev_server webpack_dev_server = fork do Dir.chdir("test/dummy") do - exec "./bin/webpack-dev-server RAILS_ENV=development" + exec "RAILS_ENV=development ./bin/webpack-dev-server " end end diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index 74990a909..b95f48171 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -1,5 +1,5 @@ module WebpackerHelpers - PACKS_DIRECTORY = File.expand_path("../dummy/public/packs", __FILE__) + PACKS_DIRECTORY = File.expand_path("../../dummy/public/packs", __FILE__) module_function def available? From 339799a824e2d89386b8e3ba45f19263e29fe485 Mon Sep 17 00:00:00 2001 From: Robert Mosolgo Date: Fri, 7 Apr 2017 13:38:52 -0400 Subject: [PATCH 10/10] clean up dev-server packs --- .../react/server_rendering/webpacker_manifest_container_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/react/server_rendering/webpacker_manifest_container_test.rb b/test/react/server_rendering/webpacker_manifest_container_test.rb index e2537be88..585ce4d25 100644 --- a/test/react/server_rendering/webpacker_manifest_container_test.rb +++ b/test/react/server_rendering/webpacker_manifest_container_test.rb @@ -65,6 +65,8 @@ def test_it_loads_from_webpack_dev_server ensure Process.kill(9, webpack_dev_server) Process.wait + # Remove the dev-server packs: + WebpackerHelpers.clear_webpacker_packs end end end