jekyll-livereload 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []