From 5ce593537248ea2d83cfb35f3d94f881548d6b78 Mon Sep 17 00:00:00 2001 From: Alexandre Daoud Date: Tue, 22 Sep 2015 02:17:52 +0100 Subject: [PATCH 1/3] refresh css in browser (dev mode) without having to reload the page --- lib/volt/page/tasks.rb | 16 +++++ lib/volt/server/forking_server.rb | 61 +++++++++++++------- lib/volt/server/socket_connection_handler.rb | 1 + 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/lib/volt/page/tasks.rb b/lib/volt/page/tasks.rb index c8c4fad7..b45b9f1a 100644 --- a/lib/volt/page/tasks.rb +++ b/lib/volt/page/tasks.rb @@ -1,4 +1,5 @@ require 'volt/utils/ejson' +require 'securerandom' module Volt # The tasks class provides an interface to call tasks on @@ -36,6 +37,8 @@ def received_message(name, promise_id, *args) response(promise_id, *args) when 'reload' reload + when 'refresh_css' + refresh_css(*args) end end @@ -82,5 +85,18 @@ def reload Volt.current_app.page._reloading = true `window.location.reload(false);` end + + # refresh changed css + def refresh_css(changed_files) + changed_files.each do |path| + + # We fetch the link (making sure to only match with 'begins with' incase the href has already been changed) + # We then invalidate the cached css by appending a random query to the href which forces the CSS to be reloaded + ` + var el = window.document.querySelector("link[href^='" + path + "']") + el.setAttribute("href", el.getAttribute("href") + "?v=" + #{SecureRandom.uuid[0..7]}) + ` + end + end end end diff --git a/lib/volt/server/forking_server.rb b/lib/volt/server/forking_server.rb index 838adf6a..9e9ed997 100644 --- a/lib/volt/server/forking_server.rb +++ b/lib/volt/server/forking_server.rb @@ -210,36 +210,53 @@ def call(env) def reload(changed_files) - # only reload the server code if a non-view file was changed - server_code_changed = changed_files.any? { |path| File.extname(path) == '.rb' } + # if all changed files are just css files then we will just refresh the css links by invalidating the cache + if changed_files.all? { |path| File.extname(path).match(/css|scss|sass/) } + msg = 'CSS updated, refreshing client...' - msg = 'file changed, reloading' - msg << ' server and' if server_code_changed - msg << ' client...' + Volt.logger.log_with_color(msg, :light_blue) - Volt.logger.log_with_color(msg, :light_blue) + # sub out the Volt root and any preprocessor extensions from the file paths + css_file_paths = changed_files.map { |path| path.gsub(Volt.root, "").gsub(/.scss|.sass/,"") } + begin + SocketConnectionHandler.send_message_all(nil, 'refresh_css', nil, css_file_paths) + rescue => e + Volt.logger.error('CSS refresh dispatch error: ') + Volt.logger.error(e) + end + else + # only reload the server code if a non-view file was changed + server_code_changed = changed_files.any? { |path| File.extname(path) == '.rb' } - # Figure out if any views or routes were changed: - # TODO: Might want to only check for /config/ under the CWD - if changed_files.any? {|path| path =~ /\/config\// } - update_mod_time - sync_mod_time - end + msg = 'file changed, reloading' + msg << ' server and' if server_code_changed + msg << ' client...' - begin - SocketConnectionHandler.send_message_all(nil, 'reload') - rescue => e - Volt.logger.error('Reload dispatch error: ') - Volt.logger.error(e) - end + Volt.logger.log_with_color(msg, :light_blue) - if server_code_changed - @child_lock.with_write_lock do - stop_child - start_child + + # Figure out if any views or routes were changed: + # TODO: Might want to only check for /config/ under the CWD + if changed_files.any? {|path| path =~ /\/config\// } + update_mod_time sync_mod_time end + + begin + SocketConnectionHandler.send_message_all(nil, 'reload') + rescue => e + Volt.logger.error('Reload dispatch error: ') + Volt.logger.error(e) + end + + if server_code_changed + @child_lock.with_write_lock do + stop_child + start_child + sync_mod_time + end + end end end diff --git a/lib/volt/server/socket_connection_handler.rb b/lib/volt/server/socket_connection_handler.rb index 63e49016..1bf83615 100644 --- a/lib/volt/server/socket_connection_handler.rb +++ b/lib/volt/server/socket_connection_handler.rb @@ -53,6 +53,7 @@ def self.channels end # Sends a message to all, optionally skipping a users channel + # Expects promise_id after message name, can be nil def self.send_message_all(skip_channel = nil, *args) return unless defined?(@@channels) @@channels.each do |channel| From 4e8c052ae36471a39f57f309f967507089a5630a Mon Sep 17 00:00:00 2001 From: Alexandre Daoud Date: Tue, 22 Sep 2015 16:07:09 +0100 Subject: [PATCH 2/3] rework css refresh and file reloading code to fix refreshing for added and removed css files --- lib/volt/page/tasks.rb | 30 ++++++++++++++++++++++++++---- lib/volt/server/forking_server.rb | 9 ++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/volt/page/tasks.rb b/lib/volt/page/tasks.rb index b45b9f1a..0b4ef85c 100644 --- a/lib/volt/page/tasks.rb +++ b/lib/volt/page/tasks.rb @@ -88,13 +88,35 @@ def reload # refresh changed css def refresh_css(changed_files) - changed_files.each do |path| - - # We fetch the link (making sure to only match with 'begins with' incase the href has already been changed) + changed_files[:removed].each do |path| + + # Remove link to css from head + ` + var el = window.document.querySelector("link[href^='" + path + "']"); + el.parentElement.removeChild(el); + ` + end + changed_files[:modified].each do |path| + + # We fetch the link # We then invalidate the cached css by appending a random query to the href which forces the CSS to be reloaded ` var el = window.document.querySelector("link[href^='" + path + "']") - el.setAttribute("href", el.getAttribute("href") + "?v=" + #{SecureRandom.uuid[0..7]}) + el.setAttribute('href', el.getAttribute('href') + '?v=' + #{SecureRandom.uuid[0..7]}) + ` + end + + changed_files[:added].each do |path| + + # Inject a new link to the css into the head + ` + link=document.createElement('link'); + link.href=path; + link.rel='stylesheet'; + link.type='text/css'; + link.meda='all'; + + document.getElementsByTagName('head')[0].appendChild(link); ` end end diff --git a/lib/volt/server/forking_server.rb b/lib/volt/server/forking_server.rb index 9e9ed997..f28683e8 100644 --- a/lib/volt/server/forking_server.rb +++ b/lib/volt/server/forking_server.rb @@ -208,8 +208,9 @@ def call(env) end end + def reload(args) + changed_files = args[:modified] + args[:added] + args[:removed] - def reload(changed_files) # if all changed files are just css files then we will just refresh the css links by invalidating the cache if changed_files.all? { |path| File.extname(path).match(/css|scss|sass/) } msg = 'CSS updated, refreshing client...' @@ -217,7 +218,9 @@ def reload(changed_files) Volt.logger.log_with_color(msg, :light_blue) # sub out the Volt root and any preprocessor extensions from the file paths - css_file_paths = changed_files.map { |path| path.gsub(Volt.root, "").gsub(/.scss|.sass/,"") } + css_file_paths = args.update(args) do |key,value| + value.map { |path| path.gsub(Volt.root, '').gsub(/.scss|.sass/,'') } + end begin SocketConnectionHandler.send_message_all(nil, 'refresh_css', nil, css_file_paths) @@ -284,7 +287,7 @@ def start_change_listener @listener = Listen.to("#{@server.app_path}/", options) do |modified, added, removed| Thread.new do # Run the reload in a new thread - reload(modified + added + removed) + reload(modified: modified, added: added, removed: removed) end end @listener.start From 1f53edd2c9dfe97486b84e76e4f9eeeabccf0c63 Mon Sep 17 00:00:00 2001 From: Alexandre Daoud Date: Tue, 22 Sep 2015 16:09:29 +0100 Subject: [PATCH 3/3] fix media typo --- lib/volt/page/tasks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/volt/page/tasks.rb b/lib/volt/page/tasks.rb index 0b4ef85c..e4fcdb53 100644 --- a/lib/volt/page/tasks.rb +++ b/lib/volt/page/tasks.rb @@ -114,7 +114,7 @@ def refresh_css(changed_files) link.href=path; link.rel='stylesheet'; link.type='text/css'; - link.meda='all'; + link.media='all'; document.getElementsByTagName('head')[0].appendChild(link); `