bridgetown-core 2.0.0.beta3 → 2.0.0.beta5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/bridgetown-core.gemspec +43 -42
  3. data/lib/bridgetown-core/collection.rb +5 -4
  4. data/lib/bridgetown-core/commands/base.rb +7 -0
  5. data/lib/bridgetown-core/commands/build.rb +29 -5
  6. data/lib/bridgetown-core/commands/console.rb +0 -1
  7. data/lib/bridgetown-core/commands/plugins.rb +4 -3
  8. data/lib/bridgetown-core/commands/start.rb +12 -2
  9. data/lib/bridgetown-core/component.rb +1 -1
  10. data/lib/bridgetown-core/concerns/intuitive_expectations.rb +67 -0
  11. data/lib/bridgetown-core/concerns/site/fast_refreshable.rb +15 -7
  12. data/lib/bridgetown-core/concerns/site/ssr.rb +1 -1
  13. data/lib/bridgetown-core/concerns/site/writable.rb +1 -0
  14. data/lib/bridgetown-core/concerns/viewable.rb +46 -0
  15. data/lib/bridgetown-core/configuration.rb +21 -9
  16. data/lib/bridgetown-core/configurations/gh-pages/gh-pages.yml +5 -5
  17. data/lib/bridgetown-core/configurations/minitesting.rb +24 -64
  18. data/lib/bridgetown-core/converters/erb_templates.rb +11 -7
  19. data/lib/bridgetown-core/converters/serbea_templates.rb +7 -4
  20. data/lib/bridgetown-core/front_matter/defaults.rb +6 -6
  21. data/lib/bridgetown-core/front_matter/loaders/ruby.rb +2 -2
  22. data/lib/bridgetown-core/front_matter/loaders/yaml.rb +2 -2
  23. data/lib/bridgetown-core/helpers.rb +2 -2
  24. data/lib/bridgetown-core/rack/boot.rb +7 -57
  25. data/lib/bridgetown-core/rack/default_config.ru +14 -0
  26. data/lib/bridgetown-core/rack/loader_hooks.rb +83 -0
  27. data/lib/bridgetown-core/rack/routes.rb +3 -2
  28. data/lib/bridgetown-core/resource/base.rb +1 -1
  29. data/lib/bridgetown-core/resource/relations.rb +3 -1
  30. data/lib/bridgetown-core/utils/initializers.rb +2 -2
  31. data/lib/bridgetown-core.rb +28 -8
  32. data/lib/roda/plugins/bridgetown_server.rb +12 -23
  33. data/lib/roda/plugins/bridgetown_ssr.rb +21 -3
  34. data/lib/roda/plugins/flashier.rb +57 -0
  35. data/lib/roda/plugins/generic_index.html +127 -0
  36. data/lib/roda/plugins/ssg.rb +3 -2
  37. data/lib/site_template/config/initializers.rb +2 -0
  38. metadata +24 -5
  39. data/lib/bridgetown-core/commands/doctor.rb +0 -147
@@ -7,93 +7,53 @@ say_status :minitesting, "Adding test gems and examples"
7
7
  append_to_file "Gemfile" do
8
8
  <<~GEMS
9
9
  \n
10
- group :test, optional: true do
11
- gem "nokogiri"
10
+ group :test do
12
11
  gem "minitest"
13
- gem "minitest-profile"
14
12
  gem "minitest-reporters"
15
- gem "shoulda"
16
- gem "rails-dom-testing"
13
+ gem "rack-test"
17
14
  end
18
15
  GEMS
19
16
  end
20
17
 
21
- create_file "test/helper.rb" do
22
- <<~RUBY
23
- require "nokogiri"
24
- require "minitest/autorun"
25
- require "minitest/reporters"
26
- require "minitest/profile"
27
- require "shoulda"
28
- require "rails-dom-testing"
18
+ gsub_file "Gemfile", '# gem "nokolexbor"', 'gem "nokolexbor"'
29
19
 
