bridgetown-core 1.0.0.beta2 → 1.1.0.beta1

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/lib/bridgetown-core/collection.rb +37 -20
  4. data/lib/bridgetown-core/commands/concerns/actions.rb +3 -2
  5. data/lib/bridgetown-core/commands/configure.rb +1 -1
  6. data/lib/bridgetown-core/commands/esbuild/esbuild.config.js +20 -16
  7. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +95 -12
  8. data/lib/bridgetown-core/commands/new.rb +10 -9
  9. data/lib/bridgetown-core/commands/plugins.rb +2 -0
  10. data/lib/bridgetown-core/commands/start.rb +3 -0
  11. data/lib/bridgetown-core/commands/webpack/update.rb +2 -2
  12. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +11 -2
  13. data/lib/bridgetown-core/component.rb +13 -7
  14. data/lib/bridgetown-core/concerns/localizable.rb +20 -0
  15. data/lib/bridgetown-core/concerns/prioritizable.rb +44 -0
  16. data/lib/bridgetown-core/concerns/publishable.rb +11 -1
  17. data/lib/bridgetown-core/concerns/site/configurable.rb +2 -10
  18. data/lib/bridgetown-core/concerns/site/localizable.rb +5 -1
  19. data/lib/bridgetown-core/concerns/site/renderable.rb +27 -16
  20. data/lib/bridgetown-core/concerns/site/ssr.rb +3 -3
  21. data/lib/bridgetown-core/concerns/site/writable.rb +28 -0
  22. data/lib/bridgetown-core/concerns/transformable.rb +62 -0
  23. data/lib/bridgetown-core/configuration.rb +2 -0
  24. data/lib/bridgetown-core/configurations/bt-postcss/postcss.config.js +5 -3
  25. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -1
  26. data/lib/bridgetown-core/configurations/gh-pages/gh-pages.yml +33 -0
  27. data/lib/bridgetown-core/configurations/gh-pages.rb +16 -0
  28. data/lib/bridgetown-core/configurations/lit/esbuild-plugins.js +21 -0
  29. data/lib/bridgetown-core/configurations/lit/happy-days.lit.js +26 -0
  30. data/lib/bridgetown-core/configurations/lit/lit-components-entry.js +1 -0
  31. data/lib/bridgetown-core/configurations/lit/lit-ssr.config.js +6 -0
  32. data/lib/bridgetown-core/configurations/lit.rb +95 -0
  33. data/lib/bridgetown-core/configurations/open-props/variables.css.erb +11 -0
  34. data/lib/bridgetown-core/configurations/open-props.rb +21 -0
  35. data/lib/bridgetown-core/configurations/ruby2js/hello_world.js.rb +9 -0
  36. data/lib/bridgetown-core/configurations/ruby2js.rb +67 -0
  37. data/lib/bridgetown-core/configurations/shoelace.rb +50 -0
  38. data/lib/bridgetown-core/configurations/tailwindcss.rb +16 -2
  39. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +1 -1
  40. data/lib/bridgetown-core/drops/generated_page_drop.rb +2 -1
  41. data/lib/bridgetown-core/drops/resource_drop.rb +2 -1
  42. data/lib/bridgetown-core/errors.rb +5 -5
  43. data/lib/bridgetown-core/filters/translation_filters.rb +11 -0
  44. data/lib/bridgetown-core/filters/url_filters.rb +37 -10
  45. data/lib/bridgetown-core/filters.rb +3 -0
  46. data/lib/bridgetown-core/frontmatter_defaults.rb +14 -8
  47. data/lib/bridgetown-core/generated_page.rb +82 -17
  48. data/lib/bridgetown-core/kramdown/parser/gfm.rb +36 -0
  49. data/lib/bridgetown-core/model/base.rb +1 -2
  50. data/lib/bridgetown-core/plugin.rb +6 -37
  51. data/lib/bridgetown-core/plugin_manager.rb +3 -2
  52. data/lib/bridgetown-core/rack/boot.rb +5 -0
  53. data/lib/bridgetown-core/rack/logger.rb +14 -4
  54. data/lib/bridgetown-core/rack/roda.rb +102 -10
  55. data/lib/bridgetown-core/rack/routes.rb +87 -6
  56. data/lib/bridgetown-core/resource/base.rb +4 -6
  57. data/lib/bridgetown-core/resource/destination.rb +18 -0
  58. data/lib/bridgetown-core/resource/permalink_processor.rb +6 -4
  59. data/lib/bridgetown-core/resource/relations.rb +1 -1
  60. data/lib/bridgetown-core/resource/transformer.rb +21 -85
  61. data/lib/bridgetown-core/utils/aux.rb +2 -1
  62. data/lib/bridgetown-core/utils/require_gems.rb +3 -6
  63. data/lib/bridgetown-core/utils.rb +25 -12
  64. data/lib/bridgetown-core/version.rb +2 -2
  65. data/lib/bridgetown-core/watcher.rb +19 -6
  66. data/lib/bridgetown-core.rb +9 -3
  67. data/lib/site_template/Gemfile.erb +1 -1
  68. data/lib/site_template/README.md +2 -2
  69. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.erb +4 -4
  70. data/lib/site_template/TEMPLATES/liquid/_components/navbar.liquid +4 -4
  71. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.serb +4 -4
  72. data/lib/site_template/bridgetown.config.yml +10 -3
  73. data/lib/site_template/frontend/javascript/index.js.erb +1 -0
  74. data/lib/site_template/frontend/styles/syntax-highlighting.css +77 -0
  75. data/lib/site_template/package.json.erb +18 -17
  76. data/lib/site_template/server/roda_app.rb +3 -6
  77. data/lib/site_template/src/404.html +2 -1
  78. data/lib/site_template/src/500.html +10 -0
  79. metadata +21 -4
  80. data/lib/bridgetown-core/publisher.rb +0 -29
  81. data/lib/bridgetown-core/renderer.rb +0 -169
