diff --git a/lib/react_on_rails/packer_utils.rb b/lib/react_on_rails/packer_utils.rb index 97999fe5e..df71afd4b 100644 --- a/lib/react_on_rails/packer_utils.rb +++ b/lib/react_on_rails/packer_utils.rb @@ -45,6 +45,10 @@ def self.dev_server_running? packer.dev_server.running? end + def self.dev_server_url + "#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}" + end + def self.shakapacker_version return @shakapacker_version if defined?(@shakapacker_version) return nil unless ReactOnRails::Utils.gem_available?("shakapacker") @@ -79,12 +83,27 @@ def self.bundle_js_uri_from_packer(bundle_name) if packer.dev_server.running? && (!is_bundle_running_on_server || ReactOnRails.configuration.same_bundle_for_client_and_server) - "#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}#{hashed_bundle_name}" + "#{dev_server_url}#{hashed_bundle_name}" else File.expand_path(File.join("public", hashed_bundle_name)).to_s end end + def self.public_output_uri_path + "#{packer.config.public_output_path.relative_path_from(packer.config.public_path)}/" + end + + # The function doesn't ensure that the asset exists. + # - It just returns url to the asset if dev server is running + # - Otherwise it returns file path to the asset + def self.asset_uri_from_packer(asset_name) + if dev_server_running? + "#{dev_server_url}/#{public_output_uri_path}#{asset_name}" + else + File.join(packer_public_output_path, asset_name).to_s + end + end + def self.precompile? return ::Webpacker.config.webpacker_precompile? if using_webpacker_const? return ::Shakapacker.config.shakapacker_precompile? if using_shakapacker_const? diff --git a/lib/react_on_rails/utils.rb b/lib/react_on_rails/utils.rb index 430c10a3d..c1a794a8f 100644 --- a/lib/react_on_rails/utils.rb +++ b/lib/react_on_rails/utils.rb @@ -113,7 +113,11 @@ def self.react_client_manifest_file_path return @react_client_manifest_path if @react_client_manifest_path && !Rails.env.development? file_name = ReactOnRails.configuration.react_client_manifest_file - @react_client_manifest_path = bundle_js_file_path(file_name) + @react_client_manifest_path = if ReactOnRails::PackerUtils.using_packer? + ReactOnRails::PackerUtils.asset_uri_from_packer(file_name) + else + File.join(generated_assets_full_path, file_name) + end end def self.running_on_windows? diff --git a/spec/react_on_rails/packer_utils_spec.rb b/spec/react_on_rails/packer_utils_spec.rb index b7bd4f2e5..767837483 100644 --- a/spec/react_on_rails/packer_utils_spec.rb +++ b/spec/react_on_rails/packer_utils_spec.rb @@ -35,5 +35,46 @@ module ReactOnRails expect(described_class.shakapacker_version_requirement_met?(minimum_version)).to be(true) end end + + describe ".asset_uri_from_packer" do + let(:asset_name) { "test-asset.js" } + let(:public_output_path) { "/path/to/public/webpack/dev" } + + context "when dev server is running" do + before do + allow(described_class.packer).to receive(:dev_server).and_return( + instance_double( + Shakapacker::DevServer, + running?: true, + protocol: "http", + host_with_port: "localhost:3035" + ) + ) + + allow(described_class.packer).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(public_output_path)) + allow(described_class.packer).to receive_message_chain("config.public_path") + .and_return(Pathname.new("/path/to/public")) + end + + it "returns asset URL with dev server path" do + expected_url = "http://localhost:3035/webpack/dev/test-asset.js" + expect(described_class.asset_uri_from_packer(asset_name)).to eq(expected_url) + end + end + + context "when dev server is not running" do + before do + allow(described_class.packer).to receive_message_chain("dev_server.running?").and_return(false) + allow(described_class.packer).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(public_output_path)) + end + + it "returns file path to the asset" do + expected_path = File.join(public_output_path, asset_name) + expect(described_class.asset_uri_from_packer(asset_name)).to eq(expected_path) + end + end + end end end diff --git a/spec/react_on_rails/utils_spec.rb b/spec/react_on_rails/utils_spec.rb index d87873ef0..eecc7d009 100644 --- a/spec/react_on_rails/utils_spec.rb +++ b/spec/react_on_rails/utils_spec.rb @@ -493,6 +493,73 @@ def mock_dev_server_running end end end + + describe ".react_client_manifest_file_path" do + before do + described_class.instance_variable_set(:@react_client_manifest_path, nil) + allow(ReactOnRails.configuration).to receive(:react_client_manifest_file) + .and_return("react-client-manifest.json") + end + + after do + described_class.instance_variable_set(:@react_client_manifest_path, nil) + end + + context "when using packer" do + let(:public_output_path) { "/path/to/public/webpack/dev" } + + before do + allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(true) + allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(public_output_path)) + allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_path") + .and_return(Pathname.new("/path/to/public")) + end + + context "when dev server is running" do + before do + allow(ReactOnRails::PackerUtils.packer).to receive(:dev_server).and_return( + instance_double( + Object.const_get(ReactOnRails::PackerUtils.packer_type.capitalize)::DevServer, + running?: true, + protocol: "http", + host_with_port: "localhost:3035" + ) + ) + end + + it "returns manifest URL with dev server path" do + expected_url = "http://localhost:3035/webpack/dev/react-client-manifest.json" + expect(described_class.react_client_manifest_file_path).to eq(expected_url) + end + end + + context "when dev server is not running" do + before do + allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?") + .and_return(false) + end + + it "returns file path to the manifest" do + expected_path = File.join(public_output_path, "react-client-manifest.json") + expect(described_class.react_client_manifest_file_path).to eq(expected_path) + end + end + end + + context "when not using packer" do + before do + allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(false) + allow(described_class).to receive(:generated_assets_full_path) + .and_return("/path/to/generated/assets") + end + + it "returns joined path with generated_assets_full_path" do + expect(described_class.react_client_manifest_file_path) + .to eq("/path/to/generated/assets/react-client-manifest.json") + end + end + end end end # rubocop:enable Metrics/ModuleLength, Metrics/BlockLength