bridgetown-core 1.3.4 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bridgetown +0 -6
  3. data/bin/bt +6 -0
  4. data/bridgetown-core.gemspec +9 -6
  5. data/lib/bridgetown-core/cleaner.rb +1 -1
  6. data/lib/bridgetown-core/collection.rb +30 -18
  7. data/lib/bridgetown-core/commands/build.rb +9 -22
  8. data/lib/bridgetown-core/commands/concerns/actions.rb +15 -8
  9. data/lib/bridgetown-core/commands/concerns/configuration_overridable.rb +1 -1
  10. data/lib/bridgetown-core/commands/console.rb +3 -0
  11. data/lib/bridgetown-core/commands/doctor.rb +2 -4
  12. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +1 -1
  13. data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +1 -1
  14. data/lib/bridgetown-core/commands/esbuild/update.rb +2 -2
  15. data/lib/bridgetown-core/commands/esbuild.rb +3 -3
  16. data/lib/bridgetown-core/commands/new.rb +32 -39
  17. data/lib/bridgetown-core/commands/start.rb +76 -60
  18. data/lib/bridgetown-core/component.rb +19 -13
  19. data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
  20. data/lib/bridgetown-core/concerns/prioritizable.rb +11 -1
  21. data/lib/bridgetown-core/concerns/site/configurable.rb +7 -18
  22. data/lib/bridgetown-core/concerns/site/content.rb +10 -9
  23. data/lib/bridgetown-core/concerns/site/extensible.rb +4 -6
  24. data/lib/bridgetown-core/concerns/site/fast_refreshable.rb +161 -0
  25. data/lib/bridgetown-core/concerns/site/processable.rb +1 -0
  26. data/lib/bridgetown-core/concerns/site/renderable.rb +31 -7
  27. data/lib/bridgetown-core/concerns/site/ssr.rb +23 -9
  28. data/lib/bridgetown-core/concerns/site/writable.rb +1 -1
  29. data/lib/bridgetown-core/concerns/transformable.rb +3 -5
  30. data/lib/bridgetown-core/configuration/configuration_dsl.rb +23 -14
  31. data/lib/bridgetown-core/configuration.rb +67 -114
  32. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -2
  33. data/lib/bridgetown-core/configurations/cypress/cypress_tasks +2 -2
  34. data/lib/bridgetown-core/configurations/cypress.rb +1 -1
  35. data/lib/bridgetown-core/configurations/gh-pages/gh-pages.yml +3 -3
  36. data/lib/bridgetown-core/configurations/is-land.rb +1 -1
  37. data/lib/bridgetown-core/configurations/lit.rb +1 -1
  38. data/lib/bridgetown-core/configurations/open-props.rb +1 -1
  39. data/lib/bridgetown-core/configurations/purgecss.rb +1 -1
  40. data/lib/bridgetown-core/configurations/ruby2js.rb +1 -1
  41. data/lib/bridgetown-core/configurations/shoelace.rb +8 -20
  42. data/lib/bridgetown-core/configurations/stimulus.rb +17 -36
  43. data/lib/bridgetown-core/configurations/turbo.rb +1 -2
  44. data/lib/bridgetown-core/converter.rb +38 -10
  45. data/lib/bridgetown-core/converters/erb_templates.rb +9 -26
  46. data/lib/bridgetown-core/converters/identity.rb +1 -1
  47. data/lib/bridgetown-core/converters/liquid_templates.rb +2 -20
  48. data/lib/bridgetown-core/converters/ruby_templates.rb +61 -3
  49. data/lib/bridgetown-core/converters/serbea_templates.rb +12 -24
  50. data/lib/bridgetown-core/current.rb +19 -17
  51. data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
  52. data/lib/bridgetown-core/drops/drop.rb +3 -3
  53. data/lib/bridgetown-core/drops/relations_drop.rb +3 -2
  54. data/lib/bridgetown-core/drops/site_drop.rb +0 -5
  55. data/lib/bridgetown-core/entry_filter.rb +4 -6
  56. data/lib/bridgetown-core/errors.rb +2 -2
  57. data/lib/bridgetown-core/filters/from_liquid.rb +6 -10
  58. data/lib/bridgetown-core/filters/localization_filters.rb +1 -1
  59. data/lib/bridgetown-core/filters/translation_filters.rb +2 -2
  60. data/lib/bridgetown-core/filters.rb +3 -3
  61. data/lib/bridgetown-core/front_matter/defaults.rb +225 -0
  62. data/lib/bridgetown-core/front_matter/importer.rb +34 -0
  63. data/lib/bridgetown-core/front_matter/loaders/base.rb +29 -0
  64. data/lib/bridgetown-core/front_matter/loaders/ruby.rb +113 -0
  65. data/lib/bridgetown-core/front_matter/loaders/yaml.rb +42 -0
  66. data/lib/bridgetown-core/front_matter/loaders.rb +44 -0
  67. data/lib/bridgetown-core/{utils/ruby_front_matter.rb → front_matter/ruby.rb} +5 -5
  68. data/lib/bridgetown-core/front_matter.rb +11 -0
  69. data/lib/bridgetown-core/generated_page.rb +71 -31
  70. data/lib/bridgetown-core/generators/prototype_generator.rb +30 -18
  71. data/lib/bridgetown-core/helpers.rb +36 -47
  72. data/lib/bridgetown-core/hooks.rb +5 -5
  73. data/lib/bridgetown-core/inflector.rb +40 -0
  74. data/lib/bridgetown-core/kramdown/parser/gfm.rb +2 -2
  75. data/lib/bridgetown-core/layout.rb +3 -3
  76. data/lib/bridgetown-core/log_adapter.rb +12 -13
  77. data/lib/bridgetown-core/log_writer.rb +4 -4
  78. data/lib/bridgetown-core/model/base.rb +17 -17
  79. data/lib/bridgetown-core/model/builder_origin.rb +5 -3
  80. data/lib/bridgetown-core/model/origin.rb +1 -3
  81. data/lib/bridgetown-core/model/repo_origin.rb +12 -14
  82. data/lib/bridgetown-core/plugin.rb +0 -1
  83. data/lib/bridgetown-core/plugin_manager.rb +27 -84
  84. data/lib/bridgetown-core/rack/boot.rb +0 -15
  85. data/lib/bridgetown-core/rack/routes.rb +30 -90
  86. data/lib/bridgetown-core/reader.rb +6 -4
  87. data/lib/bridgetown-core/readers/layout_reader.rb +2 -2
  88. data/lib/bridgetown-core/readers/plugin_content_reader.rb +2 -2
  89. data/lib/bridgetown-core/resource/base.rb +112 -29
  90. data/lib/bridgetown-core/resource/destination.rb +1 -1
  91. data/lib/bridgetown-core/resource/relations.rb +11 -8
  92. data/lib/bridgetown-core/resource/taxonomy_type.rb +3 -1
  93. data/lib/bridgetown-core/resource/transformer.rb +4 -4
  94. data/lib/bridgetown-core/ruby_template_view.rb +44 -28
  95. data/lib/bridgetown-core/signals.rb +95 -0
  96. data/lib/bridgetown-core/site.rb +22 -4
  97. data/lib/bridgetown-core/slot.rb +5 -5
  98. data/lib/bridgetown-core/static_file.rb +5 -7
  99. data/lib/bridgetown-core/tags/asset_path.rb +11 -2
  100. data/lib/bridgetown-core/tags/find.rb +3 -5
  101. data/lib/bridgetown-core/tags/highlight.rb +3 -3
  102. data/lib/bridgetown-core/tags/post_url.rb +1 -1
  103. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -2
  104. data/lib/bridgetown-core/utils/aux.rb +41 -41
  105. data/lib/bridgetown-core/utils/loaders_manager.rb +2 -21
  106. data/lib/bridgetown-core/utils/ruby_exec.rb +17 -0
  107. data/lib/bridgetown-core/utils.rb +46 -110
  108. data/lib/bridgetown-core/version.rb +2 -2
  109. data/lib/bridgetown-core/watcher.rb +21 -10
  110. data/lib/bridgetown-core.rb +35 -49
  111. data/lib/roda/plugins/bridgetown_server.rb +54 -12
  112. data/lib/roda/plugins/bridgetown_ssr.rb +13 -2
  113. data/lib/roda/plugins/ssg.rb +72 -0
  114. data/lib/site_template/.gitignore +9 -3
  115. data/lib/site_template/Gemfile.erb +3 -3
  116. data/lib/site_template/README.md +3 -4
  117. data/lib/site_template/Rakefile.erb +2 -15
  118. data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +2 -2
  119. data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +2 -2
  120. data/lib/site_template/config/initializers.rb +60 -22
  121. data/lib/site_template/config/puma.rb +2 -0
  122. data/lib/site_template/package.json.erb +2 -27
  123. data/lib/site_template/src/index.md.erb +3 -3
  124. data/lib/site_template/tmp/pids/.keep +0 -0
  125. metadata +98 -63
  126. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +0 -12
  127. data/lib/bridgetown-core/commands/webpack/setup.rb +0 -4
  128. data/lib/bridgetown-core/commands/webpack/update.rb +0 -24
  129. data/lib/bridgetown-core/commands/webpack/webpack.config.js +0 -31
  130. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +0 -135
  131. data/lib/bridgetown-core/commands/webpack.rb +0 -82
  132. data/lib/bridgetown-core/concerns/front_matter_importer.rb +0 -52
  133. data/lib/bridgetown-core/concerns/liquid_renderable.rb +0 -30
  134. data/lib/bridgetown-core/core_ext/psych.rb +0 -15
  135. data/lib/bridgetown-core/drops/url_drop.rb +0 -152
  136. data/lib/bridgetown-core/frontmatter_defaults.rb +0 -223
  137. data/lib/bridgetown-core/rack/static_indexes.rb +0 -31
  138. data/lib/bridgetown-core/url.rb +0 -166
  139. data/lib/bridgetown-core/utils/ansi.rb +0 -57
  140. data/lib/site_template/bridgetown.config.yml +0 -33
