diff --git a/bridgetown-core/lib/bridgetown-core.rb b/bridgetown-core/lib/bridgetown-core.rb index 3a9dba1de..14c20d04c 100644 --- a/bridgetown-core/lib/bridgetown-core.rb +++ b/bridgetown-core/lib/bridgetown-core.rb @@ -365,11 +365,23 @@ def sanitized_path(base_directory, questionable_path) # # @return [String] the path to the cached errors file def build_errors_path - File.join( - (Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration).root_dir, - ".bridgetown-cache", - "build_errors.txt" - ) + site_config = Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration + File.join(site_config.root_dir, site_config.cache_dir, "build_errors.txt") + end + + # This file gets touched each time there's a new build, which then triggers live reload + # in the browser. + # + # @see Bridgetown::Rack::Routes.setup_live_reload + # @return [String] the path to the empty file being watched + def live_reload_path + site_config = Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration + File.join(site_config.root_dir, site_config.cache_dir, "live_reload.txt") + end + + def touch_live_reload_file(path = live_reload_path) + FileUtils.mkdir_p File.dirname(path) + FileUtils.touch path end end diff --git a/bridgetown-core/lib/bridgetown-core/concerns/site/fast_refreshable.rb b/bridgetown-core/lib/bridgetown-core/concerns/site/fast_refreshable.rb index 2b896727a..048a69d78 100644 --- a/bridgetown-core/lib/bridgetown-core/concerns/site/fast_refreshable.rb +++ b/bridgetown-core/lib/bridgetown-core/concerns/site/fast_refreshable.rb @@ -10,6 +10,7 @@ def fast_refresh(paths = [], reload_if_needed: false) # rubocop:todo Metrics @fast_refresh_ordering = 0 full_abort = false found_gen_pages = false + found_route_file = false paths.each do |path| # rubocop:todo Metrics found_res = resources.select do |resource| resource.id.start_with?("repo://") && in_source_dir(resource.relative_path) == path @@ -28,7 +29,13 @@ def fast_refresh(paths = [], reload_if_needed: false) # rubocop:todo Metrics self, layout.instance_variable_get(:@base), layout.name ) end - next unless found_res.any? || pages.any? + + if config.key?(:routes) # carve out fast refresh track for the routes plugin + found_route_file = config.routes.source_paths.any? do |routes_dir| + path.start_with?(in_source_dir(routes_dir)) + end + end + next unless found_res.any? || pages.any? || found_route_file if pages.any? found_gen_pages = true @@ -48,7 +55,7 @@ def fast_refresh(paths = [], reload_if_needed: false) # rubocop:todo Metrics end marked_resources = resources.select(&:fast_refresh_order).sort_by(&:fast_refresh_order) - if full_abort || (marked_resources.empty? && !found_gen_pages) + if full_abort || (marked_resources.empty? && !found_gen_pages && !found_route_file) # Darn, a full reload is needed (unless we're on a super-fast track) if reload_if_needed Bridgetown::Hooks.trigger :site, :pre_reload, self, paths @@ -62,13 +69,14 @@ def fast_refresh(paths = [], reload_if_needed: false) # rubocop:todo Metrics Bridgetown::Hooks.trigger :site, :fast_refresh, self - liquid_renderer.reset - transform_resources_for_fast_refresh(marked_resources, found_gen_pages) - transform_generated_pages_for_fast_refresh - - FileUtils.touch(in_destination_dir("index.html")) + unless found_route_file + liquid_renderer.reset + transform_resources_for_fast_refresh(marked_resources, found_gen_pages) + transform_generated_pages_for_fast_refresh + end Bridgetown::Hooks.trigger :site, :post_write, self + Bridgetown.touch_live_reload_file end private diff --git a/bridgetown-core/lib/bridgetown-core/concerns/site/writable.rb b/bridgetown-core/lib/bridgetown-core/concerns/site/writable.rb index 42eac53f1..8ad402032 100644 --- a/bridgetown-core/lib/bridgetown-core/concerns/site/writable.rb +++ b/bridgetown-core/lib/bridgetown-core/concerns/site/writable.rb @@ -17,6 +17,7 @@ def write write_redirecting_index if config.prefix_default_locale Bridgetown::Hooks.trigger :site, :post_write, self + Bridgetown.touch_live_reload_file unless config.disable_disk_cache end # Yields all content objects while looping through {#generated_pages}, diff --git a/bridgetown-core/lib/bridgetown-core/rack/boot.rb b/bridgetown-core/lib/bridgetown-core/rack/boot.rb index 6c9e7b1a3..f71104f04 100644 --- a/bridgetown-core/lib/bridgetown-core/rack/boot.rb +++ b/bridgetown-core/lib/bridgetown-core/rack/boot.rb @@ -39,6 +39,7 @@ def self.autoload_server_folder( # rubocop:todo Metrics root: Bridgetown::Current.preloaded_configuration.root_dir ) server_folder = File.join(root, "server") + cached_reload_file = Bridgetown.live_reload_path Bridgetown::Hooks.register_one( :loader, :post_setup, reloadable: false @@ -62,7 +63,7 @@ def self.autoload_server_folder( # rubocop:todo Metrics end loader.reload - loader.eager_load + Bridgetown::Hooks.trigger :loader, :post_reload, loader, server_folder rescue SyntaxError => e Bridgetown::Errors.print_build_error(e) end.start @@ -75,6 +76,7 @@ def self.autoload_server_folder( # rubocop:todo Metrics next unless load_path == server_folder loader.eager_load + Bridgetown.touch_live_reload_file(cached_reload_file) end loaders_manager.setup_loaders([server_folder]) diff --git a/bridgetown-core/lib/bridgetown-core/rack/routes.rb b/bridgetown-core/lib/bridgetown-core/rack/routes.rb index 89640c044..3fbfef3f4 100644 --- a/bridgetown-core/lib/bridgetown-core/rack/routes.rb +++ b/bridgetown-core/lib/bridgetown-core/rack/routes.rb @@ -108,8 +108,7 @@ def load_all(roda_app) # @param app [Roda] def setup_live_reload(app) # rubocop:disable Metrics sleep_interval = 0.5 - file_to_check = File.join(Bridgetown::Current.preloaded_configuration.destination, - "index.html") + file_to_check = Bridgetown.live_reload_path errors_file = Bridgetown.build_errors_path app.request.get "_bridgetown/live_reload" do diff --git a/bridgetown-routes/lib/roda/plugins/bridgetown_routes.rb b/bridgetown-routes/lib/roda/plugins/bridgetown_routes.rb index 223a96adf..161440163 100644 --- a/bridgetown-routes/lib/roda/plugins/bridgetown_routes.rb +++ b/bridgetown-routes/lib/roda/plugins/bridgetown_routes.rb @@ -130,10 +130,14 @@ def view(view_class: Bridgetown::ERBView) module RequestMethods # This runs through all of the routes in the manifest, setting up Roda blocks for execution def file_routes + base_path = Bridgetown::Current.preloaded_configuration.base_path.delete_prefix("/") + scope.routes_manifest.routes.each do |route| file, localized_file_slugs, segment_keys = route localized_file_slugs.each do |slug| + on("") { scope.run_file_route(file, slug:) } if slug == "index" && !base_path.empty? + # This sets up an initial Roda route block at the slug, and handles segments as params # # _routes/nested/[slug].erb -> "nested/:slug"