30
- # Report with color.
31
- Minitest::Reporters.use! [
32
- Minitest::Reporters::DefaultReporter.new(
33
- color: true
34
- ),
35
- ]
36
-
37
- Minitest::Test.class_eval do
38
- include Rails::Dom::Testing::Assertions
39
-
40
- def site
41
- @site ||= Bridgetown::Current.site
42
- end
43
-
44
- def nokogiri(input)
45
- input.respond_to?(:output) ? Nokogiri::HTML(input.output) : Nokogiri::HTML(input)
46
- end
47
-
48
- def document_root(root)
49
- @document_root = root.is_a?(Nokogiri::XML::Document) ? root : nokogiri(root)
50
- end
20
+ insert_into_file "Rakefile", after: %(ENV["BRIDGETOWN_ENV"] = "test"\n Bridgetown::Commands::Build.start\nend\n) do
21
+ <<~RUBY
51
22
 
52
- def document_root_element
53
- if @document_root.nil?
54
- raise "Call `document_root' with a Nokogiri document before testing your assertions"
55
- end
56
- @document_root
57
- end
23
+ require "minitest/test_task"
24
+ Minitest::TestTask.create(:test) do |t| # add on to the test task
25
+ t.warning = false
58
26
  end
59
27
  RUBY
60
28
  end
61
29
 
62
- create_file "test/test_homepage.rb" do
30
+ create_file "test/minitest_helper.rb" do
63
31
  <<~RUBY
64
- require_relative "./helper"
65
-
66
- class TestHomepage < Minitest::Test
67
- context "homepage" do
68
- setup do
69
- page = site.collections.pages.resources.find { |doc| doc.relative_url == "/" }
70
- document_root page
71
- end
32
+ ENV["MT_NO_EXPECTATIONS"] = "true"
33
+ require "minitest/autorun"
34
+ require "minitest/reporters"
35
+ Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new]
72
36
 
73
- should "exist" do
74
- assert_select "body"
75
- end
76
- end
77
- end
37
+ require "bridgetown/test"
78
38
  RUBY
79
39
  end
80
40
 
81
- create_file "plugins/test_output.rb" do
41
+ create_file "test/test_homepage.rb" do
82
42
  <<~RUBY
83
- module TestOutput
84
- unless Bridgetown.env.development?
85
- Bridgetown::Hooks.register_one :site, :post_write do
86
- # Load test suite to run on exit
87
- require "nokogiri"
88
- Dir["test/**/*.rb"].each { |file| require_relative("../\#{file}") }
89
- rescue LoadError
90
- Bridgetown.logger.warn "Testing:", "To run tests, you must first run \`bundle install --with test\`"
91
- end
43
+ require "minitest_helper"
44
+
45
+ class TestHomepage < Bridgetown::Test
46
+ def test_homepage
47
+ html get "/"
48
+
49
+ assert document.query_selector("body")
92
50
  end
93
51
  end
94
52
  RUBY
95
53
  end
96
54
 
55
+ run "bundle install", env: { "BUNDLE_GEMFILE" => Bundler::SharedHelpers.in_bundle? }
56
+
97
57
  say_status :minitesting, "All set! To get started, look at test/test_homepage.rb and then run \`bin/bridgetown test\`"
98
58
 
99
59
  # rubocop:enable all
@@ -119,13 +119,17 @@ module Bridgetown
119
119
  def convert(content, convertible)
120
120
  erb_view = Bridgetown::ERBView.new(convertible)
121
121
 
122
- erb_renderer = Tilt::ErubiTemplate.new(
123
- convertible.path,
124
- line_start(convertible),
125
- outvar: "@_erbout",
126
- bufval: "Bridgetown::OutputBuffer.new",
127
- engine_class: ERBEngine
128
- ) { content }
122
+ erb_renderer =
123
+ convertible.site.tmp_cache["erb-tmpl:#{convertible.path}:#{content.hash}"] ||=
124
+ Tilt::ErubiTemplate.new(
125
+ convertible.path,
126
+ line_start(convertible),
127
+ outvar: "@_erbout",
128
+ bufval: "Bridgetown::OutputBuffer.new",
129
+ engine_class: ERBEngine
130
+ ) do
131
+ content
132
+ end
129
133
 
130
134
  if convertible.is_a?(Bridgetown::Layout)
131
135
  erb_renderer.render(erb_view) do
@@ -34,10 +34,13 @@ module Bridgetown
34
34
  # @return [String] The converted content
35
35
  def convert(content, convertible)
36
36
  serb_view = Bridgetown::SerbeaView.new(convertible)