@@ -1,103 +1,119 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rackup/server"
4
+
3
5
  module Bridgetown
6
+ class Server < Rackup::Server
7
+ def start(after_stop_callback = nil)
8
+ trap(:INT) { exit }
9
+ super()
10
+ ensure
11
+ after_stop_callback&.call
12
+ end
13
+
14
+ def name
15
+ server.to_s.split("::").last
16
+ end
17
+
18
+ def using_puma?
19
+ name == "Puma"
20
+ end
21
+
22
+ def serveable?
23
+ server
24
+ true
25
+ rescue LoadError, NameError
26
+ false
27
+ end
28
+ end
29
+
4
30
  module Commands
5
31
  class Start < Thor::Group
6
32
  extend BuildOptions
7
33
  extend Summarizable
8
34
  include ConfigurationOverridable
35
+ include Inclusive
9
36
 
10
37
  Registrations.register do
11
38
  register(Start, "start", "start", Start.summary)
12
39
  register(Start, "dev", "dev", "Alias of start")
13
40
  end
14
41
 
15
- class_option :bind, aliases: "-B", desc: "URI for Puma to bind to (start with tcp://)"
42
+ class_option :port,
43
+ aliases: "-P",
44
+ type: :numeric,
45
+ default: 4000,
46
+ desc: "Serve your site on the specified port. Defaults to 4000."
47
+ class_option :bind,
48
+ aliases: "-B",
49
+ type: :string,
50
+ default: "0.0.0.0",
51
+ desc: "URL for the server to bind to."
16
52
  class_option :skip_frontend,
