Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spec/amber/cli/commands/pipelines/pipelines_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module Amber::CLI
Amber::Pipe::Session
Amber::Pipe::Flash
Amber::Pipe::CSRF
Amber::Pipe::Reload
)

static_default_plugs = %w(
Expand Down
1 change: 1 addition & 0 deletions src/amber/cli/templates/app/config/routes.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Amber::Server.configure do
plug Amber::Pipe::Session.new
plug Amber::Pipe::Flash.new
plug Amber::Pipe::CSRF.new
plug Amber::Pipe::Reload.new if Amber.env.development?
end

pipeline :api do
Expand Down
55 changes: 55 additions & 0 deletions src/amber/cli/templates/app/public/js/amber_reload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
if ('WebSocket' in window) {
(function () {
/**
* Allows to reload the browser when the server connection is lost
*/
function tryReload() {
var request = new XMLHttpRequest();
request.open('GET', window.location.href, true);
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 0) {
setTimeout(function () {
tryReload();
}, 1000)
} else {
window.location.reload();
}
}
};
request.send();
}

/**
* Listen server file reload
*/
function refreshCSS() {
var sheets = [].slice.call(document.getElementsByTagName('link'));
var head = document.getElementsByTagName('head')[0];
for (var i = 0; i < sheets.length; ++i) {
var elem = sheets[i];
var rel = elem.rel;
if (elem.href && typeof rel != 'string' || rel.length == 0 || rel.toLowerCase() == 'stylesheet') {
head.removeChild(elem);
var url = elem.href.replace(/(&|\\?)_cacheOverride=\\d+/, '');
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
head.appendChild(elem);
}
}
}

var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
var address = protocol + window.location.host + '/client-reload';
var socket = new WebSocket(address);
socket.onmessage = function (msg) {
if (msg.data == 'reload') {
tryReload();
} else if (msg.data == 'refreshcss') {
refreshCSS();
}
};
socket.onclose = function () {
tryReload();
}
})();
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<script src="/dist/main.bundle.js"></script>
<%="<"%>%- if Amber.env.development? -%><script src="/js/amber_reload.js"></script><%="<"%>%- end -%>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where I was saying we could check a variable set by the pipeline.

#in reload_pipe
context.params["_auto_reload_"] = "true"
call_next

Then in the layout check if that param exists instead of checking the environment.

What do you think @drujensen

</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ html
script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"
script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"
script src="/dist/main.bundle.js"
- if Amber.env.development?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked to @elorest about this. Let's create a new setting for this that we can turn on and off instead of based on which environment you are in. Something like if Amber.settings.auto_reload?

script src="/js/amber_reload.js"
23 changes: 23 additions & 0 deletions src/amber/pipes/reload.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require "../../support/client_reload"

@drujensen drujensen Oct 15, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be a pipeline since it doesn't actually modify the request/response in any way. Let's find a way to initialize the socket in the CLI when using amber watch. We should look for the same Amber.settings.auto_reload? flag and if it's true then we instantiate the socket.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.


module Amber
module Pipe
# Reload clients browsers using `ClientReload`.
#
# NOTE: Amber::Pipe::Reload is intended for use in a development environment.
# ```
# pipeline :web do
# plug Amber::Pipe::Reload.new
# end
# ```
class Reload < Base
def initialize(@env : Amber::Environment::Env = Amber.env)
Support::ClientReload.new
end

def call(context : HTTP::Server::Context)
call_next(context)
end
end
end
end
47 changes: 1 addition & 46 deletions src/amber/support/client_reload.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Amber::Support
# Allow clients browser reloading using WebSockets and file watchers.
struct ClientReload
FILE_TIMESTAMPS = {} of String => String
WEBSOCKET_PATH = rand(0x10000000).to_s(36)
WEBSOCKET_PATH = "client-reload"
SESSIONS = [] of HTTP::WebSocket

def initialize
Expand Down Expand Up @@ -70,50 +70,5 @@ module Amber::Support
def log(message)
Amber.logger.info(message, "Watcher", :light_gray)
end

# Code from https://github.com/tapio/live-server/blob/master/injected.html
INJECTED_CODE = <<-HTML
<!-- Code injected by Amber Framework -->
<script type="text/javascript">
// <![CDATA[ <-- For SVG support
if ('WebSocket' in window) {
(function() {
function refreshCSS() {
console.log('Reloading CSS...');
var sheets = [].slice.call(document.getElementsByTagName('link'));
var head = document.getElementsByTagName('head')[0];
for (var i = 0; i < sheets.length; ++i) {
var elem = sheets[i];
var rel = elem.rel;
if (elem.href && typeof rel != 'string' || rel.length == 0 || rel.toLowerCase() == 'stylesheet') {
head.removeChild(elem);
var url = elem.href.replace(/(&|\\?)_cacheOverride=\\d+/, '');
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
head.appendChild(elem);
}
}
}
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
var address = protocol + window.location.host + '/#{WEBSOCKET_PATH}';
var socket = new WebSocket(address);
socket.onmessage = function(msg) {
if (msg.data == 'reload') {
window.location.reload();
} else if (msg.data == 'refreshcss') {
refreshCSS();
}
};
socket.onclose = function() {
console.log('Conection closed!');
setTimeout(function() {
window.location.reload();
}, 1000);
}
console.log('Live reload enabled.');
})();
}
// ]]>
</script>\n
HTML
end
end