diff --git a/README.md b/README.md index e12e03d..0026767 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,20 @@ use Rack::LiveReload, :min_delay => 500, ... ## How it works -The necessary `script` tag to bring in a vendored copy of [livereload.js](https://github.com/livereload/livereload-js) is +The necessary `script` tag to bring in a copy of [livereload.js](https://github.com/livereload/livereload-js) is injected right before the closing `head` tag in any `text/html` pages that come through. The `script` tag is built in such a way that the `HTTP_HOST` is used as the LiveReload host, so you can connect from external machines (say, to `mycomputer:3000` instead of `localhost:3000`) and as long as the LiveReload port is accessible from the external machine, you'll connect and be LiveReloading away! +### Which LiveReload script does it use? + +* If you've got a LiveReload watcher running on the same machine as the app that responds + to `http://localhost:35729/livereload.js`, that gets used, with the hostname being changed when + injected into the HTML page. +* If you don't, the copy vendored with rack-livereload is used. +* You can force the use of either one (and save on the cost of checking to see if that file + is available) with the middleware option `:source => :vendored` or `:source => :livereload`. + As usual, super-alpha! diff --git a/lib/rack/livereload.rb b/lib/rack/livereload.rb index 09b399e..1bfefdd 100644 --- a/lib/rack/livereload.rb +++ b/lib/rack/livereload.rb @@ -1,6 +1,7 @@ module Rack class LiveReload LIVERELOAD_JS_PATH = '/__rack/livereload.js' + LIVERELOAD_LOCAL_URI = 'http://localhost:35729/livereload.js' attr_reader :app @@ -9,6 +10,31 @@ module Rack @options = options end + def use_vendored? + return @use_vendored if @use_vendored + + if @options[:source] + @use_vendored = (@options[:source] == :vendored) + else + require 'net/http' + require 'uri' + + uri = URI.parse(LIVERELOAD_LOCAL_URI) + + http = Net::HTTP.new(uri.host, uri.port) + http.read_timeout = 1 + + begin + http.send_request('GET', uri.path) + @use_vendored = false + rescue Timeout::Error, Errno::ECONNREFUSED + @use_vendored = true + end + end + + @use_vendored + end + def call(env) if env['PATH_INFO'] == LIVERELOAD_JS_PATH deliver_file(::File.expand_path('../../../js/livereload.js', __FILE__)) @@ -21,12 +47,14 @@ module Rack body.each do |line| if !headers['X-Rack-LiveReload'] && line[''] - src = LIVERELOAD_JS_PATH.dup - if @options[:host] - src << "?host=#{@options[:host]}" + host_to_use = @options[:host] || env['HTTP_HOST'].gsub(%r{:.*}, '') + + if use_vendored? + src = LIVERELOAD_JS_PATH.dup + "?host=#{host_to_use}" else - src << "?host=#{env['HTTP_HOST'].gsub(%r{:.*}, '')}" if env['HTTP_HOST'] + src = LIVERELOAD_LOCAL_URI.dup.gsub('localhost', host_to_use) + '?' end + src << "&mindelay=#{@options[:min_delay]}" if @options[:min_delay] src << "&maxdelay=#{@options[:max_delay]}" if @options[:max_delay] src << "&port=#{@options[:port]}" if @options[:port] diff --git a/rack-livereload.gemspec b/rack-livereload.gemspec index abc8bfd..8c10272 100644 --- a/rack-livereload.gemspec +++ b/rack-livereload.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |s| s.add_development_dependency "mocha" s.add_development_dependency "guard" s.add_development_dependency "guard-rspec" + s.add_development_dependency "webmock" s.add_runtime_dependency "rack" end diff --git a/spec/rack/livereload_spec.rb b/spec/rack/livereload_spec.rb index 3b1e9de..09421a7 100644 --- a/spec/rack/livereload_spec.rb +++ b/spec/rack/livereload_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Rack::LiveReload do - let(:middleware) { described_class.new(app) } + let(:middleware) { described_class.new(app, options) } let(:app) { stub } subject { middleware } @@ -9,6 +9,37 @@ describe Rack::LiveReload do its(:app) { should == app } let(:env) { {} } + let(:options) { {} } + + describe described_class::LIVERELOAD_LOCAL_URI do + context 'does not exist' do + before do + stub_request(:any, 'localhost:35729/livereload.js').to_timeout + end + + it { should use_vendored } + end + + context 'exists' do + before do + stub_request(:any, 'localhost:35729/livereload.js') + end + + it { should_not use_vendored } + end + + context 'specify vendored' do + let(:options) { { :source => :vendored } } + + it { should use_vendored } + end + + context 'specify LR' do + let(:options) { { :source => :livereload } } + + it { should_not use_vendored } + end + end context 'not text/html' do let(:ret) { [ 200, { 'Content-Type' => 'image/png' }, [ '' ] ] } @@ -25,6 +56,7 @@ describe Rack::LiveReload do context 'text/html' do before do app.stubs(:call).with(env).returns([ 200, { 'Content-Type' => 'text/html', 'Content-Length' => 0 }, [ '' ] ]) + middleware.stubs(:use_vendored?).returns(true) end let(:host) { 'host' } @@ -34,13 +66,26 @@ describe Rack::LiveReload do let(:body) { ret.last.join } let(:length) { ret[1]['Content-Length'] } - it 'should add the livereload js script tag' do - body.should include("script") - body.should include(described_class::LIVERELOAD_JS_PATH) + context 'vendored' do + it 'should add the vendored livereload js script tag' do + body.should include("script") + body.should include(described_class::LIVERELOAD_JS_PATH) - length.should == body.length.to_s + length.should == body.length.to_s - described_class::LIVERELOAD_JS_PATH.should_not include(host) + described_class::LIVERELOAD_JS_PATH.should_not include(host) + end + end + + context 'not vendored' do + before do + middleware.stubs(:use_vendored?).returns(false) + end + + it 'should add the LR livereload js script tag' do + body.should include("script") + body.should include(described_class::LIVERELOAD_LOCAL_URI.gsub('localhost', 'host')) + end end context 'set options' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 39811a9..96ab0b9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,16 @@ require 'mocha' +require 'webmock/rspec' + require 'rack-livereload' RSpec.configure do |c| c.mock_with :mocha end +module RSpec::Matchers + define :use_vendored do + match do |subject| + subject.use_vendored? + end + end +end