Skip to content

Commit

Permalink
Replace the rack-livereload gem with own middleware
Browse files Browse the repository at this point in the history
This also patches livereload to only reload the page if it changed. (When changing a layout nanoc can send dozens of URLs for changed pages, this ensures we only reload once.)

Co-authored-by: Jan M. Faber <[email protected]>
Co-authored-by: Denis Defreyne <[email protected]>
  • Loading branch information
Fjan and denisdefreyne committed Sep 29, 2024
1 parent 85c5c96 commit e2b15cd
Show file tree
Hide file tree
Showing 10 changed files with 1,138 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ It takes the following options:
## Contributors

- Ed Brannin
- Jan M. Faber
- Larissa Reis
- Mark Meves
- Vipul Amler
Expand Down
1 change: 0 additions & 1 deletion adsf-live/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Rake::TestTask.new(:test) do |t|
t.test_files = Dir[__dir__ + '/test/**/test_*.rb']
t.libs << 'test'
t.verbose = false
t.warning = false # TODO: turn this back on when rack-livereload is fixed
end

task :gem do
Expand Down
1 change: 0 additions & 1 deletion adsf-live/adsf-live.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Gem::Specification.new do |s|
s.add_dependency('em-websocket', '~> 0.5')
s.add_dependency('eventmachine', '~> 1.2')
s.add_dependency('listen', '~> 3.0')
s.add_dependency('rack-livereload', '~> 0.3')

s.files = ['NEWS.md', 'README.md'] + Dir['lib/**/*.rb']
s.require_path = 'lib'
Expand Down
1 change: 1 addition & 0 deletions adsf-live/adsf-live.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ README.md

lib/adsf/live.rb
lib/adsf/live/version.rb
lib/adsf/live/rack_livereload.rb
lib/adsf/live/watcher.rb
lib/adsf/live/web_socket_server.rb
2 changes: 1 addition & 1 deletion adsf-live/lib/adsf/live.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
require 'em-websocket'
require 'json'
require 'listen'
require 'rack-livereload'

module Adsf
module Live
end
end

require_relative 'live/version'
require_relative 'live/rack_livereload'
require_relative 'live/web_socket_server'
require_relative 'live/watcher'
74 changes: 74 additions & 0 deletions adsf-live/lib/adsf/live/rack_livereload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

module Rack
class LiveReload
LIVERELOAD_JS_PATH = '/__rack/livereload.js'
VENDORED_JS_PATH = "#{__dir__}/../../../vendor/livereload.js"
HEAD_TAG_REGEX = /<head( [^<]+)?>/.freeze
LIVERELOAD_PORT = 35_729
LIVERELOAD_SCHEME = 'ws'

def initialize(app, options = {})
@app = app
@options = options
end

def call(env)
return deliver_file(VENDORED_JS_PATH) if env['PATH_INFO']&.end_with? LIVERELOAD_JS_PATH

status, headers, body = result = @app.call(env)

if env['REQUEST_METHOD'] != 'GET' ||
headers['content-type'] !~ %r{text/html} ||
headers['transfer-encoding'] == 'chunked' ||
headers['content-disposition'] =~ /^inline/
return result
end

body.close if body.respond_to?(:close)
new_body = []
livereload_added = false
@env = env
body.each do |line|
if !livereload_added && line =~ HEAD_TAG_REGEX
new_body << line.sub(HEAD_TAG_REGEX) { |match| %(#{match}#{template}) }
livereload_added = true
else
new_body << line
end
end
headers['content-length'] = new_body.sum(&:bytesize).to_s
headers['x-rack-livereload'] = '1' if livereload_added

[status, headers, new_body]
end

private

def deliver_file(file)
[200, { 'content-type' => 'text/javascript', 'content-length' => ::File.size(file).to_s }, [::File.read(file)]]
end

def template
<<~HTML
<script>
RACK_LIVERELOAD_PORT = #{@options[:live_reload_port] || LIVERELOAD_PORT}
RACK_LIVERELOAD_SCHEME = "#{@options[:live_reload_scheme] || LIVERELOAD_SCHEME}"
</script>
<script src="#{livereload_source}?host=#{host_to_use}"></script>
HTML
end

def livereload_source
if @options[:source] == :vendored
LIVERELOAD_JS_PATH
else
"#{@options[:protocol] || 'http'}://#{host_to_use}/livereload.js"
end
end

def host_to_use
(@options[:host] || @env['HTTP_HOST'] || 'localhost').sub(/:.*/, '')
end
end
end
2 changes: 1 addition & 1 deletion adsf-live/lib/adsf/live/web_socket_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def reload(paths)
data =
JSON.dump(
command: 'reload',
path: "#{Dir.pwd}#{path}",
path: path,
)

@sockets.each { |ws| ws.send(data) }
Expand Down
2 changes: 1 addition & 1 deletion adsf-live/test/test_watcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_receives_update
assert_equal expected_hello_data, JSON.parse(messages[0])

assert_equal 'reload', JSON.parse(messages[1])['command']
assert_match %r{adsf(-live)?/tmp/index\.html$}, JSON.parse(messages[1])['path']
assert_equal '/index.html', JSON.parse(messages[1])['path']
end
end
end
Loading

0 comments on commit e2b15cd

Please sign in to comment.