Skip to content

Commit c001a41

Browse files
authored
Merge pull request #687 from reactjs/support-webpack-dev-server
Support server-rendering from webpack-dev-server
2 parents e2fe21f + 3532fc5 commit c001a41

File tree

7 files changed

+106
-53
lines changed

7 files changed

+106
-53
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ rvm:
1010
- jruby-9.0.1.0
1111

1212
gemfile:
13+
# These have webpacker:
14+
- gemfiles/rails_4.2_sprockets_4.gemfile
15+
- gemfiles/rails_5_no_sprockets_webpacker.gemfile
16+
# These don't have webpacker:
1317
- gemfiles/rails_3.2.gemfile
1418
- gemfiles/rails_4.0.5.gemfile
1519
- gemfiles/rails_4.0_with_therubyracer.gemfile
1620
- gemfiles/rails_4.1.gemfile
1721
- gemfiles/rails_4.2_sprockets_2.gemfile
1822
- gemfiles/rails_4.2_sprockets_3.gemfile
19-
- gemfiles/rails_4.2_sprockets_4.gemfile
20-
- gemfiles/rails_5_no_sprockets_webpacker.gemfile
2123
- gemfiles/rails_5_no_sprockets.gemfile
2224
- gemfiles/rails_5_sprockets_4.gemfile
2325