17
53
  type: :boolean,
18
- desc: "Don't load the frontend bundler (always true for production)"
54
+ desc: "Don't load the frontend bundler (always true for production)."
19
55
  class_option :skip_live_reload,
20
56
  type: :boolean,
21
- desc: "Don't use the live reload functionality (always true for production)"
57
+ desc: "Don't use the live reload functionality (always true for production)."
22
58
 
23
59
  def self.banner
24
60
  "bridgetown start [options]"
25
61
  end
26
- summary "Start the Puma server, frontend bundler, and Bridgetown watcher"
62
+ summary "Start the web server, frontend bundler, and Bridgetown watcher"
27
63
 
28
- def start # rubocop:todo Metrics/PerceivedComplexity
64
+ def start
65
+ pid_tracker = packages[Bridgetown::Foundation::Packages::PidTracker]
29
66
  Bridgetown.logger.writer.enable_prefix
30
67
  Bridgetown::Commands::Build.print_startup_message
31
68
  sleep 0.25
32
69
 
33
- begin
34
- require("puma/detect")
35
- rescue LoadError
36
- raise "** Puma server gem not found. Check your Gemfile and Bundler env? **"
37
- end
38
-
39
70
  options = Thor::CoreExt::HashWithIndifferentAccess.new(self.options)
40
- options[:using_puma] = true
71
+ options[:start_command] = true
41
72
 
42
73
  # Load Bridgetown configuration into thread memory
43
74
  bt_options = configuration_with_overrides(options)
75
+ port = ENV.fetch("BRIDGETOWN_PORT", bt_options.port)
76
+ # TODO: support Puma serving HTTPS directly?
77
+ bt_bound_url = "http://#{bt_options.bind}:#{port}"
44
78
 
45
79
  # Set a local site URL in the config if one is not available
46
- if Bridgetown.env.development? && !options["url"]
47
- scheme = bt_options.bind&.split("://")&.first == "ssl" ? "https" : "http"
48
- port = bt_options.bind&.split(":")&.last || ENV["BRIDGETOWN_PORT"] || 4000
49
- bt_options.url = "#{scheme}://localhost:#{port}"
50
- end
80
+ bt_options.url = bt_bound_url if Bridgetown.env.development? && !options["url"]
51
81
 
