Skip to content

Commit 4e89e93

Browse files
feat: Improve client manifest path handling for dev server
- Add `dev_server_url` helper to centralize dev server URL construction - Add `public_output_uri_path` to get relative webpack output path - Add `asset_uri_from_packer` to handle asset URIs consistently - Update `react_client_manifest_file_path` to return dev server URLs when appropriate - Add comprehensive specs for new asset URI handling This change ensures client manifest paths are properly resolved to dev server URLs during development, improving hot-reloading functionality.
1 parent 838a6e7 commit 4e89e93

File tree

4 files changed

+133
-2
lines changed

4 files changed

+133
-2
lines changed

lib/react_on_rails/packer_utils.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ def self.dev_server_running?
4545
packer.dev_server.running?
4646
end
4747

48+
def self.dev_server_url
49+
"#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}"
50+
end
51+
4852
def self.shakapacker_version
4953
return @shakapacker_version if defined?(@shakapacker_version)
5054
return nil unless ReactOnRails::Utils.gem_available?("shakapacker")
@@ -79,12 +83,27 @@ def self.bundle_js_uri_from_packer(bundle_name)
7983

8084
if packer.dev_server.running? && (!is_bundle_running_on_server ||
8185
ReactOnRails.configuration.same_bundle_for_client_and_server)
82-
"#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}#{hashed_bundle_name}"
86+
"#{dev_server_url}#{hashed_bundle_name}"
8387
else
8488
File.expand_path(File.join("public", hashed_bundle_name)).to_s
8589
end
8690
end
8791

92+
def self.public_output_uri_path
93+
"#{packer.config.public_output_path.relative_path_from(packer.config.public_path)}/"
94+
end
95+
96+
# The function doesn't ensure that the asset exists.
97+
# - It just returns url to the asset if dev server is running
98+
# - Otherwise it returns file path to the asset
99+
def self.asset_uri_from_packer(asset_name)
100+
if dev_server_running?
101+
"#{dev_server_url}/#{public_output_uri_path}#{asset_name}"
102+
else
103+
File.join(packer_public_output_path, asset_name).to_s
104+
end
105+
end
106+
88107
def self.precompile?
89108
return ::Webpacker.config.webpacker_precompile? if using_webpacker_const?
90109
return ::Shakapacker.config.shakapacker_precompile? if using_shakapacker_const?

lib/react_on_rails/utils.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ def self.react_client_manifest_file_path
113113
return @react_client_manifest_path if @react_client_manifest_path && !Rails.env.development?
114114

115115
file_name = ReactOnRails.configuration.react_client_manifest_file
116-
@react_client_manifest_path = bundle_js_file_path(file_name)
116+
@react_client_manifest_path = if ReactOnRails::PackerUtils.using_packer?
117+
ReactOnRails::PackerUtils.asset_uri_from_packer(file_name)
118+
else
119+
File.join(generated_assets_full_path, file_name)
120+
end
117121
end
118122

119123
def self.running_on_windows?

spec/react_on_rails/packer_utils_spec.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,46 @@ module ReactOnRails
3535
expect(described_class.shakapacker_version_requirement_met?(minimum_version)).to be(true)
3636
end
3737
end
38+
39+
describe ".asset_uri_from_packer" do
40+
let(:asset_name) { "test-asset.js" }
41+
let(:public_output_path) { "/path/to/public/webpack/dev" }
42+
43+
context "when dev server is running" do
44+
before do
45+
allow(described_class.packer).to receive(:dev_server).and_return(
46+
instance_double(
47+
Shakapacker::DevServer,
48+
running?: true,
49+
protocol: "http",
50+
host_with_port: "localhost:3035"
51+
)
52+
)
53+
54+
allow(described_class.packer).to receive_message_chain("config.public_output_path")
55+
.and_return(Pathname.new(public_output_path))
56+
allow(described_class.packer).to receive_message_chain("config.public_path")
57+
.and_return(Pathname.new("/path/to/public"))
58+
end
59+
60+
it "returns asset URL with dev server path" do
61+
expected_url = "http://localhost:3035/webpack/dev/test-asset.js"
62+
expect(described_class.asset_uri_from_packer(asset_name)).to eq(expected_url)
63+
end
64+
end
65+
66+
context "when dev server is not running" do
67+
before do
68+
allow(described_class.packer).to receive_message_chain("dev_server.running?").and_return(false)
69+
allow(described_class.packer).to receive_message_chain("config.public_output_path")
70+
.and_return(Pathname.new(public_output_path))
71+
end
72+
73+
it "returns file path to the asset" do
74+
expected_path = File.join(public_output_path, asset_name)
75+
expect(described_class.asset_uri_from_packer(asset_name)).to eq(expected_path)
76+
end
77+
end
78+
end
3879
end
3980
end

spec/react_on_rails/utils_spec.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,73 @@ def mock_dev_server_running
493493
end
494494
end
495495
end
496+
497+
describe ".react_client_manifest_file_path" do
498+
before do
499+
described_class.instance_variable_set(:@react_client_manifest_path, nil)
500+
allow(ReactOnRails.configuration).to receive(:react_client_manifest_file)
501+
.and_return("react-client-manifest.json")
502+
end
503+
504+
after do
505+
described_class.instance_variable_set(:@react_client_manifest_path, nil)
506+
end
507+
508+
context "when using packer" do
509+
let(:public_output_path) { "/path/to/public/webpack/dev" }
510+
511+
before do
512+
allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(true)
513+
allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_output_path")
514+
.and_return(Pathname.new(public_output_path))
515+
allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_path")
516+
.and_return(Pathname.new("/path/to/public"))
517+
end
518+
519+
context "when dev server is running" do
520+
before do
521+
allow(ReactOnRails::PackerUtils.packer).to receive(:dev_server).and_return(
522+
instance_double(
523+
Object.const_get(ReactOnRails::PackerUtils.packer_type.capitalize)::DevServer,
524+
running?: true,
525+
protocol: "http",
526+
host_with_port: "localhost:3035"
527+
)
528+
)
529+
end
530+
531+
it "returns manifest URL with dev server path" do
532+
expected_url = "http://localhost:3035/webpack/dev/react-client-manifest.json"
533+
expect(described_class.react_client_manifest_file_path).to eq(expected_url)
534+
end
535+
end
536+
537+
context "when dev server is not running" do
538+
before do
539+
allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?")
540+
.and_return(false)
541+
end
542+
543+
it "returns file path to the manifest" do
544+
expected_path = File.join(public_output_path, "react-client-manifest.json")
545+
expect(described_class.react_client_manifest_file_path).to eq(expected_path)
546+
end
547+
end
548+
end
549+
550+
context "when not using packer" do
551+
before do
552+
allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(false)
553+
allow(described_class).to receive(:generated_assets_full_path)
554+
.and_return("/path/to/generated/assets")
555+
end
556+
557+
it "returns joined path with generated_assets_full_path" do
558+
expect(described_class.react_client_manifest_file_path)
559+
.to eq("/path/to/generated/assets/react-client-manifest.json")
560+
end
561+
end
562+
end
496563
end
497564
end
498565
# rubocop:enable Metrics/ModuleLength, Metrics/BlockLength

0 commit comments

Comments
 (0)