@@ -2,6 +2,13 @@
2
2
 
3
3
  require "rack/indifferent"
4
4
 
5
+ begin
6
+ # If it's in the Gemfile's :bridgetown_plugins group it's already been required, but we'll try
7
+ # again just to be on the safe side:
8
+ require "bridgetown-routes"
9
+ rescue LoadError
10
+ end
11
+
5
12
  class Roda
6
13
  module RodaPlugins
7
14
  module BridgetownSSR
@@ -12,6 +19,34 @@ class Roda
12
19
  end
13
20
 
14
21
  register_plugin :bridgetown_ssr, BridgetownSSR
22
+
23
+ module BridgetownBoot
24
+ module InstanceMethods
25
+ # Helper shorthand for Bridgetown::Current.site
26
+ # @return [Bridgetown::Site]
27
+ def bridgetown_site
28
+ Bridgetown::Current.site
29
+ end
30
+ end
31
+
32
+ Roda::RodaRequest.alias_method :_previous_roda_cookies, :cookies
33
+
34
+ module RequestMethods
35
+ # Monkeypatch Roda/Rack's Request object so it returns a hash which allows for
36
+ # indifferent access
37
+ def cookies
38
+ # TODO: maybe replace with a simpler hash that offers an overloaded `[]` method
39
+ _previous_roda_cookies.with_indifferent_access
40
+ end
41
+
42
+ # Starts up the Bridgetown routing system
43
+ def bridgetown
44
+ Bridgetown::Rack::Routes.start!(scope)
45
+ end
46
+ end
47
+ end
48
+
49
+ register_plugin :bridgetown_boot, BridgetownBoot
15
50
  end
16
51
  end
17
52
 
@@ -24,6 +59,7 @@ module Bridgetown
24
59
  plugin :json_parser
25
60
  plugin :cookies
26
61
  plugin :streaming
62
+ plugin :bridgetown_boot
27
63
  plugin :public, root: Bridgetown::Current.preloaded_configuration.destination
28
64
  plugin :not_found do
29
65
  output_folder = Bridgetown::Current.preloaded_configuration.destination
@@ -31,15 +67,76 @@ module Bridgetown
31
67
  rescue Errno::ENOENT
32
68
  "404 Not Found"
33
69
  end
70
+ plugin :exception_page
34
71
  plugin :error_handler do |e|
35
- puts "\n#{e.class} (#{e.message}):\n\n"
36
- puts e.backtrace
72
+ Bridgetown::Errors.print_build_error(
73
+ e, logger: Bridgetown::LogAdapter.new(self.class.opts[:common_logger])
74
+ )
75
+ next exception_page(e) if ENV.fetch("RACK_ENV", nil) == "development"
76
+
37
77
  output_folder = Bridgetown::Current.preloaded_configuration.destination