52
- puma_pid =
53
- Process.fork do
54
- require "puma/cli"
55
-
56
- Puma::Runner.class_eval do
57
- def output_header(mode)
58
- log "* Puma version: #{Puma::Const::PUMA_VERSION} (#{ruby_engine}) (\"#{Puma::Const::CODE_NAME}\")" # rubocop:disable Layout/LineLength
59
- if mode == "cluster"
60
- log "* Cluster Master PID: #{Process.pid}"
61
- else
62
- log "* PID: #{Process.pid}"
63
- end
64
- end
65
- end
82
+ Bridgetown::Server.new({
83
+ Host: bt_options.bind,
84
+ Port: port,
85
+ config: "config.ru",
86
+ }).tap do |server|
87
+ if server.serveable?
88
+ pid_tracker.create_pid_dir
66
89
 
67
- puma_args = []
68
- if bt_options[:bind]
69
- puma_args << "--bind"
70
- puma_args << bt_options[:bind]
71
- end
90
+ bt_options.skip_live_reload = !server.using_puma?
72
91
 
73
- cli = Puma::CLI.new puma_args
74
- cli.launcher.events.on_stopped do
92
+ build_args = ["-w"] + ARGV.reject { |arg| arg == "start" }
93
+ build_pid = Process.fork { Bridgetown::Commands::Build.start(build_args) }
94
+ pid_tracker.add_pid(build_pid, file: :bridgetown)
95
+
96
+ after_stop_callback = -> {
97
+ say "Stopping Bridgetown server..."
75
98
  Bridgetown::Hooks.trigger :site, :server_shutdown
76
- end
77
- cli.run
78
- end
99
+ Process.kill "SIGINT", build_pid
100
+ pid_tracker.remove_pidfile :bridgetown
79
101
 
80
- begin
81
- Signal.trap("TERM") do
82
- Process.kill "SIGINT", puma_pid
83
- sleep 0.5 # let it breathe
84
- exit 0 # this runs the ensure block below
85
- end
102
+ # Shut down the frontend bundler etc. if they're running
103
+ unless Bridgetown.env.production? || bt_options[:skip_frontend]
104
+ Bridgetown::Utils::Aux.kill_processes
105
+ end
106
+ }
86
107
 
87
- Process.setproctitle("bridgetown #{Bridgetown::VERSION} [#{File.basename(Dir.pwd)}]")
88
-
89
- build_args = ["-w"] + ARGV.reject { |arg| arg == "start" }
90
- Bridgetown::Commands::Build.start(build_args)
91
- rescue StandardError => e
92
- Process.kill "SIGINT", puma_pid
93
- sleep 0.5
94
- raise e
95
- ensure
96
- # Shut down webpack, browsersync, etc. if they're running
97
- Bridgetown::Utils::Aux.kill_processes
98
- end
108
+ Bridgetown.logger.info ""
109
+ Bridgetown.logger.info "Booting #{server.name} at:", bt_bound_url.to_s.magenta
110
+ Bridgetown.logger.info ""
99
111
 
100
- sleep 0.5 # finish cleaning up
112
+ server.start(after_stop_callback)
113
+ else
114
+ say "Unable to find a Rack server."
115
+ end
116
+ end
101
117
  end
102
118
  end
103
119
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Bridgetown
4
4
  class Component
5
+ using Bridgetown::Refinements
6
+ include Bridgetown::Streamlined
5
7
  extend Forwardable
6
8
 
7
9
  def_delegators :@view_context, :liquid_render, :partial
@@ -29,20 +31,20 @@ module Bridgetown
29
31
  # TODO: make this extensible
30
32
  #
31
33
  # @param ext [String] erb, slim, etc.
32
- def renderer_for_ext(ext, &block)
34
+ def renderer_for_ext(ext, &)
33
35
  @_tmpl ||= case ext.to_s
34
36
  when "erb"
35
37
  Tilt::ErubiTemplate.new(component_template_path,
36
38
  outvar: "@_erbout",
37
39
  bufval: "Bridgetown::OutputBuffer.new",
38
40
  engine_class: Bridgetown::ERBEngine,
39
- &block)
41
+ &)
40
42
  when "serb"
41
- Tilt::SerbeaTemplate.new(component_template_path, &block)
43
+ Tilt::SerbeaTemplate.new(component_template_path, &)
42
44
  when "slim" # requires bridgetown-slim
43
- Slim::Template.new(component_template_path, &block)
45
+ Slim::Template.new(component_template_path, &)
44
46
  when "haml" # requires bridgetown-haml
45
- Tilt::HamlTemplate.new(component_template_path, &block)
47
+ Tilt::HamlTemplate.new(component_template_path, &)
46
48
  else
47
49
  raise NameError
48
50
  end
@@ -91,7 +93,7 @@ module Bridgetown
91
93
  end
92
94
 
93
95
  def path_for_errors
94
- component_template_path
96
+ File.basename(component_template_path)
95
97
  rescue RuntimeError
96
98
  source_location
97
99
  end
