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



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
87
88
89
90
# 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|
    paths = modified + added + removed

    filter_paths(paths, options, keep: [bundling_path])

    n = paths.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")}"
      )
      paths.each { Bridgetown.logger.info "", "- #{_1.delete_prefix("#{site.root_dir}/")}" }
    end

    reload_site(
      site,
      options,
      paths:,
      fast_refreshable: site.config.fast_refresh && (added + removed).empty?
    )
  end.start
end

#load_paths_to_watch(site, options) ⇒ Object

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



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: [], fast_refreshable: false) ⇒ Object

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



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/bridgetown-core/watcher.rb', line 97

def reload_site(site, options, paths: [], fast_refreshable: false) # 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
      site.loaders_manager.reload_loaders(site, paths) unless fast_refreshable

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

      if fast_refreshable
        site.fast_refresh(paths, reload_if_needed: true)
      else
        site.process
      end
    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.

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

    return
  end

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

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

  sleep_forever
end