37
- serb_renderer = Tilt::SerbeaTemplate.new(
38
- convertible.path,
39
- line_start(convertible)
40
- ) { content }
37
+
38
+ serb_renderer =
39
+ convertible.site.tmp_cache["serb-tmpl:#{convertible.path}:#{content.hash}"] ||=
40
+ Tilt::SerbeaTemplate.new(
41
+ convertible.path,
42
+ line_start(convertible)
43
+ ) { content }
41
44
 
42
45
  if convertible.is_a?(Bridgetown::Layout)
43
46
  serb_renderer.render(serb_view) do
@@ -5,6 +5,8 @@ module Bridgetown
5
5
  # This class handles custom defaults for front matter settings.
6
6
  # It is exposed via the frontmatter_defaults method on the site class.
7
7
  class Defaults
8
+ using Bridgetown::Refinements
9
+
8
10
  # @return [Bridgetown::Site]
9
11
  attr_reader :site
10
12
 
@@ -16,6 +18,7 @@ module Bridgetown
16
18
  def reset
17
19
  @glob_cache = {}
18
20
  @defaults_cache = {}
21
+ @sets = nil
19
22
  end
20
23
 
21
24
  def ensure_time!(set)
@@ -175,15 +178,12 @@ module Bridgetown
175
178
 
176
179
  # Returns a list of valid sets
177
180
  #
178
- # This is not cached to allow plugins to modify the configuration
179
- # and have their changes take effect
180
- #
181
181
  # @return [Array<Hash>]
182
182
  def valid_sets
183
- sets = site.config["defaults"]
184
- return [] unless sets.is_a?(Array)
183
+ @sets ||= site.config["defaults"].map(&:as_dots)
184
+ return [] unless @sets.is_a?(Array)
185
185
 
186
- sets.filter_map do |set|
186
+ @sets.filter_map do |set|
187
187
  if valid?(set)
188
188
  massage_scope!(set)
189
189
  # TODO: is this trip really necessary?
@@ -62,8 +62,8 @@ module Bridgetown
62
62
  # %}~~~
63
63
  # ~~~~
64
64
  class Ruby < Base