@@ -121,7 +123,7 @@ module Bridgetown
121
123
  name = name.to_s
122
124
  slots.reject! { _1.name == name } if replace
123
125
 
124
- slots << Slot.new(name: name, content: content, context: self, transform: false)
126
+ slots << Slot.new(name:, content:, context: self, transform: false)
125
127
 
126
128
  nil
127
129
  end
@@ -179,6 +181,12 @@ module Bridgetown
179
181
  @_content_block = block
180
182
 
181
183
  if render?
184
+ if helpers.site.config.fast_refresh
185
+ signal = helpers.site.tmp_cache["comp-signal:#{self.class.source_location}"] ||=
186
+ Signalize.signal(1)
187
+ # subscribe so resources are attached to this component within effect
188
+ signal.value
189
+ end
182
190
  before_render
183
191
  template
184
192
  else
@@ -194,7 +202,7 @@ module Bridgetown
194
202
  # Subclasses can override this method to return a string from their own
195
203
  # template handling.
196
204
  def template
197
- call || _renderer.render(self)
205
+ (method(:call).arity.zero? ? call : nil) || _renderer.render(self)
198
206
  end
199
207
 
200
208
  # Typically not used but here as a compatibility nod toward ViewComponent.
@@ -221,14 +229,12 @@ module Bridgetown
221
229
  end
222
230
 
223
231
  def helpers
224
- @helpers ||= Bridgetown::RubyTemplateView::Helpers.new(
225
- self, view_context&.site || Bridgetown::Current.site
226
- )
232
+ @helpers ||= Bridgetown::RubyTemplateView::Helpers.new(self, view_context&.site)
227
233
  end
228
234
 
229
- def method_missing(method, *args, **kwargs, &block)
235
+ def method_missing(method, ...)
230
236
  if helpers.respond_to?(method.to_sym)
231
- helpers.send method.to_sym, *args, **kwargs, &block
237
+ helpers.send(method.to_sym, ...)
232
238
  else
233
239
  super
234
240
  end
@@ -7,7 +7,7 @@ module Bridgetown
7
7
  # Returns false if the document is an asset file or if the front matter
8
8
  # specifies `layout: none`
9
9
  def place_in_layout?
10
- !(yaml_file? || no_layout?)
10
+ no_layout?.!
11
11
  end
12
12
 
13
13
  def no_layout?
@@ -26,11 +26,21 @@ module Bridgetown
26
26
  def <=>(other)
27
27
  priorities[other.priority] <=> priorities[priority]
28
28
  end
29
+
30
+ # Return either this class' priorities or the superclass which has them (if any)
31
+ def priorities
32
+ return @priorities if @priorities
33
+
34
+ superclass.priorities if superclass.respond_to?(:priorities)
35
+ end
36
+
37
+ def priorities=(val)
38
+ @priorities = val
39
+ end
29
40
  end
30
41
 
31
42
  def self.included(klass)
32
43
  klass.extend ClassMethods
33
- klass.class_attribute :priorities, instance_accessor: false
34
44
  end
35
45
 
36
46
  # Spaceship is priority [higher -> lower]
@@ -12,6 +12,7 @@ class Bridgetown::Site
12
12
  configure_component_paths
13
13
  configure_file_read_opts
14
14
 
15
+ # TODO: see if we can just get rid of this. It's only used by GeneratedPage
15
16
  self.permalink_style = (config["permalink"] || "pretty").to_sym
16
17
  end
17
18
 
@@ -28,40 +29,28 @@ class Bridgetown::Site
28
29
  end
29
30
  alias_method :dest, :destination
30
31
 
31
- def uses_resource?
32
- Bridgetown::Deprecator.deprecation_message(
33
- "The Site#uses_resource? method will be removed in the next version"
34
- )
35
- true
36
- end
37
-
38
32
  # Returns a base path from which the site is served (aka `/cool-site`) or
39
33
  # `/` if served from root.
40
34
  #
41
35
  # @param strip_slash_only [Boolean] set to true if you wish "/" to be returned as ""
42
36
  # @return [String]
43
37
  def base_path(strip_slash_only: false)
44
- (config[:base_path] || config[:baseurl]).then do |path|
38
+ config[:base_path].then do |path|
45
39
  strip_slash_only ? path.to_s.sub(%r{^/$}, "") : path
46
40
  end
47
41
  end
48
42
 
49
- def baseurl
50
- Bridgetown::Deprecator.deprecation_message "Site#baseurl is now Site#base_path"
51
- base_path(strip_slash_only: true).presence
52
- end
53
-
54
43
  def defaults_reader
55
44
  @defaults_reader ||= Bridgetown::DefaultsReader.new(self)
56
45
  end
57
46
 
