detection and use of local livereload if available

This commit is contained in:
John Bintz 2011-11-08 09:48:34 -05:00
parent 38a3396cf2
commit 92479fdaff
5 changed files with 103 additions and 11 deletions

View File

@ -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!

View File

@ -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['</head>']
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]

View File

@ -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

View File

@ -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' }, [ '<head></head>' ] ] }
@ -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 }, [ '<head></head>' ] ])
middleware.stubs(:use_vendored?).returns(true)
end
let(:host) { 'host' }
@ -34,7 +66,8 @@ describe Rack::LiveReload do
let(:body) { ret.last.join }
let(:length) { ret[1]['Content-Length'] }
it 'should add the livereload js script tag' do
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)
@ -42,6 +75,18 @@ describe Rack::LiveReload do
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
let(:middleware) { described_class.new(app, :host => new_host, :port => port, :min_delay => min_delay, :max_delay => max_delay) }

View File

@ -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