[Docker] `ViteRuby#dev_server_running?` always return `false` when rails and vite run in different containers with `skipProxy: true`
Is your feature request related to a problem? Please describe.
ViteRuby#dev_server_running? always return false when rails and vite run in different containers with skipProxy: true. We can't set the VITE_RUBY_HOST to the name of the vite container, since it need to be something like localhost for the dev server to be reachable from the browser, because we are skipping the proxy. With this configuration ViteRuby#dev_server_running? isn't able to resolve the dev server and assume that it is not running.
Describe the solution you'd like
One solution could be to have a config/env to set the reachable host from the backend code e.g. VITE_RUBY_HOST_FROM_BACKEND and use it here:
https://github.com/ElMassimo/vite_ruby/blob/6249f3b8385c89c6e5f05ad94384cae53d1e5b5d/vite_ruby/lib/vite_ruby.rb#L91
Describe alternatives you've considered
Instead of checking network to see if the dev server is running, maybe we could create a file somewhere when starting the dev server and remove it when closing the dev server. To know if the dev server is running we check if the file exist or not, but that solution come with other issues.
Additional context
Here's a monkey patch we are using to bypass the current limitation:
module MonkeypatchDevServerRunning
module InstanceMethods
# original method: https://github.com/ElMassimo/vite_ruby/blob/6249f3b8385c89c6e5f05ad94384cae53d1e5b5d/vite_ruby/lib/vite_ruby.rb#L84-L98
def dev_server_running?
return super unless config.skip_proxy
return false unless run_proxy?
return @running if defined?(@running) && Time.now - @running_checked_at < 1
begin
Socket.tcp(ENV["VITE_RUBY_HOST_FROM_BACKEND"] || config.host, config.port, connect_timeout: config.dev_server_connect_timeout).close
@running = true
rescue StandardError
@running = false
ensure
@running_checked_at = Time.now
end
end
end
class << self
def apply_patch
const = find_const
mtd = find_method(const)
unless const && mtd && mtd.arity == 0
raise "Could not find class or method when patching ViteRuby#dev_server_running?. Please investigate."
end
unless vite_ruby_version_ok?
puts "WARNING: It looks like ViteRuby has been upgraded since ViteRuby#dev_server_running? was monkeypatched in #{__FILE__}. Please reevaluate the patch."
end
const.prepend(InstanceMethods)
end
private
def find_const
Kernel.const_get('ViteRuby')
rescue NameError
end
def find_method(const)
return unless const
const.instance_method(:dev_server_running?)
rescue NameError
end
def vite_ruby_version_ok?
version = Gem::Version.create(ViteRuby::VERSION)
# The skipProxy config was added in version 3.2.12
# see: https://github.com/ElMassimo/vite_ruby/compare/[email protected][email protected]
version >= "3.2.12" && version < "4.0.0"
end
end
end
# ...
MonkeypatchDevServerRunning.apply_patch
I recently migrated to Vite and faces the same issue, but my solution was different - not to rely on autoBuild at any point, which imho is better to be disabled. Posting my setup for consideration:
- I'm always running Vite server manually in a different container, so my
autoBuildis set to false inconfig/vite.json - In dev I'm always running vite server in a separate container, so
dev_server_running?can be monkey patched to returnRails.env.development? - For tests in my
test_helper.rbI'm building all assets upfront if they are stale (checkingViteRuby.instance.builder.last_build_metadata.stale?) - Not using the proxy middleware in dev, hitting Vite's server directly
That being said, I agree that there should be a way to set something like VITE_RUBY_HOST_FROM_BACKEND to keep autoBuild working correctly.