58
- # Returns the current instance of {FrontmatterDefaults} or
59
- # creates a new instance {FrontmatterDefaults} if it doesn't already exist.
47
+ # Returns the current instance of {FrontMatter::Defaults} or
48
+ # creates a new instance {FrontMatter::Defaults} if it doesn't already exist.
60
49
  #
61
- # @return [FrontmatterDefaults]
62
- # Returns an instance of {FrontmatterDefaults}
50
+ # @return [FrontMatter::Defaults]
51
+ # Returns an instance of {FrontMatter::Defaults}
63
52
  def frontmatter_defaults
64
- @frontmatter_defaults ||= Bridgetown::FrontmatterDefaults.new(self)
53
+ @frontmatter_defaults ||= Bridgetown::FrontMatter::Defaults.new(self)
65
54
  end
66
55
 
67
56
  # Prefix a path or paths with the {#root_dir} directory.
@@ -3,6 +3,8 @@
3
3
  class Bridgetown::Site
4
4
  # Content is king!
5
5
  module Content
6
+ using Bridgetown::Refinements
7
+
6
8
  def resources_grouped_by_taxonomy(taxonomy)
7
9
  data.site_taxonomies_hash ||= {}
8
10
  data.site_taxonomies_hash[taxonomy.label] ||= taxonomy.terms.transform_values do |terms|
@@ -24,11 +26,10 @@ class Bridgetown::Site
24
26
  taxonomies.category
25
27
  end
26
28
 
27
- # Returns the value of `data["site_metadata"]` or creates a new instance of
28
- # `HashWithDotAccess::Hash`
29
- # @return [Hash] Returns a hash of site metadata
29
+ # Returns the contents of the site metadata file or a blank hash
30
+ # @return [HashWithDotAccess::Hash] Returns a hash of site metadata
30
31
  def metadata
31
- data["site_metadata"] ||= HashWithDotAccess::Hash.new
32
+ signals["site_metadata"] ||= HashWithDotAccess::Hash.new
32
33
  end
33
34
 
34
35
  # The Hash payload containing site-wide data.
@@ -46,10 +47,10 @@ class Bridgetown::Site
46
47
  #
47
48
  # If `config["collections"]` is not specified, a blank hash is returned.
48
49
  #
49
- # @return [Hash{String, Symbol => Collection}] A Hash
50
+ # @return [HashWithDotAccess::Hash{String, Symbol => Collection}] A Hash
50
51
  # containing a collection name-to-instance pairs.
51
52
  #
52
- # @return [Hash] Returns a blank hash if no items found
53
+ # @return [HashWithDotAccess::Hash] Returns a blank hash if no items found
53
54
  def collections