65
- HEADER = %r!\A[~`#-]{3,}(?:ruby|<%|{%)[ \t]*\n!
66
- BLOCK = %r!#{HEADER.source}(.*?\n?)^((?:%>|%})?[~`#-]{3,}[ \t]*$\n?)!m
65
+ HEADER = %r!\A[~`#-]{3,}(?:ruby|<%|{%)[ \t\r]*\n!
66
+ BLOCK = %r!#{HEADER.source}(.*?\n?)^((?:%>|%})?[~`#-]{3,}[ \t\r]*$\n?)!m
67
67
 
68
68
  # Determines whether a given file has Ruby front matter
69
69
  #
@@ -15,8 +15,8 @@ module Bridgetown
15
15
  # ---
16
16
  # ~~~
17
17
  class YAML < Base
18
- HEADER = %r!\A---[ \t]*\n!
19
- BLOCK = %r!#{HEADER.source}(.*?\n?)^((---|\.\.\.)[ \t]*$\n?)!m
18
+ HEADER = %r!\A---[ \t\r]*\n!
19
+ BLOCK = %r!#{HEADER.source}(.*?\n?)^((---|\.\.\.)[ \t\r]*$\n?)!m
20
20
 
21
21
  # Determines whether a given file has YAML front matter
22
22
  #
@@ -11,7 +11,7 @@ module Bridgetown
11
11
  include ::Streamlined::Helpers
12
12
  include Inclusive
13
13
 
14
- # @return [Bridgetown::RubyTemplateView]
14
+ # @return [Bridgetown::RubyTemplateView, Bridgetown::Component]
15
15
  attr_reader :view
16
16
 
17
17
  # @return [Bridgetown::Site]
@@ -22,7 +22,7 @@ module Bridgetown
22
22
  # @return [Bridgetown::Foundation::SafeTranslations]
23
23
  packages def translate_package = [Bridgetown::Foundation::Packages::SafeTranslations]
24
24
 
25
- # @param view [Bridgetown::RubyTemplateView]
25
+ # @param view [Bridgetown::RubyTemplateView, Bridgetown::Component]
26
26
  # @param site [Bridgetown::Site]
27
27
  def initialize(view = nil, site = nil)
28
28
  @view = view
@@ -3,14 +3,16 @@
3
3
  require "zeitwerk"
4
4
  require "roda"
5
5
  require "json"
6
+ require "bridgetown"
6
7
 
7
- Bridgetown::Current.preloaded_configuration ||= Bridgetown.configuration
8
-
8
+ require_relative "loader_hooks"
9
9
  require_relative "logger"
10
10
  require_relative "routes"
11
11
 
12
12
  module Bridgetown
13
13
  module Rack
14
+ Bridgetown.begin!(with_config: :initializers)
15
+
14
16
  class << self
15
17
  # @return [Bridgetown::Utils::LoadersManager]
16
18
  attr_accessor :loaders_manager
@@ -23,61 +25,9 @@ module Bridgetown
23
25
  self.loaders_manager =
24
26
  Bridgetown::Utils::LoadersManager.new(Bridgetown::Current.preloaded_configuration)
25
27
  Bridgetown::Current.preloaded_configuration.run_initializers! context: :server
26
- autoload_server_folder
27
- rescue Roda::RodaError => e
28
- if e.message.include?("sessions plugin :secret option")
29
- raise Bridgetown::Errors::InvalidConfigurationError,
30
- "The Roda sessions plugin can't find a valid secret. Run `bin/bridgetown secret' " \
31
- "and put the key in a ENV var you can use to configure the session in the Roda app"
32
- end
33
-
34
- raise e
35
- end
36
-
37
- # @param root [String] root of Bridgetown site, defaults to config value
38
- def self.autoload_server_folder( # rubocop:todo Metrics
39
- root: Bridgetown::Current.preloaded_configuration.root_dir
40
- )
41
- server_folder = File.join(root, "server")
42
-
43
- Bridgetown::Hooks.register_one(
44
- :loader, :post_setup, reloadable: false
45
- ) do |loader, load_path|
46
- next unless load_path == server_folder
47
-
48
- loader.eager_load
49
- loader.do_not_eager_load(File.join(server_folder, "roda_app.rb"))
50
-
51
- unless ENV["BRIDGETOWN_ENV"] == "production"
52
- Listen.to(server_folder) do |modified, added, removed|
53
- c = modified + added + removed
54
- n = c.length
55
-
56
- Bridgetown.logger.info(
57
- "Reloading…",
58
- "#{n} file#{"s" if n > 1} changed at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"
59
- )
60
- c.each do |path|
61
- Bridgetown.logger.info "", "- #{path["#{File.dirname(server_folder)}/".length..]}"
62
- end
63
-
64
- loader.reload
65
- loader.eager_load
66
- rescue SyntaxError => e
67
- Bridgetown::Errors.print_build_error(e)
68
- end.start
69
- end
70
- end
71
-
72
- Bridgetown::Hooks.register_one(
73
- :loader, :post_reload, reloadable: false
74
- ) do |loader, load_path|
75
- next unless load_path == server_folder
76
-
77
- loader.eager_load
78
- end
79
-
80
- loaders_manager.setup_loaders([server_folder])
28
+ LoaderHooks.autoload_server_folder(
29
+ File.join(Bridgetown::Current.preloaded_configuration.root_dir, "server")
30
+ )
81
31
  end
82
32
  end
83
33
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bridgetown-core/rack/boot"
4
+
5
+ Bridgetown::Rack.boot
6
+
7
+ unless defined?(RodaApp)
8
+ class RodaApp < Roda
9
+ plugin :bridgetown_server
10
+ route(&:bridgetown)
11
+ end
12
+ end
13
+
14
+ run RodaApp.freeze.app
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Rack
5
+ module LoaderHooks
6
+ # Sets up a Zeitwerk loader for the Roda routes in the server folder. Called by the server
7
+ # boot process when Rack starts up
8
+ #
9
+ # @param server_folder [String] typically `server` within the site root
10
+ def self.autoload_server_folder(server_folder)
11
+ reload_file_path = Bridgetown.live_reload_path
12
+
13
+ register_hooks server_folder, reload_file_path
14
+
15
+ Bridgetown::Rack.loaders_manager.setup_loaders([server_folder])
16
+ end
17
+
18
+ # Registers a `post_setup` and `post_reload` hook for the Zeitwerk loader in order to handle
19
+ # eager loading and, in development, the live reload watcher
20
+ #
21
+ # @param server_folder [String]
22
+ # @param reload_file_path [String] path to the special live reload txt file
23
+ def self.register_hooks(server_folder, reload_file_path) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
24
+ Bridgetown::Hooks.register_one(
25
+ :loader, :post_setup, reloadable: false
26
+ ) do |loader, load_path|
27
+ next unless load_path == server_folder
28
+
29
+ loader.eager_load
30
+ subclass_names = Roda.subclasses.map(&:name)
31
+ subclass_paths = Set.new
32
+
33
+ loader.all_expected_cpaths.each do |cpath, cname|
34
+ if subclass_names.include?(cname) && cpath.start_with?(server_folder)
35
+ subclass_paths << cpath
36
+ loader.do_not_eager_load cpath
37
+ end
38
+ end
39
+
40
+ unless ENV["BRIDGETOWN_ENV"] == "production"
41
+ setup_autoload_listener loader, server_folder, subclass_paths
42
+ end
43
+ end
44
+
45
+ Bridgetown::Hooks.register_one(
46
+ :loader, :post_reload, reloadable: false
47
+ ) do |loader, load_path|
48
+ next unless load_path == server_folder
49
+
50
+ loader.eager_load
51
+ Bridgetown.touch_live_reload_file(reload_file_path)
52
+ end
53
+ end
54
+
55
+ # Creates a listener to detect file changes within the server folder and notify Zeitwerk
56
+ #
57
+ # @param loader [Zeitwerk::Loader]
58
+ # @param server_loader [String]
59
+ # @param subclass_paths [Array<string>]
60
+ def self.setup_autoload_listener(loader, server_folder, subclass_paths)
61
+ Listen.to(server_folder) do |modified, added, removed|
62
+ c = modified + added + removed
63
+ n = c.length
64
+
65
+ unless n == 1 && subclass_paths.include?(c.first)
66
+ Bridgetown.logger.info(
67
+ "Reloading…",
68
+ "#{n} file#{"s" if n > 1} changed at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"
69
+ )
70
+ c.each do |path|
71
+ Bridgetown.logger.info "", "- #{path["#{File.dirname(server_folder)}/".length..]}"
72
+ end
73
+ end
74
+
75
+ loader.reload
76
+ Bridgetown::Hooks.trigger :loader, :post_reload, loader, server_folder
77
+ rescue SyntaxError => e
78
+ Bridgetown::Errors.print_build_error(e)
79
+ end.start
80
+ end
81
+ end
82
+ end
83
+ end
@@ -101,13 +101,14 @@ module Bridgetown
101
101
  Bridgetown::Rack::Routes.sorted_subclasses&.each do |klass|
102
102
  klass.merge roda_app
103
103
  end
104
+
105
+ nil # required for proper 404 handling
104
106
  end
105
107
 
106
108
  # @param app [Roda]
107
109
  def setup_live_reload(app) # rubocop:disable Metrics
108
110
  sleep_interval = 0.5
109
- file_to_check = File.join(Bridgetown::Current.preloaded_configuration.destination,
110
- "index.html")
111
+ file_to_check = Bridgetown.live_reload_path
111
112
  errors_file = Bridgetown.build_errors_path
112
113
 
113
114
  app.request.get "_bridgetown/live_reload" do
@@ -364,7 +364,7 @@ module Bridgetown
364
364
  origin_data = model.origin.read
365
365
  correct_locale = origin_data["locale"] || origin_data[:locale] || data.locale
366
366
  model.attributes = origin_data
367
- model.attributes.locale = correct_locale
367
+ model.attributes.locale = correct_locale.to_s == "multi" ? data.locale : correct_locale
368
368
  @relative_url = @absolute_url = nil # wipe memoizations
369
369
  read!
370
370
  tax_diff = past_values.any? { |k, v| @data.peek[k] != v }
@@ -20,7 +20,9 @@ module Bridgetown
20
20
 
21
21
  # @return [HashWithDotAccess::Hash]
22
22
  def relation_schema
23
- resource.collection.metadata.relations
23
+ @relation_schema ||= resource.collection.metadata.relations&.transform_values do |value|
24
+ value.is_a?(Array) ? value.map(&:to_s) : value.to_s
25
+ end
24
26
  end
25
27
 
26
28
  # @return [Array<String>]
@@ -4,9 +4,9 @@ Bridgetown.initializer :dotenv do |config|
4
4
  Bridgetown.load_dotenv root: config.root_dir
5
5
  end
6
6
 
7
- Bridgetown.initializer :ssr do |config, setup: nil|
7
+ Bridgetown.initializer :ssr do |config, setup: nil, **options|
8
8
  config.roda do |app|
9
- app.plugin(:bridgetown_ssr, &setup)
9
+ app.plugin(:bridgetown_ssr, options, &setup)
10
10
  end
11
11
  end
12
12
 
@@ -54,8 +54,9 @@ I18n::Backend::Simple.include I18n::Backend::Fallbacks
54
54
 
55
55
  # Monkey patches:
56
56
 
57
+ # @!visibility private
57
58
  module HashWithDotAccess
58
- class Hash # :nodoc:
59
+ class Hash
59
60
  def to_liquid
60
61
  to_h.to_liquid
61
62
  end
@@ -99,6 +100,7 @@ module Bridgetown
99
100
  autoload :Slot, "bridgetown-core/slot"
100
101
  autoload :StaticFile, "bridgetown-core/static_file"
101
102
  autoload :Transformable, "bridgetown-core/concerns/transformable"
103
+ autoload :Viewable, "bridgetown-core/concerns/viewable"
102
104
  autoload :Utils, "bridgetown-core/utils"
103
105
  autoload :VERSION, "bridgetown-core/version"
104
106
  autoload :Watcher, "bridgetown-core/watcher"
@@ -131,10 +133,16 @@ module Bridgetown
131
133
 
132
134
  # Set up the Bridgetown execution environment before attempting to load any
133
135
  # plugins or gems prior to a site build
134
- def begin!
136
+ def begin!(with_config: :preflight)
135
137
  ENV["RACK_ENV"] ||= environment
136
138
 
137
- Bridgetown::Current.preloaded_configuration = Bridgetown::Configuration::Preflight.new
139
+ if with_config == :preflight
140
+ Bridgetown::Current.preloaded_configuration ||= Bridgetown::Configuration::Preflight.new
141
+ elsif with_config == :initializers &&
142
+ !Bridgetown::Current.preloaded_configuration.is_a?(Bridgetown::Configuration)
143
+ Bridgetown::Current.preloaded_configuration = Bridgetown.configuration
144
+ end
145
+
138
146
  Bridgetown::PluginManager.setup_bundler
139
147
  end
140
148
 
@@ -365,11 +373,23 @@ module Bridgetown
365
373
  #
366
374
  # @return [String] the path to the cached errors file
367
375
  def build_errors_path
368
- File.join(
369
- (Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration).root_dir,
370
- ".bridgetown-cache",
371
- "build_errors.txt"
372
- )
376
+ site_config = Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration
377
+ File.join(site_config.root_dir, site_config.cache_dir, "build_errors.txt")
378
+ end
379
+
380
+ # This file gets touched each time there's a new build, which then triggers live reload
381
+ # in the browser.
382
+ #
383
+ # @see Bridgetown::Rack::Routes.setup_live_reload
384
+ # @return [String] the path to the empty file being watched
385
+ def live_reload_path
386
+ site_config = Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration
387
+ File.join(site_config.root_dir, site_config.cache_dir, "live_reload.txt")
388
+ end
389
+
390
+ def touch_live_reload_file(path = live_reload_path)
391
+ FileUtils.mkdir_p File.dirname(path)
392
+ FileUtils.touch path
373
393
  end
374
394
  end
375
395
 
@@ -13,20 +13,15 @@ class Roda
13
13
 
14
14
  app.extend ClassMethods # we need to do this here because Roda hasn't done it yet
15
15
  app.plugin :initializers
16
- app.plugin :method_override
17
- app.plugin :all_verbs
18
- app.plugin :hooks
19
16
  app.plugin :common_logger, Bridgetown::Rack::Logger.new($stdout), method: :info
20
17
  app.plugin :json
21
18
  app.plugin :json_parser
22
- app.plugin :indifferent_params
23
- app.plugin :cookies, path: "/"
24
19
  app.plugin :ssg, root: Bridgetown::Current.preloaded_configuration.destination
25
20
  app.plugin :not_found do
26
21
  output_folder = Bridgetown::Current.preloaded_configuration.destination
27
22
  File.read(File.join(output_folder, "404.html"))
28
23
  rescue Errno::ENOENT
29
- "404 Not Found"
24
+ "<h1>404 Not Found</h1>"
30
25
  end
31
26
  app.plugin :exception_page
32
27
  app.plugin :error_handler do |e|
@@ -35,10 +30,10 @@ class Roda
35
30
  )
36
31
  next exception_page(e) if ENV.fetch("RACK_ENV", nil) == "development"
37
32
 
38
- output_folder = Bridgetown::Current.preloaded_configuration.destination
33
+ output_folder = self.class.opts[:bridgetown_preloaded_config].destination
39
34
  File.read(File.join(output_folder, "500.html"))
40
35
  rescue Errno::ENOENT
41
- "500 Internal Server Error"
36
+ "<h1>500 Internal Server Error</h1>"
42
37
  end
43
38
 
44
39
  # TODO: there may be a better way to do this, see `exception_page_css` instance method
@@ -123,9 +118,12 @@ class Roda
123
118
  hook_result = instance_exec(&self.class.opts[:root_hook]) if self.class.opts[:root_hook]
124
119
  next hook_result if hook_result
125
120
 
126
- status, headers, body = self.class.opts[:ssg_server].serving(
127
- request, File.join(self.class.opts[:ssg_root], "index.html")
128
- )
121
+ root_file = [
122
+ File.join(self.class.opts[:ssg_root], "index.html"),
123
+ File.expand_path("generic_index.html", __dir__),
124
+ ].find { File.exist?(_1) }
125
+
126
+ status, headers, body = self.class.opts[:ssg_server].serving(request, root_file)
129
127
  response_headers = response.headers
130
128
  response_headers.replace(headers)
131
129
 
@@ -133,7 +131,7 @@ class Roda
133
131
  rescue StandardError => e
134
132
  Bridgetown.logger.debug("Root handler error: #{e.message}")
135
133
  response.status = 500
136
- "<p>ERROR: cannot find <code>index.html</code> in the output folder.</p>"
134
+ "<p>ERROR: cannot serve the root <code>index</code> file.</p>"
137
135
  end
138
136
  end
139
137
 
@@ -158,20 +156,11 @@ class Roda
158
156
  scope.initialize_bridgetown_context
159
157
  scope.initialize_bridgetown_root
160
158
 
161
- # There are two different code paths depending on if there's a site `base_path` configured
162
- if Bridgetown::Current.preloaded_configuration.base_path == "/"
159
+ base_path = Bridgetown::Current.preloaded_configuration.base_path.delete_prefix("/")
160
+ on(base_path.empty? ? true : base_path) do
163
161
  ssg # static file server
164
162
  Bridgetown::Rack::Routes.load_all scope
165
- return
166
163
  end
167
-
168
- # Support custom base_path configurations
169
- on(Bridgetown::Current.preloaded_configuration.base_path.delete_prefix("/")) do
170
- ssg # static file server
171
- Bridgetown::Rack::Routes.load_all scope
172
- end
173
-
174
- nil
175
164
  end
176
165
  end
177
166
  end
@@ -13,13 +13,31 @@ class Roda
13
13
  alias_method :site, :bridgetown_site
14
14
  end
15
15
 
16
- def self.load_dependencies(app)
17
- app.plugin :custom_block_results
16
+ def self.load_dependencies(app, opts = { sessions: false })
17
+ app.plugin :all_verbs
18
+ app.plugin :cookies, path: "/"
19
+ app.plugin :indifferent_params
20
+ app.plugin :method_override
21
+ app.plugin :route_csrf
18
22
 
19
23
  # This lets us return callable objects directly in Roda response blocks
24
+ app.plugin :custom_block_results
20
25
  app.handle_block_result(Bridgetown::RodaCallable) do |callable|
21
- callable.(self)
26
+ request.send :block_result_body, callable.(self)
27
+ end
28
+
29
+ return unless opts[:sessions]
30
+
31
+ secret_key = ENV.fetch("RODA_SECRET_KEY", nil)
32
+ unless secret_key
33
+ raise Bridgetown::Errors::InvalidConfigurationError,
34
+ "The Roda sessions plugin can't find a valid secret. Run " \
35
+ "`bin/bridgetown secret' and put the key in your ENV as the " \
36
+ "RODA_SECRET_KEY variable"
22
37
  end
38
+
39
+ app.plugin :sessions, secret: secret_key
40
+ app.plugin :flashier
23
41
  end
24
42
 
25
43
  def self.configure(app, _opts = {}, &)