lib/react/server_rendering/webpacker_manifest_container.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
module React
44
module ServerRendering
5+
CLIENT_REQUIRE = %r{__webpack_require__\(.*webpack-dev-server\/client\/index\.js.*\n}
6+
57
# Get a compiled file from Webpacker
68
class WebpackerManifestContainer
79
def find_asset(logical_path)
810
asset_path = Webpacker::Manifest.lookup(logical_path) # raises if not found
911
if asset_path.start_with?("http")
10-
# TODO: this includes webpack-dev-server code which causes ExecJS to 💥
12+
# this includes `webpack-dev-server/client/index.js` code which causes ExecJS to 💥
1113
dev_server_asset = open(asset_path).read
14+
dev_server_asset.sub!(CLIENT_REQUIRE, '//\0')
15+
dev_server_asset
1216
else
1317
full_path = File.join(
1418
# TODO: using `.parent` here won't work for nonstandard configurations

test/dummy/app/javascript/components/GreetingMessage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = React.createClass({
1616
},
1717
render: function() {
1818
return React.DOM.div({},
19-
React.DOM.div({}, this.state.greeting, ' ', this.props.name),
19+
React.DOM.div({}, this.state.greeting, ' from Webpacker ', this.props.name ),
2020
React.DOM.button({onClick: this.goodbye}, 'Goodbye')
2121
);
2222
}

test/react/rails/pages_controller_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,15 @@ class PagesControllerTest < ActionController::TestCase
2525
assert_includes(response.body, "Hello")
2626
end
2727
end
28+
29+
WebpackerHelpers.when_webpacker_available do
30+
test "it mounts components from the dev server" do
31+
WebpackerHelpers.with_dev_server do
32+
get :show, id: 1, prerender: true
33+
assert_match /Hello<!--.*--> from Webpacker/, response.body
34+
get :show, id: 1, prerender: true, greeting: "Howdy"
35+
assert_match /Howdy<!--.*--> from Webpacker/, response.body
36+
end
37+
end
38+
end
2839
end

test/react/rails/webpacker_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest
1313
WebpackerHelpers.clear_webpacker_packs
1414
end
1515

16-
test 'it mounts pages from the pack' do
16+
test 'it mounts components from the pack' do
1717
visit '/pack_component'
1818
assert page.has_content?('Export Default')
1919
assert page.has_content?('Named Export')

test/react/server_rendering/webpacker_manifest_container_test.rb

Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,55 +18,14 @@ class WebpackerManifestContainerTest < ActiveSupport::TestCase
1818
end
1919

2020
def test_it_loads_from_webpack_dev_server
21-
webpack_dev_server = fork do
22-
Dir.chdir("test/dummy") do
23-
exec "RAILS_ENV=development ./bin/webpack-dev-server "
24-
end
21+
WebpackerHelpers.with_dev_server do
22+
container = React::ServerRendering::WebpackerManifestContainer.new
23+
js_file = container.find_asset("application.js")
24+
# Main file:
25+
assert_includes js_file, "ReactRailsUJS.loadContext(ctx)"
26+
# Bundled dependencies:
27+
assert_includes js_file, "ExportDefaultComponent"
2528
end
26-
27-
detected_dev_server = false
28-
60.times do |i|
29-
begin
30-
# Make sure that the manifest has been updated:
31-
Webpacker::Manifest.load("./test/dummy/public/packs/manifest.json")
32-
webpack_manifest = Webpacker::Manifest.instance.data
33-
example_asset_path = webpack_manifest.values.first
34-
if example_asset_path.nil?
35-
puts "Manifest is blank, all manifests:"
36-
Dir.glob("./test/dummy/public/packs/*.json").each do |f|
37-
puts f
38-
puts File.read(f)
39-
end
40-
next
41-
end
42-
assert_includes example_asset_path, "http://localhost:8080"
43-
# Make sure the dev server is up:
44-
open("http://localhost:8080/application.js")
45-
detected_dev_server = true
46-
break
47-
rescue StandardError => err
48-
puts err.message
49-
ensure
50-
sleep 0.5
51-
puts i
52-
end
53-
end
54-
55-
# If we didn't hook up with a dev server after 10s,
56-
# fail loudly.
57-
assert detected_dev_server
58-
59-
container = React::ServerRendering::WebpackerManifestContainer.new
60-
js_file = container.find_asset("application.js")
61-
# Main file:
62-
assert_includes js_file, "ReactRailsUJS.loadContext(ctx)"
63-
# Bundled dependencies:
64-
assert_includes js_file, "ExportDefaultComponent"
65-
ensure
66-
Process.kill(9, webpack_dev_server)
67-
Process.wait
68-
# Remove the dev-server packs:
69-
WebpackerHelpers.clear_webpacker_packs
7029
end
7130
end
7231
end

test/support/webpacker_helpers.rb

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,81 @@ def compile_if_missing
3434
def clear_webpacker_packs
3535
FileUtils.rm_rf(PACKS_DIRECTORY)
3636
end
37+
38+
# Start a webpack-dev-server
39+
# Call the block
40+
# Make sure to clean up the server
41+
def with_dev_server
42+
# Start the server in a forked process:
43+
webpack_dev_server = Dir.chdir("test/dummy") do
44+
spawn "RAILS_ENV=development ./bin/webpack-dev-server "
45+
end
46+
47+
detected_dev_server = false
48+
49+
# Wait for it to start up, make sure it's there by connecting to it:
50+
30.times do |i|
51+
begin
52+
# Make sure that the manifest has been updated:
53+
Webpacker::Manifest.load("./test/dummy/public/packs/manifest.json")
54+
webpack_manifest = Webpacker::Manifest.instance.data
55+
example_asset_path = webpack_manifest.values.first
56+
if example_asset_path.nil?
57+
# Debug helper
58+
# puts "Manifest is blank, all manifests:"
59+
# Dir.glob("./test/dummy/public/packs/*.json").each do |f|
60+
# puts f
61+
# puts File.read(f)
62+
# end
63+
next
64+
end
65+
# Make sure the dev server is up:
66+
open("http://localhost:8080/application.js")
67+
if !example_asset_path.start_with?("http://localhost:8080")
68+
raise "Manifest doesn't include absolute path to dev server"
69+
end
70+
71+
detected_dev_server = true
72+
break
73+
rescue StandardError => err
74+
puts err.message
75+
ensure
76+
sleep 0.5
77+
# debug counter
78+
# puts i
79+
end
80+
end
81+
82+
# If we didn't hook up with a dev server after waiting, fail loudly.
83+
if !detected_dev_server
84+
raise "Failed to start dev server"
85+
end
86+
87+
# Call the test block:
88+
yield
89+
ensure
90+
# Kill the server process
91+
# puts "Killing webpack dev server"
92+
check_cmd = "lsof -i :8080 -S"
93+
10.times do
94+
# puts check_cmd
95+
status = `#{check_cmd}`
96+
# puts status
97+
remaining_pid_match = status.match(/\n[a-z]+\s+(\d+)/)
98+
if remaining_pid_match
99+
remaining_pid = remaining_pid_match[1]
100+
# puts "Remaining #{remaining_pid}"
101+
kill_cmd = "kill -9 #{remaining_pid}"
102+
# puts kill_cmd
103+
`#{kill_cmd}`
104+
sleep 0.5
105+
else
106+
break
107+
end
108+
end
109+
110+
# Remove the dev-server packs:
111+
WebpackerHelpers.clear_webpacker_packs
112+
# puts "Killed."
113+
end
37114
end

0 commit comments

Comments
 (0)