Skip to content

Commit 077a610

Browse files
justin808claude
andcommitted
Fix server bundle path resolution in test environments (#1797)
- Fix fallback logic when manifest lookup fails to check multiple locations - Try environment-specific path, standard location (public/packs), then generated assets path - Return first path where bundle file actually exists - Maintains backward compatibility with original behavior as final fallback - Add comprehensive test cases to prevent regression Fixes issue where server rendering failed in test environments when bundles were in standard Shakapacker location but manifest lookup pointed to environment-specific directory. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 32d4665 commit 077a610

File tree

3 files changed

+81
-5
lines changed

3 files changed

+81
-5
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
react_on_rails (16.0.1.rc.0)
4+
react_on_rails (16.0.1.rc.2)
55
addressable
66
connection_pool
77
execjs (~> 2.5)

lib/react_on_rails/utils.rb

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,24 @@ def self.bundle_js_file_path(bundle_name)
8484
rescue Object.const_get(
8585
ReactOnRails::PackerUtils.packer_type.capitalize
8686
)::Manifest::MissingEntryError
87-
File.expand_path(
88-
File.join(ReactOnRails::PackerUtils.packer_public_output_path,
89-
bundle_name)
90-
)
87+
# When manifest lookup fails, try multiple fallback locations:
88+
# 1. Environment-specific path (e.g., public/webpack/test)
89+
# 2. Standard Shakapacker location (public/packs)
90+
# 3. Generated assets path (for legacy setups)
91+
fallback_locations = [
92+
File.join(ReactOnRails::PackerUtils.packer_public_output_path, bundle_name),
93+
File.join("public", "packs", bundle_name),
94+
File.join(generated_assets_full_path, bundle_name)
95+
].uniq
96+
97+
# Return the first location where the bundle file actually exists
98+
fallback_locations.each do |path|
99+
expanded_path = File.expand_path(path)
100+
return expanded_path if File.exist?(expanded_path)
101+
end
102+
103+
# If none exist, return the environment-specific path (original behavior)
104+
File.expand_path(fallback_locations.first)
91105
end
92106
else
93107
# Default to the non-hashed name in the specified output directory, which, for legacy

spec/react_on_rails/utils_spec.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,32 @@ def mock_dev_server_running
134134

135135
it { is_expected.to eq("#{packer_public_output_path}/manifest.json") }
136136
end
137+
138+
context "when file not in manifest and fallback to standard location" do
139+
before do
140+
mock_missing_manifest_entry("webpack-bundle.js")
141+
end
142+
143+
let(:standard_path) { File.expand_path(File.join("public", "packs", "webpack-bundle.js")) }
144+
let(:env_specific_path) { File.join(packer_public_output_path, "webpack-bundle.js") }
145+
146+
it "returns standard path when bundle exists there" do
147+
allow(File).to receive(:exist?).and_call_original
148+
allow(File).to receive(:exist?).with(File.expand_path(env_specific_path)).and_return(false)
149+
allow(File).to receive(:exist?).with(standard_path).and_return(true)
150+
151+
result = described_class.bundle_js_file_path("webpack-bundle.js")
152+
expect(result).to eq(standard_path)
153+
end
154+
155+
it "returns environment-specific path when no bundle exists anywhere" do
156+
allow(File).to receive(:exist?).and_call_original
157+
allow(File).to receive(:exist?).and_return(false)
158+
159+
result = described_class.bundle_js_file_path("webpack-bundle.js")
160+
expect(result).to eq(File.expand_path(env_specific_path))
161+
end
162+
end
137163
end
138164
end
139165

@@ -189,6 +215,42 @@ def mock_dev_server_running
189215

190216
expect(path).to end_with("public/webpack/development/#{server_bundle_name}")
191217
end
218+
219+
context "with bundle file existing in standard location but not environment-specific location" do
220+
it "returns the standard location path" do
221+
server_bundle_name = "server-bundle.js"
222+
mock_bundle_configs(server_bundle_name: server_bundle_name)
223+
mock_missing_manifest_entry(server_bundle_name)
224+
225+
# Mock File.exist? to return false for environment-specific path but true for standard path
226+
standard_path = File.expand_path(File.join("public", "packs", server_bundle_name))
227+
env_specific_path = File.join(packer_public_output_path, server_bundle_name)
228+
229+
allow(File).to receive(:exist?).and_call_original
230+
allow(File).to receive(:exist?).with(File.expand_path(env_specific_path)).and_return(false)
231+
allow(File).to receive(:exist?).with(standard_path).and_return(true)
232+
233+
path = described_class.server_bundle_js_file_path
234+
235+
expect(path).to eq(standard_path)
236+
end
237+
end
238+
239+
context "with bundle file not existing in any fallback location" do
240+
it "returns the environment-specific path as final fallback" do
241+
server_bundle_name = "server-bundle.js"
242+
mock_bundle_configs(server_bundle_name: server_bundle_name)
243+
mock_missing_manifest_entry(server_bundle_name)
244+
245+
# Mock File.exist? to return false for all paths
246+
allow(File).to receive(:exist?).and_call_original
247+
allow(File).to receive(:exist?).and_return(false)
248+
249+
path = described_class.server_bundle_js_file_path
250+
251+
expect(path).to end_with("public/webpack/development/#{server_bundle_name}")
252+
end
253+
end
192254
end
193255

194256
context "with server file in the manifest, used for client", packer_type.to_sym do

0 commit comments

Comments
 (0)