54
55
  @collections ||= collection_names.each_with_object(
55
56
  HashWithDotAccess::Hash.new
@@ -67,7 +68,7 @@ class Bridgetown::Site
67
68
 
68
69
  # @return [Array<Bridgetown::Resource::TaxonomyType>]
69
70
  def taxonomy_types
70
- @taxonomy_types ||= config.taxonomies.to_h do |label, key_or_metadata|
71
+ @taxonomy_types ||= config.taxonomies.to_dot_h do |label, key_or_metadata|
71
72
  key = key_or_metadata
72
73
  tax_metadata = if key_or_metadata.is_a? Hash
73
74
  key = key_or_metadata["key"]
@@ -77,9 +78,9 @@ class Bridgetown::Site
77
78
  end
78
79
 
79
80
  [label, Bridgetown::Resource::TaxonomyType.new(
80
- site: self, label: label, key: key, metadata: tax_metadata
81
+ site: self, label:, key:, metadata: tax_metadata
81
82
  ),]
82
- end.with_dot_access
83
+ end
83
84
  end
84
85
 
85
86
  # Get all loaded resources.
@@ -25,11 +25,9 @@ class Bridgetown::Site
25
25
 
26
26
  next unless ENV["BRIDGETOWN_LOG_LEVEL"] == "debug"
27
27
 
28
- generator_name = if generator.class.respond_to?(:custom_name)
29
- generator.class.custom_name
30
- else
28
+ generator_name = generator.class.respond_to?(:custom_name) ?
29
+ generator.class.custom_name :
31
30
  generator.class.name
32
- end
33
31
  Bridgetown.logger.debug "Generating:",
34
32
  "#{generator_name} finished in #{Time.now - start} seconds."
35
33
  end
@@ -61,8 +59,8 @@ class Bridgetown::Site
61
59
  # @param event [Symbol] name of the event (`:pre_read`, `:post_render`, etc.)
62
60
  # @yield the block will be called when the event is triggered
63
61
  # @yieldparam site the site which triggered the event hook
64
- def on(event, reloadable: false, &block)
65
- Bridgetown::Hooks.register_one :site, event, reloadable: reloadable, &block
62
+ def on(event, reloadable: false, &)
63
+ Bridgetown::Hooks.register_one :site, event, reloadable:, &
66
64
  end
67
65
  end
68
66
  end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bridgetown::Site
4
+ module FastRefreshable
5
+ using Bridgetown::Refinements
6
+
7
+ def fast_refresh(paths = [], reload_if_needed: false) # rubocop:todo Metrics
8
+ FileUtils.rm_f(Bridgetown.build_errors_path)
9
+
10
+ @fast_refresh_ordering = 0
11
+ full_abort = false
12
+ found_gen_pages = false
13
+ paths.each do |path|
14
+ res = resources.find do |resource|
15
+ resource.id.start_with?("repo://") && in_source_dir(resource.relative_path) == path
16
+ end
17
+
18
+ layouts_to_reload = Set.new
19
+ locate_resource_layouts_and_partials_for_fash_refresh(path, layouts_to_reload) unless res
20
+
21
+ locate_components_for_fast_refresh(path) unless res
22
+
23
+ pages = locate_layouts_and_pages_for_fast_refresh(path, layouts_to_reload)
24
+
25
+ layouts_to_reload.each do |layout|
26
+ layouts[layout.label] = Bridgetown::Layout.new(
27
+ self, layout.instance_variable_get(:@base), layout.name
28
+ )
29
+ end
30
+ liquid_renderer.reset unless layouts_to_reload.empty?
31
+ next unless res || !pages.empty?
32
+
33
+ unless pages.empty?
34
+ found_gen_pages = true
35
+ mark_original_page_resources_for_fast_refresh(pages)
36
+ next
37
+ end
38
+
39
+ res.prepare_for_fast_refresh!.tap { full_abort = true unless _1 }
40
+ next unless res.collection.data?
41
+
42
+ res.collection.merge_data_resources.each do |k, v|
43
+ data[k] = v
44
+ signals[k] = v
45
+ end
46
+ end
47
+
48
+ marked_resources = resources.select(&:fast_refresh_order).sort_by(&:fast_refresh_order)
49
+ if full_abort || (marked_resources.empty? && !found_gen_pages)
50
+ # Darn, a full reload is needed (unless we're on a super-fast track)
51
+ if reload_if_needed
52
+ Bridgetown::Hooks.trigger :site, :pre_reload, self, paths
53
+ Bridgetown::Hooks.clear_reloadable_hooks
54
+ loaders_manager.reload_loaders
55
+ Bridgetown::Hooks.trigger :site, :post_reload, self, paths
56
+ process # bring out the big guns
57
+ end
58
+ return
59
+ end
60
+
61
+ Bridgetown::Hooks.trigger :site, :fast_refresh, self
62
+
63
+ transform_resources_for_fast_refresh(marked_resources, found_gen_pages)
64
+ transform_generated_pages_for_fast_refresh
65
+
66
+ FileUtils.touch(in_destination_dir("index.html"))
67
+
68
+ Bridgetown::Hooks.trigger :site, :post_write, self
69
+ end
70
+
71
+ private
72
+
73
+ def locate_resource_layouts_and_partials_for_fash_refresh(path, layouts_to_reload) # rubocop:todo Metrics/AbcSize
74
+ resources.each do |resource|
75
+ next unless resource.data.layout
76
+
77
+ res_layouts = validated_layouts_for(resource, resource.data.layout)
78
+ .select { _1.path == path }
79
+ next unless res_layouts.length.positive?
80
+
81
+ res_layouts.each { layouts_to_reload << _1 }
82
+ resource.mark_for_fast_refresh!
83
+ end
84
+
85
+ tmp_cache.each_key do |key|
86
+ next unless key.delete_prefix("partial-tmpl:") == path
87
+
88
+ tmp_cache[key].template = nil
89
+ tmp_cache[key].signal.value += 1
90
+ end
91
+ end
92
+
93
+ def locate_components_for_fast_refresh(path)
94
+ comp = Bridgetown::Component.descendants.find do |item|
95
+ item.component_template_path == path || item.source_location == path
96
+ rescue StandardError # rubocop:disable Lint/SuppressedException
97
+ end
98
+ return unless comp
99
+
100
+ tmp_cache["comp-signal:#{comp.source_location}"]&.value += 1
101
+
102
+ # brute force reload all components for now
103
+ load_path = config.components_load_paths.last
104
+ loader = loaders_manager.loaders[load_path]
105
+ Bridgetown::Hooks.trigger :loader, :pre_reload, loader, load_path
106
+ loader.reload
107
+ loader.eager_load if config.eager_load_paths.include?(load_path)
108
+ Bridgetown::Hooks.trigger :loader, :post_reload, loader, load_path
109
+ end
110
+
111
+ def locate_layouts_and_pages_for_fast_refresh(path, layouts_to_reload)
112
+ generated_pages.select do |pg|
113
+ next unless pg.respond_to?(:page_to_copy)
114
+
115
+ found = in_source_dir(pg.original_resource.relative_path) == path
116
+ next true if found
117
+ next false unless pg.data.layout
118
+
119
+ pg_layouts = validated_layouts_for(pg, pg.data.layout)
120
+ .select { _1.path == path }
121
+ next false unless pg_layouts.length.positive?
122
+
123
+ pg_layouts.each { layouts_to_reload << _1 }
124
+ true
125
+ end
126
+ end
127
+
128
+ def mark_original_page_resources_for_fast_refresh(pages)
129
+ pages.each do |page|
130
+ res = page.original_resource
131
+ res.prepare_for_fast_refresh! unless res.fast_refresh_order
132
+ page.mark_for_fast_refresh!
133
+ end
134
+ end
135
+
136
+ def transform_resources_for_fast_refresh(marked_resources, found_gen_pages)
137
+ marked_resources.each { _1.transform!.write }
138
+ number_of_resources = marked_resources.length
139
+ number_of_resources += 1 if found_gen_pages
140
+ Bridgetown.logger.info(
141
+ "⚡️",
142
+ "#{number_of_resources} resource#{"s" if number_of_resources > 1} fast refreshed"
143
+ )
144
+ end
145
+
146
+ def transform_generated_pages_for_fast_refresh
147
+ marked_generated = generated_pages.select(&:fast_refresh_order).sort_by(&:fast_refresh_order)
148
+ return if marked_generated.empty?
149
+
150
+ marked_generated.each do |page|
151
+ page.fast_refresh! if page.respond_to?(:fast_refresh!)
152
+ page.transform!.write(dest)
153
+ end
154
+ number_of_pages = marked_generated.length
155
+ Bridgetown.logger.info(
156
+ "⚡️",
157
+ "#{number_of_pages} generated page#{"s" if number_of_pages > 1} fast refreshed"
158
+ )
159
+ end
160
+ end
161
+ end
@@ -35,6 +35,7 @@ class Bridgetown::Site
35
35
  self.generated_pages = []
36
36
  self.static_files = []
37
37
  self.data = HashWithDotAccess::Hash.new unless soft
38
+ @fast_refresh_ordering = 0 if config.fast_refresh
38
39
  @frontend_manifest = nil
39
40
  @collections = nil
40
41
  @documents = nil
@@ -26,19 +26,43 @@ class Bridgetown::Site
26
26
  end
27
27
  end
28
28
 
29
- def matched_converters_for_convertible(convertible)
29
+ def matched_converters_for_convertible(convertible) # rubocop:todo Metrics
30
30
  @layout_converters ||= {}
31
31
 
32
32
  if convertible.is_a?(Bridgetown::Layout) && @layout_converters[convertible]
33
33
  return @layout_converters[convertible]
34
34
  end
35
35
 
36
- matches = converters.select do |converter|
37
- if converter.method(:matches).arity == 1
38
- converter.matches(convertible.extname)
39
- else
40
- converter.matches(convertible.extname, convertible)
36
+ if convertible.is_a?(Bridgetown::GeneratedPage) && convertible.original_resource
37
+ convertible = convertible.original_resource
38
+ end
39
+
40
+ directly_matched_template_engine = nil
41
+ matches = converters.map do |converter|
42
+ result = [
43
+ converter,
44
+ converter.matches(convertible.extname, convertible),
45
+ converter.determine_template_engine(convertible),
46
+ ]
47
+
48
+ directly_matched_template_engine = converter if result[1] && converter.class.template_engine
49
+
50
+ result
51
+ end
52
+
53
+ matches = matches.filter_map do |result|
54
+ converter, ext_matched, engine_matched = result
55
+ next nil if !ext_matched && !engine_matched
56
+
57
+ next nil if !ext_matched &&
58
+ engine_matched && directly_matched_template_engine &&
59
+ converter != directly_matched_template_engine
60
+
61
+ if !convertible.data["template_engine"] && engine_matched
62
+ convertible.data["template_engine"] = converter.class.template_engine
41
63
  end
64
+
65
+ converter
42
66
  end
43
67
 
44
68
  @layout_converters[convertible] = matches if convertible.is_a?(Bridgetown::Layout)
@@ -85,7 +109,7 @@ class Bridgetown::Site
85
109
  end
86
110
 
87
111
  # Renders a content item while ensuring site locale is set if the data is available.
88
- # @param item [Document, Page, Bridgetown::Resource::Base] The item to render
112
+ # @param item [Bridgetown::Resource::Base] The item to render
89
113
  # @yield Runs the block in between locale setting and resetting
90
114
  # @return [void]
91
115
  def render_with_locale(item)