38
78
  File.read(File.join(output_folder, "500.html"))
39
79
  rescue Errno::ENOENT
40
80
  "500 Internal Server Error"
41
81
  end
42
82
 
83
+ ::Roda::RodaPlugins::ExceptionPage.class_eval do
84
+ def self.css
85
+ <<~CSS
86
+ html * { padding:0; margin:0; }
87
+ body * { padding:10px 20px; }
88
+ body * * { padding:0; }
89
+ body { font-family: -apple-system, sans-serif; font-size: 90%; }
90
+ body>div { border-bottom:1px solid #ddd; }
91
+ code { font-family: ui-monospace, monospace; }
92
+ h1 { font-weight: bold; margin-block-end: .8em; }
93
+ h2 { margin-block-end:.8em; }
94
+ h2 span { font-size:80%; color:#f7f7db; font-weight:normal; }
95
+ h3 { margin:1em 0 .5em 0; }
96
+ h4 { margin:0 0 .5em 0; font-weight: normal; }
97
+ table {
98
+ border:1px solid #ccc; border-collapse: collapse; background:white; }
99
+ tbody td, tbody th { vertical-align:top; padding:2px 3px; }
100
+ thead th {
101
+ padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
102
+ font-weight:normal; font-size:11px; border:1px solid #ddd; }
103
+ tbody th { text-align:right; opacity: 0.7; padding-right:.5em; }
104
+ table.vars { margin:5px 0 2px 40px; }
105
+ table.vars td, table.req td { font-family: ui-monospace, monospace; }
106
+ table td.code { width:100%;}
107
+ table td.code div { overflow:hidden; }
108
+ table.source th { color:#666; }
109
+ table.source td {
110
+ font-family: ui-monospace, monospace; white-space:pre; border-bottom:1px solid #eee; }
111
+ ul.traceback { list-style-type:none; }
112
+ ul.traceback li.frame { margin-bottom:1em; }
113
+ div.context { margin: 10px 0; }
114
+ div.context ol {
115
+ padding-left:30px; margin:0 10px; list-style-position: inside; }
116
+ div.context ol li {
117
+ font-family: ui-monospace, monospace; white-space:pre; color:#666; cursor:pointer; }
118
+ div.context ol.context-line li { color:black; background-color:#f7f7db; }
119
+ div.context ol.context-line li span { float: right; }
120
+ div.commands { margin-left: 40px; }
121
+ div.commands a { color:black; text-decoration:none; }
122
+ #summary { background: #1D453C; color: white; }
123
+ #summary h2 { font-weight: normal; color: white; }
124
+ #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
125
+ #summary ul#quicklinks li { float: left; padding: 0 1em; }
126
+ #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
127
+ #summary a { color: #f47c3c; }
128
+ #explanation { background:#eee; }
129
+ #traceback { background: white; }
130
+ #requestinfo { background:#f6f6f6; padding-left:120px; }
131
+ #summary table { border:none; background:transparent; }
132
+ #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
133
+ #requestinfo h3 { margin-bottom:-1em; }
134
+ .error { background: #ffc; }
135
+ .specific { color:#cc3300; font-weight:bold; }
136
+ CSS
137
+ end
138
+ end
139
+
43
140
  before do
44
141
  if self.class.opts[:bridgetown_site]
45
142
  # The site had previously been initialized via the bridgetown_ssr plugin
@@ -48,19 +145,14 @@ module Bridgetown
48
145
  Bridgetown::Current.preloaded_configuration ||=
49
146
  self.class.opts[:bridgetown_preloaded_config]
50
147
 
51
- request.public
52
-
53
148
  request.root do
54
149
  output_folder = Bridgetown::Current.preloaded_configuration.destination
55
150
  File.read(File.join(output_folder, "index.html"))
151
+ rescue StandardError
152
+ response.status = 500
153
+ "<p>ERROR: cannot find <code>index.html</code> in the output folder.</p>"
56
154
  end
57
155
  end
58
-
59
- # Helper shorthand for Bridgetown::Current.site
60
- # @return [Bridgetown::Site]
61
- def bridgetown_site
62
- Bridgetown::Current.site
63
- end
64
156
  end
65
157
  end
66
158
  end
@@ -9,19 +9,49 @@ module Bridgetown
9
9
  end
10
10
 
11
11
  class Routes
12
+ include Bridgetown::Prioritizable
13
+
14
+ self.priorities = {
15
+ highest: "010",
16
+ high: "020",
17
+ normal: "030",
18
+ low: "040",
19
+ lowest: "050",
20
+ }.freeze
21
+
12
22
  class << self
13
- attr_accessor :tracked_subclasses, :router_block
23
+ # @return [Hash<String, Class(Routes)>]
24
+ attr_accessor :tracked_subclasses
25
+
26
+ # @return [Proc]
27
+ attr_accessor :router_block
28
+
29
+ # Spaceship is priority [higher -> lower]
30
+ #
31
+ # @param other [Class(Routes)] The class to be compared.
32
+ # @return [Integer] -1, 0, 1.
33
+ def <=>(other)
34
+ "#{priorities[priority]}#{self}" <=> "#{priorities[other.priority]}#{other}"
35
+ end
14
36
 
37
+ # @param base [Class(Routes)]
15
38
  def inherited(base)
16
39
  Bridgetown::Rack::Routes.track_subclass base
17
40
  super
18
41
  end
19
42
 
43
+ # @param klass [Class(Routes)]
20
44
  def track_subclass(klass)
21
45
  Bridgetown::Rack::Routes.tracked_subclasses ||= {}
22
46
  Bridgetown::Rack::Routes.tracked_subclasses[klass.name] = klass
23
47
  end
24
48
 
49
+ # @return [Array<Class(Routes)>]
50
+ def sorted_subclasses
51
+ Bridgetown::Rack::Routes.tracked_subclasses&.values&.sort
52
+ end
53
+
54
+ # @return [void]
25
55
  def reload_subclasses
26
56
  Bridgetown::Rack::Routes.tracked_subclasses&.each_key do |klassname|
27
57
  Kernel.const_get(klassname)
@@ -30,33 +60,78 @@ module Bridgetown
30
60
  end
31
61
  end
32
62
 
63
+ # Add a router block via the current Routes class
64
+ #
65
+ # Example:
66
+ #
67
+ # class Routes::Hello < Bridgetown::Rack::Routes
68
+ # route do |r|
69
+ # r.get "hello", String do |name|
70
+ # { hello: "friend #{name}" }
71
+ # end
72
+ # end
73
+ # end
74
+ #
75
+ # @param block [Proc]
33
76
  def route(&block)
34
77
  self.router_block = block
35
78
  end
36
79
 
80
+ # Initialize a new Routes instance and execute the route as part of the
81
+ # Roda app request cycle
82
+ #
83
+ # @param roda_app [Bridgetown::Rack::Roda]
37
84
  def merge(roda_app)
38
85
  return unless router_block
39
86
 
40
87
  new(roda_app).handle_routes
41
88
  end
42
89
 
90
+ # Start the Roda app request cycle. There are two different code paths
91
+ # depending on if there's a site `base_path` configured
92
+ #
93
+ # @param roda_app [Bridgetown::Rack::Roda]
94
+ # @return [void]
43
95
  def start!(roda_app)
96
+ if Bridgetown::Current.preloaded_configuration.base_path == "/"
97
+ load_all_routes roda_app
98
+ return
99
+ end
100
+
101
+ # Support custom base_path configurations
102
+ roda_app.request.on(
103
+ Bridgetown::Current.preloaded_configuration.base_path.delete_prefix("/")
104
+ ) do
105
+ load_all_routes roda_app
106
+ end
107
+
108
+ nil
109
+ end
110
+
111
+ # Run the Roda public plugin first, set up live reload if allowed, then
112
+ # run through all the Routes blocks. If the file-based router plugin
113
+ # is available, kick off that request process next.
114
+ #
115
+ # @param roda_app [Bridgetown::Rack::Roda]
116
+ # @return [void]
117
+ def load_all_routes(roda_app)
118
+ roda_app.request.public
119
+
44
120
  if Bridgetown.env.development? &&
45
121
  !Bridgetown::Current.preloaded_configuration.skip_live_reload
46
122
  setup_live_reload roda_app
47
123
  end
48
124
 
49
- Bridgetown::Rack::Routes.tracked_subclasses&.each_value do |klass|
125
+ Bridgetown::Rack::Routes.sorted_subclasses&.each do |klass|
50
126
  klass.merge roda_app
51
127
  end
52
128
 
53
- if defined?(Bridgetown::Routes::RodaRouter)
54
- Bridgetown::Routes::RodaRouter.start!(roda_app)
55
- end
129
+ return unless defined?(Bridgetown::Routes::RodaRouter)
56
130
 
57
- nil
131
+ Bridgetown::Routes::RodaRouter.start!(roda_app)
58
132
  end
59
133
 
134
+ # @param app [Bridgetown::Rack::Roda]
60
135
  def setup_live_reload(app) # rubocop:disable Metrics/AbcSize
61
136
  sleep_interval = 0.2
62
137
  file_to_check = File.join(app.class.opts[:bridgetown_preloaded_config].destination,
@@ -86,14 +161,20 @@ module Bridgetown
86
161
  end
87
162
  end
88
163
 
164
+ # @param roda_app [Bridgetown::Rack::Roda]
89
165
  def initialize(roda_app)
90
166
  @_roda_app = roda_app
91
167
  end
92
168
 
169
+ # Execute the router block via the instance, passing it the Roda request
170
+ #
171
+ # @return [Object] whatever is returned by the router block as expected
172
+ # by the Roda API
93
173
  def handle_routes
94
174
  instance_exec(@_roda_app.request, &self.class.router_block)
95
175
  end
96
176
 
177
+ # Any missing methods are passed along to the underlying Roda app if possible
97
178
  def method_missing(method_name, *args, **kwargs, &block)
98
179
  if @_roda_app.respond_to?(method_name.to_sym)
99
180
  @_roda_app.send method_name.to_sym, *args, **kwargs, &block
@@ -7,6 +7,7 @@ module Bridgetown
7
7
  include Bridgetown::Publishable
8
8
  include Bridgetown::LayoutPlaceable
9
9
  include Bridgetown::LiquidRenderable
10
+ include Bridgetown::Localizable
10
11
 
11
12
  # @return [HashWithDotAccess::Hash]
12
13
  attr_reader :data
@@ -210,10 +211,7 @@ module Bridgetown
210
211
  def requires_destination?
211
212
  collection.write? && data.config&.output != false
212
213
  end
213
-
214
- def write?
215
- requires_destination? && site.publisher.publish?(self)
216
- end
214
+ alias_method :write?, :requires_destination?
217
215
 
218
216
  # Write the generated Document file to the destination directory.
219
217
  #
@@ -295,7 +293,7 @@ module Bridgetown
295
293
 
296
294
  private
297
295
 
298
- def ensure_default_data # rubocop:todo Metrics/AbcSize
296
+ def ensure_default_data
299
297
  determine_locale
300
298
 
301
299
  slug = if matches = relative_path.to_s.match(DATE_FILENAME_MATCHER) # rubocop:disable Lint/AssignmentInCondition
@@ -305,7 +303,7 @@ module Bridgetown
305
303
  basename_without_ext
306
304
  end
307
305
 
308
- slug.chomp!(".#{data.locale}") if data.locale && slug.ends_with?(".#{data.locale}")
306
+ Bridgetown::Utils.chomp_locale_suffix!(slug, data.locale)
309
307
 
310
308
  data.slug ||= slug
311
309
  data.title ||= Bridgetown::Utils.titleize_slug(slug)
@@ -12,6 +12,7 @@ module Bridgetown
12
12
  # @param resource [Bridgetown::Resource::Base]
13
13
  def initialize(resource)
14
14
  @resource = resource
15
+ warn_on_rails_style_extension
15
16
  @output_ext = resource.transformer.final_ext
16
17
  end
17
18
 
@@ -46,6 +47,23 @@ module Bridgetown
46
47
  Bridgetown.logger.debug "Writing:", path
47
48
  File.write(path, output, mode: "wb")
48
49
  end
50
+
51
+ private
52
+
53
+ def warn_on_rails_style_extension
54
+ return unless resource.relative_path.fnmatch?("*.{html,json,js}.*", File::FNM_EXTGLOB)
55
+
56
+ Bridgetown.logger.warn("Uh oh!", "You're using a Rails-style filename extension in:")
57
+ Bridgetown.logger.warn("", resource.relative_path)
58
+ Bridgetown.logger.warn(
59
+ "", "Instead, you can use either the desired output file extension or set a permalink."
60
+ )
61
+ Bridgetown.logger.warn(
62
+ "For more info:",
63
+ "https://www.bridgetownrb.com/docs/template-engines/erb-and-beyond#extensions-and-permalinks"
64
+ )
65
+ Bridgetown.logger.warn("")
66
+ end
49
67
  end
50
68
  end
51
69
  end
@@ -113,9 +113,8 @@ module Bridgetown
113
113
  if resource.site.config["collections_dir"].present?
114
114
  path.delete_prefix! "#{resource.site.config["collections_dir"]}/"
115
115
  end
116
- if resource.data.locale && path.ends_with?(".#{resource.data.locale}")
117
- path.chomp!(".#{resource.data.locale}")
118
- end
116
+
117
+ Bridgetown::Utils.chomp_locale_suffix!(path, resource.data.locale)
119
118
  end,
120
119
  }
121
120
  end
@@ -137,7 +136,10 @@ module Bridgetown
137
136
 
138
137
  # @param resource [Bridgetown::Resource::Base]
139
138
  register_placeholder :locale, ->(resource) do
140
- next nil if resource.data.locale&.to_sym == resource.site.config.default_locale
139
+ if !resource.site.config.prefix_default_locale &&
140
+ resource.data.locale&.to_sym == resource.site.config.default_locale
141
+ next nil
142
+ end
141
143
 
142
144
  locale_data = resource.data.locale&.to_sym
143
145
  resource.site.config.available_locales.include?(locale_data) ? locale_data.to_s : nil
@@ -68,7 +68,7 @@ module Bridgetown
68
68
  # @return [String]
69
69
  def kind_of_relation_for_type(type)
70
70
  relation_schema&.each do |relation_type, collections|
71
- collections = Array(collections).yield_self do |collections_arr|
71
+ collections = Array(collections).then do |collections_arr|
72
72
  collections_arr +
73
73
  collections_arr.map { |item| ActiveSupport::Inflector.pluralize(item) }
74
74
  end.flatten.uniq
@@ -3,6 +3,8 @@
3
3
  module Bridgetown
4
4
  module Resource
5
5
  class Transformer
6
+ include Transformable
7
+
6
8
  # @return [Array<Hash>]
7
9
  attr_reader :conversions
8
10
 
@@ -30,10 +32,18 @@ module Bridgetown
30
32
  permalink_ext || output_ext
31
33
  end
32
34
 
33
- def process!
35
+ def process! # rubocop:disable Metrics/AbcSize
34
36
  Bridgetown.logger.debug "Transforming:", resource.relative_path
35
37
  resource.around_hook :render do
36
- run_conversions
38
+ resource.content = transform_content(resource) do |converter, index, output|
39
+ conversions[index] = {
40
+ type: :content,
41
+ converter: converter,
42
+ output: Bridgetown.env.production? ? nil : output,
43
+ output_ext: conversions[index]&.dig(:output_ext) ||
44
+ converter.output_ext(resource.extname),
45
+ }
46
+ end
37
47
  resource.place_in_layout? ? place_into_layouts : resource.output = resource.content.dup
38
48
  end
39
49
  end
@@ -85,95 +95,21 @@ module Bridgetown
85
95
  .fetch(:output_ext)
86
96
  end
87
97
 
88
- # @return [Array<Bridgetown::Layout>]
89
- def validated_layouts
90
- layout = site.layouts[resource.data.layout]
91
- warn_on_missing_layout layout, resource.data.layout
92
-
93
- layout_list = Set.new([layout])
94
- while layout
95
- layout_name = layout.data.layout
96
- layout = site.layouts[layout_name]
97
- warn_on_missing_layout layout, layout_name
98
-
99
- layout_list << layout
100
- end
101
-
102
- layout_list.to_a.compact
103
- end
104
-
105
- def warn_on_missing_layout(layout, layout_name)
106
- return unless layout.nil? && layout_name
107
-
108
- Bridgetown.logger.warn(
109
- "Build Warning:",
110
- "Layout '#{layout_name}' requested via #{resource.relative_path} does not exist."
111
- )
112
- end
113
-
114
- ### Transformation Actions
115
-
116
- def run_conversions # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
117
- input = resource.content.to_s
118
-
119
- # @param content [String]
120
- # @param converter [Bridgetown::Converter]
121
- resource.content = converters.each_with_index.inject(input) do |content, (converter, index)|
122
- output = if converter.method(:convert).arity == 1
123
- converter.convert content
124
- else
125
- converter.convert content, resource
126
- end
127
- conversions[index] = {
128
- type: :content,
129
- converter: converter,
130
- output: Bridgetown.env.production? ? nil : output,
131
- output_ext: conversions[index]&.dig(:output_ext) ||
132
- converter.output_ext(resource.extname),
133
- }
134
- output.html_safe
135
- rescue StandardError => e
136
- Bridgetown.logger.error "Conversion error:",
137
- "#{converter.class} encountered an error while "\
138
- "converting `#{resource.relative_path}'"
139
- raise e
140
- end
141
- end
142
-
143
98
  def place_into_layouts
144
99
  Bridgetown.logger.debug "Placing in Layouts:", resource.relative_path
145
100
  output = resource.content.dup
146
- validated_layouts.each do |layout|
147
- output = run_layout_conversions layout, output
101
+ site.validated_layouts_for(resource, resource.data.layout).each do |layout|
102
+ output = transform_with_layout(layout, output, resource) do |converter, layout_output|
103
+ conversions << {
104
+ type: :layout,
105
+ layout: layout,
106
+ converter: converter,
107
+ output: Bridgetown.env.production? ? nil : layout_output,
108
+ }
109
+ end
148
110
  end
149
111
  resource.output = output
150
112
  end
151
-
152
- def run_layout_conversions(layout, output)
153
- layout_converters = site.matched_converters_for_convertible(layout)
154
- layout_input = layout.content.dup
155
-
156
- layout_converters.inject(layout_input) do |content, converter|
157
- next(content) unless [2, -2].include?(converter.method(:convert).arity) # rubocop:disable Performance/CollectionLiteralInLoop
158
-
159
- layout.current_document = resource
160
- layout.current_document_output = output
161
- layout_output = converter.convert content, layout
162
-
163
- conversions << {
164
- type: :layout,
165
- layout: layout,
166
- converter: converter,
167
- output: Bridgetown.env.production? ? nil : layout_output,
168
- }
169
- layout_output
170
- rescue StandardError => e
171
- Bridgetown.logger.error "Conversion error:",
172
- "#{converter.class} encountered an error while "\
173
- "converting `#{resource.relative_path}'"
174
- raise e
175
- end
176
- end
177
113
  end
178
114
  end
179
115
  end
@@ -20,7 +20,8 @@ module Bridgetown
20
20
  def self.run_process(name, color, cmd)
21
21
  Thread.new do
22
22
  rd, wr = IO.pipe("BINARY")
23
- pid = Process.spawn(cmd, out: wr, err: wr, pgroup: true)
23
+ pid = Process.spawn({ "BRIDGETOWN_NO_BUNDLER_REQUIRE" => nil },
24
+ cmd, out: wr, err: wr, pgroup: true)
24
25
  @mutex.synchronize do
25
26
  add_pid pid
26
27
  end
@@ -41,15 +41,12 @@ module Bridgetown
41
41
  require name
42
42
  rescue LoadError => e
43
43
  Bridgetown.logger.error "Dependency Error:", <<~MSG
44
- Yikes! It looks like you don't have #{name} or one of its dependencies installed.
45
- In order to use Bridgetown as currently configured, you'll need to install this gem.
44
+ Oops! It looks like you don't have #{name} or one of its dependencies installed.
45
+ Please double-check you've added #{name} to your Gemfile.
46
46
 
47
- If you've run Bridgetown with `bundle exec`, ensure that you have included the #{name}
48
- gem in your Gemfile as well.
47
+ If you're stuck, you can find help at https://www.bridgetownrb.com/community
49
48
 
50
49
  The full error message from Ruby is: '#{e.message}'
51
-
52
- If you run into trouble, you can find helpful resources at https://www.bridgetownrb.com/docs/community/
53
50
  MSG
54
51
  raise Bridgetown::Errors::MissingDependencyException, name
55
52
  end
@@ -320,7 +320,7 @@ module Bridgetown
320
320
  end
321
321
 
322
322
  if continue_processing
323
- line_indentation = line.match(%r!^ +!).yield_self do |indent|
323
+ line_indentation = line.match(%r!^ +!).then do |indent|
324
324
  indent.nil? ? "" : indent[0]
325
325
  end
326
326
  new_indentation = line_indentation.rjust(starting_indent_length, " ")
@@ -339,6 +339,11 @@ module Bridgetown
339
339
  end
340
340
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
341
341
 
342
+ # Return an asset path based on a frontend manifest file
343
+ #
344
+ # @param site [Bridgetown::Site] The current site object
345
+ # @param asset_type [String] js or css, or filename in manifest
346
+ # @return [String, nil]
342
347
  def parse_frontend_manifest_file(site, asset_type)
343
348
  case frontend_bundler_type(site.root_dir)
344
349
  when :webpack
@@ -362,9 +367,6 @@ module Bridgetown
362
367
  # file isnt found
363
368
  # @return [nil] Returns nil if the asset isnt found
364
369
  # @return [String] Returns the path to the asset if no issues parsing
365
- #
366
- # @raise [WebpackAssetError] if unable to find css or js in the manifest
367
- # file
368
370
  def parse_webpack_manifest_file(site, asset_type)
369
371
  return log_frontend_asset_error(site, "Webpack manifest") if site.frontend_manifest.nil?
370
372
 
@@ -389,16 +391,17 @@ module Bridgetown
389
391
  # file isnt found
390
392
  # @return [nil] Returns nil if the asset isnt found
391
393
  # @return [String] Returns the path to the asset if no issues parsing
392
- #
393
- # @raise [WebpackAssetError] if unable to find css or js in the manifest
394
- # file
395
394
  def parse_esbuild_manifest_file(site, asset_type) # rubocop:disable Metrics/PerceivedComplexity
396
395
  return log_frontend_asset_error(site, "esbuild manifest") if site.frontend_manifest.nil?
397
396
 
398
- asset_path = if %w(js css).include?(asset_type)
399
- folder = asset_type == "js" ? "javascript" : "styles"
400
- site.frontend_manifest["#{folder}/index.#{asset_type}"] ||
401
- site.frontend_manifest["#{folder}/index.#{asset_type}.rb"]
397
+ asset_path = case asset_type
398
+ when "css"
399
+ site.frontend_manifest["styles/index.css"] ||
400
+ site.frontend_manifest["styles/index.scss"] ||
401
+ site.frontend_manifest["styles/index.sass"]
402
+ when "js"
403
+ site.frontend_manifest["javascript/index.js"] ||
404
+ site.frontend_manifest["javascript/index.js.rb"]
402
405
  else
403
406
  site.frontend_manifest.find do |item, _|
404
407
  item.sub(%r{^../(frontend/|src/)?}, "") == asset_type
@@ -457,7 +460,7 @@ module Bridgetown
457
460
  code = <<~JAVASCRIPT
458
461
  let lastmod = 0
459
462
  function startReloadConnection() {
460
- const evtSource = new EventSource("/_bridgetown/live_reload")
463
+ const evtSource = new EventSource("#{site.base_path(strip_slash_only: true)}/_bridgetown/live_reload")
461
464
  evtSource.onmessage = event => {
462
465
  if (event.data == "reloaded!") {
463
466
  location.reload()
@@ -488,6 +491,16 @@ module Bridgetown
488
491
  %(<script type="module">#{code}</script>).html_safe
489
492
  end
490
493
 
494
+ def chomp_locale_suffix!(path, locale)
495
+ return path unless locale
496
+
497
+ if path.ends_with?(".#{locale}")
498
+ path.chomp!(".#{locale}")
499
+ elsif path.ends_with?(".multi")
500
+ path.chomp!(".multi")
501
+ end
502
+ end
503
+
491
504
  private
492
505
 
493
506
  def merge_values(target, overwrite)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- VERSION = "1.0.0.beta2"
5
- CODE_NAME = "Pearl"
4
+ VERSION = "1.1.0.beta1"
5
+ CODE_NAME = "Belmont"
6
6
  end