jekyll-livereload 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ require 'jekyll'
2
+
3
+ module Jekyll
4
+ module Livereload
5
+ LIVERELOAD_PORT = 35729
6
+ LIVERELOAD_DIR = File.expand_path("../js", File.dirname(__FILE__))
7
+
8
+ class << self
9
+ attr_accessor(:pages, :reactor)
10
+ def pages
11
+ @pages ||= []
12
+ end
13
+ end
14
+
15
+ require "jekyll-livereload/build"
16
+ require "jekyll-livereload/serve"
17
+ require "jekyll-livereload/version"
18
+ require "jekyll-livereload/websocket"
19
+ end
20
+ end
21
+
22
+ # Add livereload support the Jekyll
23
+ class << Jekyll::Commands::Serve
24
+ prepend Jekyll::Livereload::Serve
25
+ end
26
+
27
+ class << Jekyll::Commands::Build
28
+ prepend Jekyll::Livereload::Build
29
+ end
@@ -0,0 +1,35 @@
1
+ require 'json'
2
+
3
+ # Register Hooks, if livereload is enabled
4
+ module Jekyll
5
+ module Livereload
6
+ module Build
7
+ def process(opts)
8
+ opts['host'] = 'localhost' unless opts.key?('host')
9
+ opts['reload_port'] = Livereload::LIVERELOAD_PORT unless opts.key?('reload_port')
10
+ if opts['livereload']
11
+ Jekyll::Hooks.register(:site, :post_render) do |site|
12
+ regenerator = Jekyll::Regenerator.new(site)
13
+ Livereload.pages = site.pages.select do |p|
14
+ regenerator.regenerate?(p)
15
+ end
16
+ end
17
+ Jekyll::Hooks.register([:pages, :documents], :post_render) do |doc|
18
+ doc.output.sub!(/<head>(.*)<\/head>/m, "<head>\\1#{reload_script(opts)}</head>")
19
+ end
20
+ Jekyll::Hooks.register :site, :post_write do
21
+ Livereload.reactor.reload() unless Livereload.reactor.nil?
22
+ end
23
+ end
24
+
25
+ super opts
26
+ end
27
+
28
+ private
29
+ def reload_script(opts)
30
+ "<script src=\"http://#{opts['host']}:#{opts['reload_port']}/livereload.js\"></script>"
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # Allows us to add more option parameter to the serve command
2
+ module Mercenary
3
+ class Command
4
+ def command(cmd_name)
5
+ Jekyll.logger.debug "Refined Command"
6
+ cmd = @commands[cmd_name] || Command.new(cmd_name, self)
7
+ yield cmd
8
+ @commands[cmd_name] = cmd
9
+ end
10
+ end
11
+ end
12
+
13
+ # Monkey Patch the Serve command to do a few things before the built-in
14
+ # Serve command methods are invoked.
15
+ module Jekyll
16
+ module Livereload
17
+ module Serve
18
+ def init_with_program(prog)
19
+ prog.command(:serve) do |c|
20
+ c.option 'livereload', '-L', '--livereload', 'Inject Livereload.js and run a WebSocket Server'
21
+ c.option 'reload_port', '-R', '--reload_port [PORT]', Integer, 'Port to serve Livereload on'
22
+ end
23
+
24
+ super prog
25
+ end
26
+
27
+ def process(opts)
28
+ Livereload.reactor = Livereload::Reactor.new(opts)
29
+ Livereload.reactor.start
30
+ super opts
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ module Livereload
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,170 @@
1
+ # Credit Alex Wood (https://github.com/awood) for most of this code.
2
+ # This was modified to work with both version 3.0.5 and 3.1.3 of Jekyll
3
+
4
+ # The MIT License (MIT)
5
+ #
6
+ # Copyright (c) 2014 Alex Wood
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to
13
+ # permit persons to whom the Software is furnished to do so, subject to
14
+ # the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be
17
+ # included in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+ require 'json'
28
+ require 'em-websocket'
29
+ require 'http/parser'
30
+
31
+ module Jekyll
32
+ module Livereload
33
+ # The LiveReload protocol requires the server to serve livereload.js over HTTP
34
+ # despite the fact that the protocol itself uses WebSockets. This custom connection
35
+ # class addresses the dual protocols that the server needs to understand.
36
+ class HttpAwareConnection < EventMachine::WebSocket::Connection
37
+ attr_reader :reload_file
38
+
39
+ def initialize(opts)
40
+ super
41
+ @reload_file = File.join(LIVERELOAD_DIR, "livereload.js")
42
+ end
43
+
44
+ def dispatch(data)
45
+ parser = Http::Parser.new
46
+ parser << data
47
+
48
+ # WebSockets requests will have a Connection: Upgrade header
49
+ if parser.http_method != 'GET' || parser.upgrade?
50
+ super
51
+ elsif parser.request_url =~ /^\/livereload.js/
52
+ headers = [
53
+ 'HTTP/1.1 200 OK',
54
+ 'Content-Type: application/javascript',
55
+ "Content-Length: #{File.size(reload_file)}",
56
+ '',
57
+ '',
58
+ ].join("\r\n")
59
+ send_data(headers)
60
+ stream_file_data(reload_file).callback do
61
+ close_connection_after_writing
62
+ end
63
+ else
64
+ body = "This port only serves livereload.js over HTTP.\n"
65
+ headers = [
66
+ 'HTTP/1.1 400 Bad Request',
67
+ 'Content-Type: text/plain',
68
+ "Content-Length: #{body.bytesize}",
69
+ '',
70
+ '',
71
+ ].join("\r\n")
72
+ send_data(headers)
73
+ send_data(body)
74
+ close_connection_after_writing
75
+ end
76
+ end
77
+ end
78
+
79
+ class Reactor
80
+ attr_reader :thread
81
+ attr_reader :opts
82
+
83
+ def initialize(opts)
84
+ @opts = opts
85
+ @thread = nil
86
+ @websockets = []
87
+ @connections_count = 0
88
+ trap("INT") { stop }
89
+ end
90
+
91
+ def stop
92
+ @thread.kill unless @thread.nil?
93
+ Jekyll.logger.debug("LiveReload Server:", "halted")
94
+ end
95
+
96
+ def running?
97
+ !@thread.nil? && @thread.alive?
98
+ end
99
+
100
+ def start
101
+ @thread = Thread.new do
102
+ # Use epoll if the kernel supports it
103
+ EM.epoll
104
+ # TODO enable SSL
105
+ EM.run do
106
+ Jekyll.logger.info("LiveReload Server:", "#{@opts['host']}:#{@opts['reload_port']}")
107
+ EM.start_server(@opts['host'], @opts['reload_port'], HttpAwareConnection, @opts) do |ws|
108
+ ws.onopen do |handshake|
109
+ connect(ws, handshake)
110
+ end
111
+
112
+ ws.onclose do
113
+ disconnect(ws)
114
+ end
115
+
116
+ ws.onmessage do |msg|
117
+ print_message(msg)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ # For a description of the protocol see http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol
125
+ def reload
126
+ Livereload.pages.each do |p|
127
+ msg = {
128
+ :command => 'reload',
129
+ :path => p.path,
130
+ :liveCSS => true,
131
+ }
132
+
133
+ # TODO Add support for override URL?
134
+ # See http://feedback.livereload.com/knowledgebase/articles/86220-preview-css-changes-against-a-live-site-then-uplo
135
+
136
+ Jekyll.logger.debug("LiveReload:", "Reloading #{p.path}")
137
+ @websockets.each do |ws|
138
+ ws.send(JSON.dump(msg))
139
+ end
140
+ end
141
+ Livereload.pages.clear
142
+ end
143
+
144
+ private
145
+
146
+ def connect(ws, _handshake)
147
+ @connections_count += 1
148
+ Jekyll.logger.info("LiveReload:", "Browser connected") if @connections_count == 1
149
+ ws.send(
150
+ JSON.dump(
151
+ :command => 'hello',
152
+ :protocols => ['http://livereload.com/protocols/official-7'],
153
+ :serverName => 'jekyll livereload',
154
+ ))
155
+
156
+ @websockets << ws
157
+ end
158
+
159
+ def disconnect(ws)
160
+ @websockets.delete(ws)
161
+ end
162
+
163
+ def print_message(json_message)
164
+ msg = JSON.parse(json_message)
165
+ # Not sure what the 'url' command even does in LiveReload
166
+ Jekyll.logger.info("LiveReload:", "Browser URL: #{msg['url']}") if msg['command'] == 'url'
167
+ end
168
+ end
169
+ end
170
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-livereload
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Robert DeRose
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: em-websocket
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.12'
55
+ description:
56
+ email:
57
+ - RobertDeRose@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - Gemfile
65
+ - History.markdown
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - jekyll-livereload.gemspec
70
+ - js/livereload.js
71
+ - lib/jekyll-livereload.rb
72
+ - lib/jekyll-livereload/build.rb
73
+ - lib/jekyll-livereload/serve.rb
74
+ - lib/jekyll-livereload/version.rb
75
+ - lib/jekyll-livereload/websocket.rb
76
+ homepage: https://github.com/RobertDeRose/jekyll-livereload
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.5.1
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Adds LiveReload support to Jekyll's included Server
100
+ test_files: []