bridgetown-core 1.2.0 → 1.3.0.beta2
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.
- checksums.yaml +4 -4
- data/bridgetown-core.gemspec +21 -22
- data/lib/bridgetown-core/collection.rb +1 -1
- data/lib/bridgetown-core/commands/build.rb +3 -0
- data/lib/bridgetown-core/commands/console.rb +0 -1
- data/lib/bridgetown-core/commands/esbuild/esbuild.config.js +12 -2
- data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +64 -18
- data/lib/bridgetown-core/commands/esbuild/jsconfig.json +10 -0
- data/lib/bridgetown-core/commands/esbuild/setup.rb +1 -0
- data/lib/bridgetown-core/commands/esbuild/update.rb +3 -0
- data/lib/bridgetown-core/commands/new.rb +2 -0
- data/lib/bridgetown-core/configuration/configuration_dsl.rb +1 -1
- data/lib/bridgetown-core/configuration.rb +13 -12
- data/lib/bridgetown-core/configurations/is-land.rb +15 -0
- data/lib/bridgetown-core/configurations/lit/lit-components-entry.js +1 -1
- data/lib/bridgetown-core/configurations/lit.rb +9 -54
- data/lib/bridgetown-core/configurations/purgecss.rb +1 -1
- data/lib/bridgetown-core/configurations/ruby2js/ruby2js.rb +10 -0
- data/lib/bridgetown-core/configurations/ruby2js.rb +12 -40
- data/lib/bridgetown-core/configurations/turbo.rb +17 -7
- data/lib/bridgetown-core/errors.rb +10 -1
- data/lib/bridgetown-core/filters/localization_filters.rb +11 -0
- data/lib/bridgetown-core/helpers.rb +34 -0
- data/lib/bridgetown-core/plugin_manager.rb +0 -24
- data/lib/bridgetown-core/rack/boot.rb +13 -1
- data/lib/bridgetown-core/rack/routes.rb +40 -6
- data/lib/bridgetown-core/readers/layout_reader.rb +2 -2
- data/lib/bridgetown-core/tags/dsd.rb +15 -0
- data/lib/bridgetown-core/tags/l.rb +14 -0
- data/lib/bridgetown-core/utils/aux.rb +2 -0
- data/lib/bridgetown-core/utils/loaders_manager.rb +7 -0
- data/lib/bridgetown-core/utils.rb +52 -5
- data/lib/bridgetown-core/version.rb +2 -2
- data/lib/bridgetown-core/watcher.rb +15 -8
- data/lib/bridgetown-core.rb +12 -0
- data/lib/roda/plugins/bridgetown_server.rb +140 -0
- data/lib/site_template/Gemfile.erb +6 -3
- data/lib/site_template/frontend/javascript/index.js.erb +10 -1
- data/lib/site_template/package.json.erb +6 -6
- data/lib/site_template/server/roda_app.rb +4 -2
- data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +1 -1
- metadata +16 -27
- data/lib/bridgetown-core/commands/serve/servlet.rb +0 -68
- data/lib/bridgetown-core/commands/serve.rb +0 -253
- data/lib/bridgetown-core/rack/roda.rb +0 -157
- data/lib/roda/plugins/bridgetown_boot.rb +0 -25
@@ -15,10 +15,13 @@ module Bridgetown
|
|
15
15
|
InvalidURLError = Class.new(FatalException)
|
16
16
|
InvalidConfigurationError = Class.new(FatalException)
|
17
17
|
|
18
|
-
def self.print_build_error(exc, trace: false, logger: Bridgetown.logger)
|
18
|
+
def self.print_build_error(exc, trace: false, logger: Bridgetown.logger, server: false) # rubocop:disable Metrics
|
19
19
|
logger.error "Exception raised:", exc.class.to_s.bold
|
20
20
|
logger.error exc.message.reset_ansi
|
21
21
|
|
22
|
+
build_errors_file = Bridgetown.build_errors_path if !server && Bridgetown::Current.site
|
23
|
+
build_errors_data = "#{exc.class}: #{exc.message}"
|
24
|
+
|
22
25
|
trace_args = ["-t", "--trace"]
|
23
26
|
print_trace_msg = true
|
24
27
|
traces = if trace || ARGV.find { |arg| trace_args.include?(arg) }
|
@@ -29,6 +32,12 @@ module Bridgetown
|
|
29
32
|
end
|
30
33
|
traces.each_with_index do |backtrace_line, index|
|
31
34
|
logger.error "#{index + 1}:", backtrace_line.reset_ansi
|
35
|
+
build_errors_data << "\n#{backtrace_line}" if index < 2
|
36
|
+
end
|
37
|
+
|
38
|
+
if build_errors_file
|
39
|
+
FileUtils.mkdir_p(File.dirname(build_errors_file))
|
40
|
+
File.write(build_errors_file, build_errors_data, mode: "w")
|
32
41
|
end
|
33
42
|
|
34
43
|
return unless print_trace_msg
|
@@ -135,6 +135,14 @@ module Bridgetown
|
|
135
135
|
I18n.send :t, *args, **kwargs
|
136
136
|
end
|
137
137
|
|
138
|
+
# Forward all arguments to I18n.l method
|
139
|
+
#
|
140
|
+
# @return [String] the localized string
|
141
|
+
# @see I18n
|
142
|
+
def l(*args, **kwargs)
|
143
|
+
I18n.send :l, *args, **kwargs
|
144
|
+
end
|
145
|
+
|
138
146
|
# For template contexts where ActiveSupport's output safety is loaded, we
|
139
147
|
# can ensure a string has been marked safe
|
140
148
|
#
|
@@ -221,6 +229,32 @@ module Bridgetown
|
|
221
229
|
end
|
222
230
|
end
|
223
231
|
|
232
|
+
def dsd(input = nil, &block)
|
233
|
+
tmpl_content = block.nil? ? input.to_s : view.capture(&block)
|
234
|
+
|
235
|
+
Bridgetown::Utils.dsd_tag(tmpl_content)
|
236
|
+
end
|
237
|
+
|
238
|
+
def dsd_style
|
239
|
+
tmpl_path = caller_locations(1, 2).find do |loc|
|
240
|
+
loc.label.include?("method_missing").!
|
241
|
+
end&.path
|
242
|
+
|
243
|
+
return unless tmpl_path # virtually guaranteed not to happen
|
244
|
+
|
245
|
+
tmpl_basename = File.basename(tmpl_path, ".*")
|
246
|
+
style_path = File.join(File.dirname(tmpl_path), "#{tmpl_basename}.dsd.css")
|
247
|
+
|
248
|
+
unless File.file?(style_path)
|
249
|
+
raise Bridgetown::Errors::FatalException, "Missing stylesheet at #{style_path}"
|
250
|
+
end
|
251
|
+
|
252
|
+
style_tag = site.tmp_cache["dsd_style:#{style_path}"] ||=
|
253
|
+
"<style>#{File.read(style_path)}</style>"
|
254
|
+
|
255
|
+
style_tag.html_safe
|
256
|
+
end
|
257
|
+
|
224
258
|
private
|
225
259
|
|
226
260
|
# Covert an underscored value into a dashed string.
|
@@ -206,30 +206,6 @@ module Bridgetown
|
|
206
206
|
sorted_plugin_files.each do |plugin_file|
|
207
207
|
self.class.add_registered_plugin plugin_file
|
208
208
|
end
|
209
|
-
next if site.config[:plugins_use_zeitwerk]
|
210
|
-
|
211
|
-
Deprecator.deprecation_message(
|
212
|
-
"The `plugins_use_zeitwerk' configuration option will be removed in the next version " \
|
213
|
-
"of Bridgetown (aka will be permanently set to \"true\")"
|
214
|
-
)
|
215
|
-
Bridgetown::Utils::RequireGems.require_with_graceful_fail(sorted_plugin_files)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# Reloads .rb plugin files via the watcher
|
220
|
-
# DEPRECATED (not necessary with Zeitwerk)
|
221
|
-
#
|
222
|
-
# @return [void]
|
223
|
-
def reload_plugin_files
|
224
|
-
return if site.config[:plugins_use_zeitwerk]
|
225
|
-
|
226
|
-
plugins_path.each do |plugin_search_path|
|
227
|
-
plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb"))
|
228
|
-
Array(plugin_files).each do |name|
|
229
|
-
Bridgetown.logger.debug "Reloading:", name.to_s
|
230
|
-
self.class.add_registered_plugin name
|
231
|
-
load name
|
232
|
-
end
|
233
209
|
end
|
234
210
|
end
|
235
211
|
|
@@ -8,12 +8,22 @@ require "roda/plugins/public"
|
|
8
8
|
Bridgetown::Current.preloaded_configuration ||= Bridgetown.configuration
|
9
9
|
|
10
10
|
require_relative "logger"
|
11
|
-
require_relative "roda"
|
12
11
|
require_relative "routes"
|
13
12
|
require_relative "static_indexes"
|
14
13
|
|
15
14
|
module Bridgetown
|
16
15
|
module Rack
|
16
|
+
class Roda < ::Roda
|
17
|
+
def self.inherited(klass)
|
18
|
+
Bridgetown::Deprecator.deprecation_message(
|
19
|
+
"The `Bridgetown::Rack::Roda' class will be removed in favor of using the " \
|
20
|
+
"`bridgetown_server' plugin in a future version"
|
21
|
+
)
|
22
|
+
super
|
23
|
+
klass.plugin :bridgetown_server
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
class << self
|
18
28
|
# @return [Bridgetown::Utils::LoadersManager]
|
19
29
|
attr_accessor :loaders_manager
|
@@ -56,6 +66,8 @@ module Bridgetown
|
|
56
66
|
loader.reload
|
57
67
|
loader.eager_load
|
58
68
|
Bridgetown::Rack::Routes.reload_subclasses
|
69
|
+
rescue SyntaxError => e
|
70
|
+
Bridgetown::Errors.print_build_error(e)
|
59
71
|
end.start
|
60
72
|
end
|
61
73
|
end
|
@@ -20,6 +20,37 @@ module Bridgetown
|
|
20
20
|
}.freeze
|
21
21
|
|
22
22
|
class << self
|
23
|
+
# rubocop:disable Bridgetown/NoPutsAllowed, Metrics/MethodLength
|
24
|
+
def print_routes
|
25
|
+
# TODO: this needs to be fully documented
|
26
|
+
routes = begin
|
27
|
+
JSON.parse(
|
28
|
+
File.read(
|
29
|
+
File.join(Bridgetown::Current.preloaded_configuration.root_dir, ".routes.json")
|
30
|
+
)
|
31
|
+
)
|
32
|
+
rescue StandardError
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
puts
|
36
|
+
puts "Routes:"
|
37
|
+
puts "======="
|
38
|
+
if routes.blank?
|
39
|
+
puts "No routes found. Have you commented all of your routes?"
|
40
|
+
puts "Documentation: https://github.com/jeremyevans/roda-route_list#basic-usage-"
|
41
|
+
end
|
42
|
+
|
43
|
+
routes.each do |route|
|
44
|
+
puts [
|
45
|
+
route["methods"]&.join("|") || "GET",
|
46
|
+
route["path"],
|
47
|
+
route["file"] ? "\n File: #{route["file"]}" : nil,
|
48
|
+
].compact.join(" ")
|
49
|
+
end
|
50
|
+
puts
|
51
|
+
end
|
52
|
+
# rubocop:enable Bridgetown/NoPutsAllowed, Metrics/MethodLength
|
53
|
+
|
23
54
|
# @return [Hash<String, Class(Routes)>]
|
24
55
|
attr_accessor :tracked_subclasses
|
25
56
|
|
@@ -80,7 +111,7 @@ module Bridgetown
|
|
80
111
|
# Initialize a new Routes instance and execute the route as part of the
|
81
112
|
# Roda app request cycle
|
82
113
|
#
|
83
|
-
# @param roda_app [
|
114
|
+
# @param roda_app [Roda]
|
84
115
|
def merge(roda_app)
|
85
116
|
return unless router_block
|
86
117
|
|
@@ -90,7 +121,7 @@ module Bridgetown
|
|
90
121
|
# Start the Roda app request cycle. There are two different code paths
|
91
122
|
# depending on if there's a site `base_path` configured
|
92
123
|
#
|
93
|
-
# @param roda_app [
|
124
|
+
# @param roda_app [Roda]
|
94
125
|
# @return [void]
|
95
126
|
def start!(roda_app)
|
96
127
|
if Bridgetown::Current.preloaded_configuration.base_path == "/"
|
@@ -112,7 +143,7 @@ module Bridgetown
|
|
112
143
|
# run through all the Routes blocks. If the file-based router plugin
|
113
144
|
# is available, kick off that request process next.
|
114
145
|
#
|
115
|
-
# @param roda_app [
|
146
|
+
# @param roda_app [Roda]
|
116
147
|
# @return [void]
|
117
148
|
def load_all_routes(roda_app)
|
118
149
|
roda_app.request.public
|
@@ -127,11 +158,12 @@ module Bridgetown
|
|
127
158
|
end
|
128
159
|
end
|
129
160
|
|
130
|
-
# @param app [
|
131
|
-
def setup_live_reload(app) # rubocop:disable Metrics
|
161
|
+
# @param app [Roda]
|
162
|
+
def setup_live_reload(app) # rubocop:disable Metrics
|
132
163
|
sleep_interval = 0.2
|
133
164
|
file_to_check = File.join(Bridgetown::Current.preloaded_configuration.destination,
|
134
165
|
"index.html")
|
166
|
+
errors_file = Bridgetown.build_errors_path
|
135
167
|
|
136
168
|
app.request.get "_bridgetown/live_reload" do
|
137
169
|
app.response["Content-Type"] = "text/event-stream"
|
@@ -146,6 +178,8 @@ module Bridgetown
|
|
146
178
|
if @_mod < new_mod
|
147
179
|
out << "data: reloaded!\n\n"
|
148
180
|
break
|
181
|
+
elsif File.exist?(errors_file)
|
182
|
+
out << "event: builderror\ndata: #{File.read(errors_file).to_json}\n\n"
|
149
183
|
else
|
150
184
|
out << "data: #{new_mod}\n\n"
|
151
185
|
end
|
@@ -157,7 +191,7 @@ module Bridgetown
|
|
157
191
|
end
|
158
192
|
end
|
159
193
|
|
160
|
-
# @param roda_app [
|
194
|
+
# @param roda_app [Roda]
|
161
195
|
def initialize(roda_app)
|
162
196
|
@_roda_app = roda_app
|
163
197
|
end
|
@@ -11,13 +11,13 @@ module Bridgetown
|
|
11
11
|
|
12
12
|
def read
|
13
13
|
layout_entries.each do |layout_file|
|
14
|
-
@layouts[layout_name(layout_file)] =
|
14
|
+
@layouts[layout_name(layout_file)] =
|
15
15
|
Layout.new(site, layout_directory, layout_file)
|
16
16
|
end
|
17
17
|
|
18
18
|
site.config.source_manifests.filter_map(&:layouts).each do |plugin_layouts|
|
19
19
|
layout_entries(plugin_layouts).each do |layout_file|
|
20
|
-
@layouts[layout_name(layout_file)] ||=
|
20
|
+
@layouts[layout_name(layout_file)] ||=
|
21
21
|
Layout.new(site, plugin_layouts, layout_file, from_plugin: true)
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Tags
|
5
|
+
class DSDTag < Liquid::Block
|
6
|
+
def render(_context)
|
7
|
+
template_content = super
|
8
|
+
|
9
|
+
Bridgetown::Utils.dsd_tag(template_content)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Liquid::Template.register_tag("dsd", Bridgetown::Tags::DSDTag)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Tags
|
5
|
+
class LocalizationTag < Liquid::Tag
|
6
|
+
def render(_context)
|
7
|
+
key = @markup.strip
|
8
|
+
I18n.l(key)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Liquid::Template.register_tag("l", Bridgetown::Tags::LocalizationTag)
|
@@ -29,6 +29,8 @@ module Bridgetown
|
|
29
29
|
loop do
|
30
30
|
line = rd.gets
|
31
31
|
line.to_s.lines.map(&:chomp).each do |message|
|
32
|
+
next if name == "Frontend" && %r{ELIFECYCLE.*?Command failed}.match?(message)
|
33
|
+
|
32
34
|
output = +""
|
33
35
|
output << with_color(color, "[#{name}] ") if color
|
34
36
|
output << message
|
@@ -13,6 +13,8 @@ module Bridgetown
|
|
13
13
|
@config = config
|
14
14
|
@loaders = {}
|
15
15
|
@root_dir = config.root_dir
|
16
|
+
|
17
|
+
FileUtils.rm_f(Bridgetown.build_errors_path)
|
16
18
|
end
|
17
19
|
|
18
20
|
def unload_loaders
|
@@ -60,6 +62,9 @@ module Bridgetown
|
|
60
62
|
end
|
61
63
|
loader.enable_reloading if reloading_enabled?(load_path)
|
62
64
|
loader.ignore(File.join(load_path, "**", "*.js.rb"))
|
65
|
+
loader.ignore(
|
66
|
+
File.join(File.expand_path(config[:islands_dir], config[:source]), "routes")
|
67
|
+
)
|
63
68
|
config.autoloader_collapsed_paths.each do |collapsed_path|
|
64
69
|
next unless collapsed_path.starts_with?(load_path)
|
65
70
|
|
@@ -75,6 +80,8 @@ module Bridgetown
|
|
75
80
|
end
|
76
81
|
|
77
82
|
def reload_loaders
|
83
|
+
FileUtils.rm_f(Bridgetown.build_errors_path)
|
84
|
+
|
78
85
|
@loaders.each do |load_path, loader|
|
79
86
|
next unless reloading_enabled?(load_path)
|
80
87
|
|
@@ -412,7 +412,7 @@ module Bridgetown
|
|
412
412
|
end&.last
|
413
413
|
end
|
414
414
|
|
415
|
-
return log_frontend_asset_error(site, asset_type) if asset_path.nil?
|
415
|
+
return log_frontend_asset_error(site, "`#{asset_type}' asset") if asset_path.nil?
|
416
416
|
|
417
417
|
static_frontend_path site, [asset_path]
|
418
418
|
end
|
@@ -429,14 +429,16 @@ module Bridgetown
|
|
429
429
|
|
430
430
|
def log_frontend_asset_error(site, asset_type)
|
431
431
|
site.data[:__frontend_asset_errors] ||= {}
|
432
|
-
site.data[:__frontend_asset_errors][asset_type] ||=
|
432
|
+
site.data[:__frontend_asset_errors][asset_type] ||= begin
|
433
|
+
Bridgetown.logger.warn("#{frontend_bundler_type}:", "The #{asset_type} could not be found.")
|
433
434
|
Bridgetown.logger.warn(
|
434
435
|
"#{frontend_bundler_type}:",
|
435
|
-
"
|
436
|
-
Please check your #{asset_type} file for any errors."
|
436
|
+
"Double-check your frontend config or re-run `bin/bridgetown frontend:build'"
|
437
437
|
)
|
438
|
+
true
|
439
|
+
end
|
438
440
|
|
439
|
-
"MISSING_#{frontend_bundler_type.upcase}
|
441
|
+
"MISSING_#{frontend_bundler_type.upcase}_ASSET"
|
440
442
|
end
|
441
443
|
|
442
444
|
def frontend_bundler_type(cwd = Dir.pwd)
|
@@ -449,6 +451,27 @@ module Bridgetown
|
|
449
451
|
end
|
450
452
|
end
|
451
453
|
|
454
|
+
def update_esbuild_autogenerated_config(config)
|
455
|
+
defaults_file = File.join(config[:root_dir], "config", "esbuild.defaults.js")
|
456
|
+
return unless File.exist?(defaults_file)
|
457
|
+
|
458
|
+
config_hash = {
|
459
|
+
source: Pathname.new(config[:source]).relative_path_from(config[:root_dir]),
|
460
|
+
destination: Pathname.new(config[:destination]).relative_path_from(config[:root_dir]),
|
461
|
+
componentsDir: config[:components_dir],
|
462
|
+
islandsDir: config[:islands_dir],
|
463
|
+
}
|
464
|
+
|
465
|
+
defaults_file_contents = File.read(defaults_file)
|
466
|
+
File.write(
|
467
|
+
defaults_file,
|
468
|
+
defaults_file_contents.sub(
|
469
|
+
%r{(const autogeneratedBridgetownConfig = ){\n.*?}}m,
|
470
|
+
"\\1#{JSON.pretty_generate config_hash}"
|
471
|
+
)
|
472
|
+
)
|
473
|
+
end
|
474
|
+
|
452
475
|
def default_github_branch_name(repo_url)
|
453
476
|
repo_match = Bridgetown::Commands::Actions::GITHUB_REPO_REGEX.match(repo_url)
|
454
477
|
api_endpoint = "https://api.github.com/repos/#{repo_match[1]}"
|
@@ -466,6 +489,7 @@ module Bridgetown
|
|
466
489
|
function startReloadConnection() {
|
467
490
|
const evtSource = new EventSource("#{site.base_path(strip_slash_only: true)}/_bridgetown/live_reload")
|
468
491
|
evtSource.onmessage = event => {
|
492
|
+
if (document.querySelector("#bridgetown-build-error")) document.querySelector("#bridgetown-build-error").close()
|
469
493
|
if (event.data == "reloaded!") {
|
470
494
|
location.reload()
|
471
495
|
} else {
|
@@ -477,6 +501,23 @@ module Bridgetown
|
|
477
501
|
}
|
478
502
|
}
|
479
503
|
}
|
504
|
+
evtSource.addEventListener("builderror", event => {
|
505
|
+
let dialog = document.querySelector("#bridgetown-build-error")
|
506
|
+
if (!dialog) {
|
507
|
+
dialog = document.createElement("dialog")
|
508
|
+
dialog.id = "bridgetown-build-error"
|
509
|
+
dialog.style.borderColor = "red"
|
510
|
+
dialog.style.fontSize = "110%"
|
511
|
+
dialog.innerHTML = `
|
512
|
+
<p style="color:red">There was an error when building the site:</p>
|
513
|
+
<output><pre></pre></output>
|
514
|
+
<p><small>Check your Bridgetown logs for further details.</small></p>
|
515
|
+
`
|
516
|
+
document.body.appendChild(dialog)
|
517
|
+
dialog.showModal()
|
518
|
+
}
|
519
|
+
dialog.querySelector("pre").textContent = JSON.parse(event.data)
|
520
|
+
})
|
480
521
|
evtSource.onerror = event => {
|
481
522
|
if (evtSource.readyState === 2) {
|
482
523
|
// reconnect with new object
|
@@ -505,6 +546,12 @@ module Bridgetown
|
|
505
546
|
end
|
506
547
|
end
|
507
548
|
|
549
|
+
def dsd_tag(input, shadow_root_mode: :open)
|
550
|
+
raise ArgumentError unless [:open, :closed].include? shadow_root_mode
|
551
|
+
|
552
|
+
%(<template shadowrootmode="#{shadow_root_mode}">#{input}</template>).html_safe
|
553
|
+
end
|
554
|
+
|
508
555
|
private
|
509
556
|
|
510
557
|
def merge_values(target, overwrite)
|
@@ -55,7 +55,7 @@ module Bridgetown
|
|
55
55
|
# Start a listener to watch for changes and call {#reload_site}
|
56
56
|
#
|
57
57
|
# @param (see #watch)
|
58
|
-
def listen(site, options)
|
58
|
+
def listen(site, options) # rubocop:disable Metrics/MethodLength
|
59
59
|
bundling_path = site.frontend_bundling_path
|
60
60
|
FileUtils.mkdir_p(bundling_path)
|
61
61
|
Listen.to(
|
@@ -66,12 +66,17 @@ module Bridgetown
|
|
66
66
|
force_polling: options["force_polling"]
|
67
67
|
) do |modified, added, removed|
|
68
68
|
c = modified + added + removed
|
69
|
+
|
70
|
+
# NOTE: inexplicably, this matcher doesn't work with the Listen gem, so
|
71
|
+
# we have to run it here manually
|
72
|
+
c.reject! { component_frontend_matcher(options).match? _1 }
|
69
73
|
n = c.length
|
74
|
+
next if n.zero?
|
70
75
|
|
71
76
|
unless site.ssr?
|
72
77
|
Bridgetown.logger.info(
|
73
78
|
"Reloading…",
|
74
|
-
"#{n} file#{"s" if
|
79
|
+
"#{n} file#{"s" if n > 1} changed at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"
|
75
80
|
)
|
76
81
|
c.each { |path| Bridgetown.logger.info "", "- #{path["#{site.root_dir}/".length..]}" }
|
77
82
|
end
|
@@ -93,7 +98,6 @@ module Bridgetown
|
|
93
98
|
catch :halt do
|
94
99
|
Bridgetown::Hooks.trigger :site, :pre_reload, site, paths
|
95
100
|
Bridgetown::Hooks.clear_reloadable_hooks
|
96
|
-
site.plugin_manager.reload_plugin_files
|
97
101
|
site.loaders_manager.reload_loaders
|
98
102
|
Bridgetown::Hooks.trigger :site, :post_reload, site, paths
|
99
103
|
|
@@ -106,7 +110,7 @@ module Bridgetown
|
|
106
110
|
end
|
107
111
|
Bridgetown.logger.info "Done! 🎉", "#{"Completed".bold.green} in less than " \
|
108
112
|
"#{(Time.now - time).ceil(2)} seconds."
|
109
|
-
rescue StandardError => e
|
113
|
+
rescue StandardError, SyntaxError => e
|
110
114
|
Bridgetown::Errors.print_build_error(e, trace: options[:trace])
|
111
115
|
end
|
112
116
|
Bridgetown.logger.info ""
|
@@ -124,12 +128,15 @@ module Bridgetown
|
|
124
128
|
end
|
125
129
|
|
126
130
|
def custom_excludes(options)
|
127
|
-
Array(options["exclude"]).map { |e| Bridgetown.sanitized_path(options["
|
131
|
+
Array(options["exclude"]).map { |e| Bridgetown.sanitized_path(options["root_dir"], e) }
|
128
132
|
end
|
129
133
|
|
130
|
-
|
131
|
-
|
134
|
+
# rubocop:disable Layout/LineLength
|
135
|
+
def component_frontend_matcher(options)
|
136
|
+
@fematcher ||=
|
137
|
+
%r{(#{options[:components_dir]}|#{options[:islands_dir]})/(?:[^.]+|\.(?!dsd))+(\.js|\.jsx|\.js\.rb|\.css)$}
|
132
138
|
end
|
139
|
+
# rubocop:enable Layout/LineLength
|
133
140
|
|
134
141
|
def to_exclude(options)
|
135
142
|
[
|
@@ -162,7 +169,7 @@ module Bridgetown
|
|
162
169
|
rescue ArgumentError
|
163
170
|
# Could not find a relative path
|
164
171
|
end
|
165
|
-
end
|
172
|
+
end
|
166
173
|
end
|
167
174
|
|
168
175
|
def sleep_forever
|
data/lib/bridgetown-core.rb
CHANGED
@@ -377,6 +377,18 @@ module Bridgetown
|
|
377
377
|
File.join(base_directory, clean_path)
|
378
378
|
end
|
379
379
|
end
|
380
|
+
|
381
|
+
# When there's a build error, error details will be logged to a file which the dev server
|
382
|
+
# can read and pass along to the browser.
|
383
|
+
#
|
384
|
+
# @return [String] the path to the cached errors file
|
385
|
+
def build_errors_path
|
386
|
+
File.join(
|
387
|
+
(Bridgetown::Current.site&.config || Bridgetown::Current.preloaded_configuration).root_dir,
|
388
|
+
".bridgetown-cache",
|
389
|
+
"build_errors.txt"
|
390
|
+
)
|
391
|
+
end
|
380
392
|
end
|
381
393
|
end
|
382
394
|
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Roda
|
4
|
+
module RodaPlugins
|
5
|
+
module BridgetownServer
|
6
|
+
SiteContext = Struct.new(:registers) # for use by Liquid-esque URL helpers
|
7
|
+
|
8
|
+
def self.load_dependencies(app) # rubocop:disable Metrics
|
9
|
+
unless Bridgetown::Current.preloaded_configuration
|
10
|
+
raise "You must supply a preloaded configuration before loading the Bridgetown Roda " \
|
11
|
+
"plugin"
|
12
|
+
end
|
13
|
+
|
14
|
+
app.plugin :initializers
|
15
|
+
app.plugin :method_override
|
16
|
+
app.plugin :all_verbs
|
17
|
+
app.plugin :hooks
|
18
|
+
app.plugin :common_logger, Bridgetown::Rack::Logger.new($stdout), method: :info
|
19
|
+
app.plugin :json
|
20
|
+
app.plugin :json_parser
|
21
|
+
app.plugin :indifferent_params
|
22
|
+
app.plugin :cookies
|
23
|
+
app.plugin :streaming
|
24
|
+
app.plugin :public, root: Bridgetown::Current.preloaded_configuration.destination
|
25
|
+
app.plugin :not_found do
|
26
|
+
output_folder = Bridgetown::Current.preloaded_configuration.destination
|
27
|
+
File.read(File.join(output_folder, "404.html"))
|
28
|
+
rescue Errno::ENOENT
|
29
|
+
"404 Not Found"
|
30
|
+
end
|
31
|
+
app.plugin :exception_page
|
32
|
+
app.plugin :error_handler do |e|
|
33
|
+
Bridgetown::Errors.print_build_error(
|
34
|
+
e, logger: Bridgetown::LogAdapter.new(self.class.opts[:common_logger]), server: true
|
35
|
+
)
|
36
|
+
next exception_page(e) if ENV.fetch("RACK_ENV", nil) == "development"
|
37
|
+
|
38
|
+
output_folder = Bridgetown::Current.preloaded_configuration.destination
|
39
|
+
File.read(File.join(output_folder, "500.html"))
|
40
|
+
rescue Errno::ENOENT
|
41
|
+
"500 Internal Server Error"
|
42
|
+
end
|
43
|
+
|
44
|
+
ExceptionPage.class_eval do # rubocop:disable Metrics/BlockLength
|
45
|
+
def self.css
|
46
|
+
<<~CSS
|
47
|
+
html * { padding:0; margin:0; }
|
48
|
+
body * { padding:10px 20px; }
|
49
|
+
body * * { padding:0; }
|
50
|
+
body { font-family: -apple-system, sans-serif; font-size: 90%; }
|
51
|
+
body>div { border-bottom:1px solid #ddd; }
|
52
|
+
code { font-family: ui-monospace, monospace; }
|
53
|
+
h1 { font-weight: bold; margin-block-end: .8em; }
|
54
|
+
h2 { margin-block-end:.8em; }
|
55
|
+
h2 span { font-size:80%; color:#f7f7db; font-weight:normal; }
|
56
|
+
h3 { margin:1em 0 .5em 0; }
|
57
|
+
h4 { margin:0 0 .5em 0; font-weight: normal; }
|
58
|
+
table {
|
59
|
+
border:1px solid #ccc; border-collapse: collapse; background:white; }
|
60
|
+
tbody td, tbody th { vertical-align:top; padding:2px 3px; }
|
61
|
+
thead th {
|
62
|
+
padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
|
63
|
+
font-weight:normal; font-size:11px; border:1px solid #ddd; }
|
64
|
+
tbody th { text-align:right; opacity: 0.7; padding-right:.5em; }
|
65
|
+
table.vars { margin:5px 0 2px 40px; }
|
66
|
+
table.vars td, table.req td { font-family: ui-monospace, monospace; }
|
67
|
+
table td.code { width:100%;}
|
68
|
+
table td.code div { overflow:hidden; }
|
69
|
+
table.source th { color:#666; }
|
70
|
+
table.source td {
|
71
|
+
font-family: ui-monospace, monospace; white-space:pre; border-bottom:1px solid #eee; }
|
72
|
+
ul.traceback { list-style-type:none; }
|
73
|
+
ul.traceback li.frame { margin-bottom:1em; }
|
74
|
+
div.context { margin: 10px 0; }
|
75
|
+
div.context ol {
|
76
|
+
padding-left:30px; margin:0 10px; list-style-position: inside; }
|
77
|
+
div.context ol li {
|
78
|
+
font-family: ui-monospace, monospace; white-space:pre; color:#666; cursor:pointer; }
|
79
|
+
div.context ol.context-line li { color:black; background-color:#f7f7db; }
|
80
|
+
div.context ol.context-line li span { float: right; }
|
81
|
+
div.commands { margin-left: 40px; }
|
82
|
+
div.commands a { color:black; text-decoration:none; }
|
83
|
+
#summary { background: #1D453C; color: white; }
|
84
|
+
#summary h2 { font-weight: normal; color: white; }
|
85
|
+
#summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
|
86
|
+
#summary ul#quicklinks li { float: left; padding: 0 1em; }
|
87
|
+
#summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
|
88
|
+
#summary a { color: #f47c3c; }
|
89
|
+
#explanation { background:#eee; }
|
90
|
+
#traceback { background: white; }
|
91
|
+
#requestinfo { background:#f6f6f6; padding-left:120px; }
|
92
|
+
#summary table { border:none; background:transparent; }
|
93
|
+
#requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
|
94
|
+
#requestinfo h3 { margin-bottom:-1em; }
|
95
|
+
.error { background: #ffc; }
|
96
|
+
.specific { color:#cc3300; font-weight:bold; }
|
97
|
+
CSS
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
app.before do
|
102
|
+
if self.class.opts[:bridgetown_site]
|
103
|
+
# The site had previously been initialized via the bridgetown_ssr plugin
|
104
|
+
Bridgetown::Current.sites[self.class.opts[:bridgetown_site].label] =
|
105
|
+
self.class.opts[:bridgetown_site]
|
106
|
+
@context ||= SiteContext.new({ site: self.class.opts[:bridgetown_site] })
|
107
|
+
end
|
108
|
+
Bridgetown::Current.preloaded_configuration ||=
|
109
|
+
self.class.opts[:bridgetown_preloaded_config]
|
110
|
+
|
111
|
+
request.root do
|
112
|
+
output_folder = Bridgetown::Current.preloaded_configuration.destination
|
113
|
+
File.read(File.join(output_folder, "index.html"))
|
114
|
+
rescue StandardError
|
115
|
+
response.status = 500
|
116
|
+
"<p>ERROR: cannot find <code>index.html</code> in the output folder.</p>"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Roda::RodaRequest.alias_method :_previous_roda_cookies, :cookies
|
122
|
+
|
123
|
+
module RequestMethods
|
124
|
+
# Monkeypatch Roda/Rack's Request object so it returns a hash which allows for
|
125
|
+
# indifferent access
|
126
|
+
def cookies
|
127
|
+
# TODO: maybe replace with a simpler hash that offers an overloaded `[]` method
|
128
|
+
_previous_roda_cookies.with_indifferent_access
|
129
|
+
end
|
130
|
+
|
131
|
+
# Starts up the Bridgetown routing system
|
132
|
+
def bridgetown
|
133
|
+
Bridgetown::Rack::Routes.start!(scope)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
register_plugin :bridgetown_server, BridgetownServer
|
139
|
+
end
|
140
|
+
end
|