bridgetown-core 1.2.0 → 1.3.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|