Module: Bridgetown::Watcher

Extended by:
Watcher
Included in:
Watcher
Defined in:
lib/bridgetown-core/watcher.rb

Class Attribute Summary collapse

Instance Method Summary collapse

Class Attribute Details

.shutdownObject

Returns the value of attribute shutdown.



8
9
10
# File 'lib/bridgetown-core/watcher.rb', line 8

def shutdown
  @shutdown
end

Instance Method Details

#listen(site, options) ⇒ Object

Start a listener to watch for changes and call #reload_site

Parameters:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/bridgetown-core/watcher.rb', line 58

def listen(site, options) # rubocop:disable Metrics/MethodLength
  bundling_path = site.frontend_bundling_path
  FileUtils.mkdir_p(bundling_path)
  Listen.to(
    options["source"],
    bundling_path,
    *load_paths_to_watch(site, options),
    ignore: listen_ignore_paths(options),
    force_polling: options["force_polling"]
  ) do |modified, added, removed|
    c = modified + added + removed

    # NOTE: inexplicably, this matcher doesn't work with the Listen gem, so
    # we have to run it here manually
    c.reject! { component_frontend_matcher(options).match? _1 }
    n = c.length
    next if n.zero?

    unless site.ssr?
      Bridgetown.logger.info(
        "Reloading…",
        "#{n} file#{"s" if n > 1} changed at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"
      )
      c.each { |path| Bridgetown.logger.info "", "- #{path["#{site.root_dir}/".length..]}" }
    end

    reload_site(site, options, paths: c)
  end.start
end

#load_paths_to_watch(site, options) ⇒ Object

Return a list of load paths which should be watched for changes

Parameters:



44
45
46
47
48
49
50
51
52
53
# File 'lib/bridgetown-core/watcher.rb', line 44

def load_paths_to_watch(site, options)
  additional_paths = options.additional_watch_paths
  [
    *site.plugin_manager.plugins_path,
    *options.autoload_paths,
    *additional_paths,
  ].uniq.select do |path|
    Dir.exist?(path)
  end
end

#reload_site(site, options, paths: []) ⇒ Object

Reload the site including plugins and Zeitwerk autoloaders and process it (unless SSR)

Parameters:



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/bridgetown-core/watcher.rb', line 93

def reload_site(site, options, paths: []) # rubocop:todo Metrics/MethodLength
  begin
    time = Time.now
    I18n.reload! # make sure any locale files get read again
    Bridgetown::Current.sites[site.label] = site # needed in SSR mode apparently
    catch :halt do
      Bridgetown::Hooks.trigger :site, :pre_reload, site, paths
      Bridgetown::Hooks.clear_reloadable_hooks
      site.loaders_manager.reload_loaders
      Bridgetown::Hooks.trigger :site, :post_reload, site, paths

      if site.ssr?
        site.reset(soft: true)
        return
      end

      site.process
    end
    Bridgetown.logger.info "Done! 🎉", "#{"Completed".bold.green} in less than " \
                                      "#{(Time.now - time).ceil(2)} seconds."
  rescue StandardError, SyntaxError => e
    Bridgetown::Errors.print_build_error(e, trace: options[:trace])
  end
  Bridgetown.logger.info ""
end

#watch(site, options) { ... } ⇒ Object

Continuously watch for file changes and rebuild the site whenever a change is detected.

Parameters:

Yields:

  • the block will be called when in SSR mode right after the post_read event



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/bridgetown-core/watcher.rb', line 16

def watch(site, options, &block)
  ENV["LISTEN_GEM_DEBUGGING"] ||= "1" if options["verbose"]

  listen(site, options)

  if site.ssr?
    # We need to trigger pre/post read hooks when SSR reload occurs in order to re-run Builders
    Bridgetown::Hooks.register_one :site, :after_soft_reset, reloadable: false do
      Bridgetown::Hooks.trigger :site, :pre_read, site
      Bridgetown::Hooks.trigger :site, :post_read, site
      block&.call(site)
    end
  end

  Bridgetown.logger.info "Watcher:", "enabled." unless options[:using_puma]

  return if options[:serving]

  trap("INT") do
    self.shutdown = true
  end

  sleep_forever
end