bridgetown-core 1.0.0.alpha8 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/bin/bridgetown +14 -2
  4. data/bridgetown-core.gemspec +5 -4
  5. data/lib/bridgetown-core/collection.rb +6 -6
  6. data/lib/bridgetown-core/commands/base.rb +18 -18
  7. data/lib/bridgetown-core/commands/build.rb +1 -1
  8. data/lib/bridgetown-core/commands/clean.rb +2 -2
  9. data/lib/bridgetown-core/commands/concerns/configuration_overridable.rb +7 -0
  10. data/lib/bridgetown-core/commands/console.rb +39 -12
  11. data/lib/bridgetown-core/commands/doctor.rb +8 -5
  12. data/lib/bridgetown-core/commands/esbuild/esbuild.config.js +27 -0
  13. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +216 -0
  14. data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +47 -0
  15. data/lib/bridgetown-core/commands/esbuild/setup.rb +4 -0
  16. data/lib/bridgetown-core/commands/esbuild/update.rb +4 -0
  17. data/lib/bridgetown-core/commands/esbuild.rb +83 -0
  18. data/lib/bridgetown-core/commands/new.rb +80 -10
  19. data/lib/bridgetown-core/commands/plugins.rb +1 -1
  20. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +1 -1
  21. data/lib/bridgetown-core/commands/webpack/update.rb +3 -3
  22. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +1 -1
  23. data/lib/bridgetown-core/commands/webpack.rb +3 -3
  24. data/lib/bridgetown-core/component.rb +9 -3
  25. data/lib/bridgetown-core/concerns/site/configurable.rb +4 -0
  26. data/lib/bridgetown-core/concerns/site/content.rb +4 -4
  27. data/lib/bridgetown-core/concerns/site/extensible.rb +8 -0
  28. data/lib/bridgetown-core/concerns/site/processable.rb +22 -4
  29. data/lib/bridgetown-core/concerns/site/ssr.rb +2 -17
  30. data/lib/bridgetown-core/configurations/minitesting.rb +1 -1
  31. data/lib/bridgetown-core/configurations/purgecss.rb +2 -1
  32. data/lib/bridgetown-core/configurations/render/render.yaml.erb +3 -0
  33. data/lib/bridgetown-core/configurations/stimulus.rb +40 -12
  34. data/lib/bridgetown-core/configurations/tailwindcss/css_imports.css +5 -0
  35. data/lib/bridgetown-core/configurations/tailwindcss.rb +31 -2
  36. data/lib/bridgetown-core/configurations/turbo/turbo_transitions.js +48 -0
  37. data/lib/bridgetown-core/configurations/turbo.rb +15 -5
  38. data/lib/bridgetown-core/converters/erb_templates.rb +2 -2
  39. data/lib/bridgetown-core/converters/ruby_templates.rb +1 -1
  40. data/lib/bridgetown-core/converters/serbea_templates.rb +71 -0
  41. data/lib/bridgetown-core/drops/drop.rb +1 -1
  42. data/lib/bridgetown-core/drops/resource_drop.rb +28 -5
  43. data/lib/bridgetown-core/errors.rb +21 -0
  44. data/lib/bridgetown-core/generators/prototype_generator.rb +3 -3
  45. data/lib/bridgetown-core/helpers.rb +3 -2
  46. data/lib/bridgetown-core/hooks.rb +51 -20
  47. data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -3
  48. data/lib/bridgetown-core/model/base.rb +24 -1
  49. data/lib/bridgetown-core/model/origin.rb +4 -6
  50. data/lib/bridgetown-core/model/repo_origin.rb +48 -0
  51. data/lib/bridgetown-core/rack/boot.rb +5 -9
  52. data/lib/bridgetown-core/rack/roda.rb +4 -5
  53. data/lib/bridgetown-core/rack/routes.rb +44 -10
  54. data/lib/bridgetown-core/rack/static_indexes.rb +2 -0
  55. data/lib/bridgetown-core/resource/base.rb +2 -0
  56. data/lib/bridgetown-core/ruby_template_view.rb +4 -0
  57. data/lib/bridgetown-core/tags/{webpack_path.rb → asset_path.rb} +7 -9
  58. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -1
  59. data/lib/bridgetown-core/utils/loaders_manager.rb +11 -0
  60. data/lib/bridgetown-core/utils.rb +88 -30
  61. data/lib/bridgetown-core/version.rb +1 -1
  62. data/lib/bridgetown-core/watcher.rb +74 -70
  63. data/lib/bridgetown-core.rb +1 -1
  64. data/lib/site_template/Gemfile.erb +17 -11
  65. data/lib/site_template/README.md +2 -2
  66. data/lib/site_template/{Rakefile → Rakefile.erb} +15 -0
  67. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.erb +11 -0
  68. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.rb +5 -0
  69. data/lib/site_template/TEMPLATES/erb/_layouts/default.erb +15 -0
  70. data/lib/site_template/TEMPLATES/erb/_layouts/page.erb +7 -0
  71. data/lib/site_template/TEMPLATES/erb/_layouts/post.erb +7 -0
  72. data/lib/site_template/TEMPLATES/erb/_partials/_footer.erb +3 -0
  73. data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +10 -0
  74. data/lib/site_template/{src → TEMPLATES/liquid}/_components/footer.liquid +0 -0
  75. data/lib/site_template/TEMPLATES/liquid/_components/head.liquid +10 -0
  76. data/lib/site_template/TEMPLATES/liquid/_components/navbar.liquid +11 -0
  77. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/default.liquid +2 -2
  78. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/page.liquid +0 -0
  79. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/post.liquid +0 -0
  80. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.rb +5 -0
  81. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.serb +11 -0
  82. data/lib/site_template/TEMPLATES/serbea/_layouts/default.serb +15 -0
  83. data/lib/site_template/TEMPLATES/serbea/_layouts/page.serb +7 -0
  84. data/lib/site_template/TEMPLATES/serbea/_layouts/post.serb +7 -0
  85. data/lib/site_template/TEMPLATES/serbea/_partials/_footer.serb +3 -0
  86. data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +10 -0
  87. data/lib/site_template/frontend/javascript/index.js.erb +7 -3
  88. data/lib/site_template/frontend/styles/index.css +71 -6
  89. data/lib/site_template/package.json.erb +24 -9
  90. data/lib/site_template/ruby-version.erb +1 -0
  91. data/lib/site_template/server/roda_app.rb +5 -3
  92. data/lib/site_template/server/routes/hello.rb.sample +1 -1
  93. data/lib/site_template/src/images/logo.svg +91 -0
  94. data/lib/site_template/src/index.md.erb +22 -0
  95. data/lib/site_template/src/posts.md.erb +28 -0
  96. metadata +82 -36
  97. data/lib/bridgetown-core/configurations/swup.rb +0 -37
  98. data/lib/site_template/frontend/styles/index.scss +0 -17
  99. data/lib/site_template/src/_components/head.liquid +0 -10
  100. data/lib/site_template/src/_components/navbar.liquid +0 -5
  101. data/lib/site_template/src/_layouts/home.liquid +0 -7
  102. data/lib/site_template/src/images/.keep +0 -1
  103. data/lib/site_template/src/index.md +0 -7
  104. data/lib/site_template/src/posts.md +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0d6ef82d9ee9b28132bda459264d887de83f704a67277a0c9d4046a755e2508
4
- data.tar.gz: d39e9bb5399b5d5d7167cc20a81d3ce89fff1626c7ec13847cc5042b48a802e7
3
+ metadata.gz: b6953f85017e90090c0078b710b3e447b69366bd9fed38bd5e307ee72ae3181c
4
+ data.tar.gz: 863dcdcea016110ae4e05922f7357b866bd2a77998b5da78ffb92819238c59c4
5
5
  SHA512:
6
- metadata.gz: ff214944686584ddbc3ec0f853e60d233af3cc2d34a580141fe3771d76822770c6040429266b967133356588a01aec468b54fcd40d87cdffe844b1b307f48e85
7
- data.tar.gz: d6028a5f062ae873bac66ff929315e884844aae412999180484316d774c5480849c854ea731f993419552693058ada6aeb2abef74c5176e98802acb6d1c5a274
6
+ metadata.gz: eb6a1aa56f1544fcc37c4e204df417b5d7d37fa0e219e6a484872cdf4defee1c165fda09f4f30486d64635ef9ab6cf6db3edc8c63316dd3e61ab37be1394443c
7
+ data.tar.gz: 81b03e750b6fe6b25c1fbb2e62350f2c2776bf4902c236c5299f90c653720037e74ae8500bf71d928825efd3d83c651ad1d80523cb1362a1db2100d8f88daef9
data/.rubocop.yml CHANGED
@@ -11,6 +11,8 @@ AllCops:
11
11
  - vendor/**/*
12
12
  - tmp/**/*
13
13
  - test/source/**/*
14
+ - test/resources/src/_pages/*.rb
15
+ - lib/site_template/TEMPLATES/**/*
14
16
  - lib/site_template/Rakefile
15
17
  - lib/site_template/config.ru
16
18
  - lib/site_template/config/**/*
@@ -30,6 +32,10 @@ Performance/CollectionLiteralInLoop:
30
32
  Exclude:
31
33
  - test/test_filters.rb
32
34
 
35
+ Style/OpenStructUse:
36
+ Exclude:
37
+ - test/**/*.rb
38
+
33
39
  Style/StringConcatenation:
34
40
  Exclude:
35
41
  - test/test_apply_command.rb
data/bin/bridgetown CHANGED
@@ -19,12 +19,24 @@ Bridgetown::PluginManager.require_from_bundler
19
19
  # TODO: need to change behavior of Colorator gem
20
20
  ENV["THOR_SHELL"] = "Basic" if ENV["NO_COLOR"]
21
21
 
22
- output_version = if ARGV[0] == "-v"
22
+ output_version = if ARGV[0] == "-v" || ARGV[0] == "--version"
23
23
  puts "bridgetown #{Bridgetown::VERSION} \"#{Bridgetown::CODE_NAME}\""
24
24
  true
25
25
  end
26
26
 
27
+ if env_index = ARGV.index { |arg| arg == "-e" } # rubocop:disable Lint/AssignmentInCondition
28
+ env = ARGV[env_index + 1]
29
+ ENV["BRIDGETOWN_ENV"] = env if env
30
+ elsif env_flag = ARGV.find { |arg| arg.start_with?("--environment=") } # rubocop:disable Lint/AssignmentInCondition
31
+ ENV["BRIDGETOWN_ENV"] = env_flag.split("=").last
32
+ end
33
+
27
34
  ENV["RACK_ENV"] = ENV["BRIDGETOWN_ENV"]
28
35
 
29
36
  require "bridgetown-core/commands/base"
30
- Bridgetown::Commands::Base.start unless output_version
37
+ begin
38
+ Bridgetown::Commands::Base.start unless output_version
39
+ rescue StandardError => e
40
+ Bridgetown::Errors.print_build_error(e)
41
+ exit(false)
42
+ end
@@ -30,27 +30,28 @@ Gem::Specification.new do |s|
30
30
 
31
31
  s.required_ruby_version = ">= 2.7.0"
32
32
 
33
- s.add_runtime_dependency("activemodel", "~> 6.0")
34
- s.add_runtime_dependency("activesupport", "~> 6.0")
33
+ s.add_runtime_dependency("activemodel", [">= 6.0", "< 8.0"])
34
+ s.add_runtime_dependency("activesupport", [">= 6.0", "< 8.0"])
35
35
  s.add_runtime_dependency("addressable", "~> 2.4")
36
36
  s.add_runtime_dependency("amazing_print", "~> 1.2")
37
37
  s.add_runtime_dependency("colorator", "~> 1.0")
38
38
  s.add_runtime_dependency("erubi", "~> 1.9")
39
39
  s.add_runtime_dependency("faraday", "~> 1.0")
40
40
  s.add_runtime_dependency("faraday_middleware", "~> 1.0")
41
- s.add_runtime_dependency("hash_with_dot_access", "~> 1.0")
41
+ s.add_runtime_dependency("hash_with_dot_access", "~> 1.2")
42
42
  s.add_runtime_dependency("i18n", "~> 1.0")
43
43
  s.add_runtime_dependency("kramdown", "~> 2.1")
44
44
  s.add_runtime_dependency("kramdown-parser-gfm", "~> 1.0")
45
45
  s.add_runtime_dependency("liquid", "~> 5.0")
46
- s.add_runtime_dependency("liquid-component", ">= 0.1")
47
46
  s.add_runtime_dependency("listen", "~> 3.0")
48
47
  s.add_runtime_dependency("rack-indifferent", ">= 1.2.0")
49
48
  s.add_runtime_dependency("rake", ">= 13.0")
50
49
  s.add_runtime_dependency("roda", "~> 3.46")
51
50
  s.add_runtime_dependency("rouge", "~> 3.0")
51
+ s.add_runtime_dependency("serbea", "~> 1.0")
52
52
  s.add_runtime_dependency("terminal-table", "~> 1.8")
53
53
  s.add_runtime_dependency("thor", "~> 1.1")
54
54
  s.add_runtime_dependency("tilt", "~> 2.0")
55
55
  s.add_runtime_dependency("webrick", "~> 1.7")
56
+ s.add_runtime_dependency("zeitwerk", "~> 2.5")
56
57
  end
@@ -297,12 +297,6 @@ module Bridgetown
297
297
  resources << resource if site.config.unpublished || resource.published?
298
298
  end
299
299
 
300
- private
301
-
302
- def container
303
- @container ||= site.config["collections_dir"]
304
- end
305
-
306
300
  def sort_resources!
307
301
  if metadata["sort_by"].is_a?(String)
308
302
  sort_resources_by_key!
@@ -312,6 +306,12 @@ module Bridgetown
312
306
  resources.reverse! if metadata.sort_direction == "descending"
313
307
  end
314
308
 
309
+ private
310
+
311
+ def container
312
+ @container ||= site.config["collections_dir"]
313
+ end
314
+
315
315
  # A custom sort function based on Schwartzian transform
316
316
  # Refer https://byparker.com/blog/2017/schwartzian-transform-faster-sorting/ for details
317
317
  def sort_resources_by_key!
@@ -34,41 +34,42 @@ module Bridgetown
34
34
  rake.display_tasks_and_comments
35
35
  end
36
36
 
37
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Style/GlobalVars
37
+ def load_rake_tasks(rake)
38
+ rake.load_rakefile
39
+ tasks = rake.instance_variable_get(:@tasks)
40
+ rake.instance_variable_set(:@tasks, tasks.reject do |_k, v|
41
+ v.locations.first&.include?("/lib/rails/tasks/") ||
42
+ v.locations.first&.include?("/lib/rake/dsl_definition")
43
+ end)
44
+ end
45
+
46
+ # rubocop:disable Style/GlobalVars
38
47
  def handle_no_command_error(cmd, _has_namespace = $thor_runner)
39
48
  require "rake"
40
49
  Rake::TaskManager.record_task_metadata = true
41
50
 
42
51
  Rake.with_application do |rake|
43
- rake.instance_variable_set(:@name, "bridgetown")
44
52
  rake.standard_exception_handling do
45
53
  rakefile, _location = rake.find_rakefile_location
46
54
  unless rakefile
47
- puts "No Rakefile found (searching: #{rake.class::DEFAULT_RAKEFILES.join(", ")})\n"
55
+ puts "No Rakefile found (searching: #{rake.class::DEFAULT_RAKEFILES.join(", ")})\n\n" # rubocop:disable Layout/LineLength
48
56
  new.invoke("help")
49
57
  return # rubocop:disable Lint/NonLocalExitFromIterator
50
58
  end
51
- rake.load_rakefile
52
- rake.top_level
53
- end
54
- cmd = cmd.split("[")
55
- args = []
56
- if cmd[1]
57
- args = cmd[1].gsub("\\,", "__COMMA__").delete_suffix!("]").split(",").map do |item|
58
- item.gsub("__COMMA__", ",")
59
- end
59
+ rake.init("bridgetown")
60
+ load_rake_tasks(rake)
60
61
  end
61
62
 
62
- if Rake::Task.task_defined?(cmd[0])
63
- Rake::Task[cmd[0]].invoke(*args)
63
+ if Rake::Task.task_defined?(cmd.split("[")[0])
64
+ rake.top_level
64
65
  else
65
- puts "Unknown task: #{cmd[0]}\n\nHere's a list of tasks you can run:"
66
+ puts "Unknown task: #{cmd.split("[")[0]}\n\nHere's a list of tasks you can run:"
66
67
  display_rake_tasks(rake)
67
68
  end
68
69
  end
69
70
  end
70
71
  end
71
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Style/GlobalVars
72
+ # rubocop:enable Style/GlobalVars
72
73
 
73
74
  desc "dream", "There's a place where that idea still exists as a reality"
74
75
  def dream
@@ -101,8 +102,7 @@ module Bridgetown
101
102
  rakefile, _location = rake.find_rakefile_location
102
103
  return unless rakefile # rubocop:disable Lint/NonLocalExitFromIterator
103
104
 
104
- rake.load_rakefile
105
- rake.top_level
105
+ self.class.load_rake_tasks(rake)
106
106
  puts "Available Rake Tasks:"
107
107
  self.class.display_rake_tasks(rake)
108
108
  end
@@ -77,7 +77,7 @@ module Bridgetown
77
77
  end
78
78
  Bridgetown.logger.info "Generating…"
79
79
  @site.process
80
- Bridgetown.logger.info "Done! 🎉", "#{"Completed".green} in less than" \
80
+ Bridgetown.logger.info "Done! 🎉", "#{"Completed".bold.green} in less than" \
81
81
  " #{(Time.now - t).ceil(2)} seconds."
82
82
 
83
83
  return unless config_options[:using_puma]
@@ -21,12 +21,12 @@ module Bridgetown
21
21
  destination = config["destination"]
22
22
  metadata_file = File.join(config["root_dir"], ".bridgetown-metadata")
23
23
  cache_dir = File.join(config["root_dir"], config["cache_dir"])
24
- webpack_dir = File.join(config["root_dir"], ".bridgetown-webpack")
24
+ bundling_dir = File.join(config["root_dir"], ".bridgetown-cache", "frontend-bundling")
25
25
 
26
26
  remove(destination, checker_func: :directory?)
27
27
  remove(metadata_file, checker_func: :file?)
28
28
  remove(cache_dir, checker_func: :directory?)
29
- remove(webpack_dir, checker_func: :directory?)
29
+ remove(bundling_dir, checker_func: :directory?)
30
30
  end
31
31
 
32
32
  protected
@@ -3,6 +3,13 @@
3
3
  module Bridgetown
4
4
  module Commands
5
5
  module ConfigurationOverridable
6
+ def self.included(klass)
7
+ desc = "The environment used for this command (aka development, test, production, etc.)"
8
+ klass.class_option :environment,
9
+ aliases: "-e",
10
+ desc: desc
11
+ end
12
+
6
13
  # Create a full Bridgetown configuration with the options passed in as overrides
7
14
  #
8
15
  # options - the configuration overrides
@@ -1,6 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
+ module ConsoleMethods
5
+ def site
6
+ Bridgetown::Current.site
7
+ end
8
+
9
+ def collections
10
+ site.collections
11
+ end
12
+
13
+ def reload!
14
+ Bridgetown.logger.info "Reloading site..."
15
+
16
+ I18n.reload! # make sure any locale files get read again
17
+ Bridgetown::Hooks.trigger :site, :pre_reload, site
18
+ Bridgetown::Hooks.clear_reloadable_hooks
19
+ site.plugin_manager.reload_plugin_files
20
+ site.loaders_manager.reload_loaders
21
+ Bridgetown::Hooks.trigger :site, :post_reload, site
22
+
23
+ ConsoleMethods.site_reset(site)
24
+ end
25
+
26
+ def self.site_reset(site)
27
+ site.reset
28
+ Bridgetown.logger.info "Reading files..."
29
+ site.read
30
+ Bridgetown.logger.info "", "done!"
31
+ Bridgetown.logger.info "Running generators..."
32
+ site.generate
33
+ Bridgetown.logger.info "", "done!"
34
+ end
35
+ end
36
+
4
37
  module Commands
5
38
  class Console < Thor::Group
6
39
  extend Summarizable
@@ -37,24 +70,18 @@ module Bridgetown
37
70
  Bridgetown.logger.info "Environment:", Bridgetown.environment.cyan
38
71
  site = Bridgetown::Site.new(configuration_with_overrides(options))
39
72
 
40
- unless options[:blank]
41
- site.reset
42
- Bridgetown.logger.info "Reading files..."
43
- site.read
44
- Bridgetown.logger.info "", "done!"
45
- Bridgetown.logger.info "Running generators..."
46
- site.generate
47
- Bridgetown.logger.info "", "done!"
48
- end
73
+ ConsoleMethods.site_reset(site) unless options[:blank]
49
74
 
50
- $BRIDGETOWN_SITE = site
75
+ IRB::ExtendCommandBundle.include ConsoleMethods
51
76
  IRB.setup(nil)
52
77
  workspace = IRB::WorkSpace.new
53
78
  irb = IRB::Irb.new(workspace)
54
79
  IRB.conf[:IRB_RC]&.call(irb.context)
55
80
  IRB.conf[:MAIN_CONTEXT] = irb.context
56
- eval("site = $BRIDGETOWN_SITE", workspace.binding, __FILE__, __LINE__)
57
- Bridgetown.logger.info "Console:", "Now loaded as #{"site".cyan} variable."
81
+ Bridgetown.logger.info "Console:", "Your site is now available as #{"site".cyan}"
82
+ Bridgetown.logger.info "",
83
+ "You can also access #{"collections".cyan} or perform a" \
84
+ " #{"reload!".cyan}"
58
85
 
59
86
  trap("SIGINT") do
60
87
  irb.signal_handle
@@ -57,8 +57,7 @@ module Bridgetown
57
57
  def conflicting_urls(site)
58
58
  conflicting_urls = false
59
59
  urls = {}
60
- urls = collect_urls(urls, site.pages, site.dest)
61
- urls = collect_urls(urls, site.collections.posts.docs, site.dest)
60
+ urls = collect_urls(urls, site.contents, site.dest)
62
61
  urls.each do |url, paths|
63
62
  next unless paths.size > 1
64
63
 
@@ -98,7 +97,11 @@ module Bridgetown
98
97
 
99
98
  def collect_urls(urls, things, destination)
100
99
  things.each do |thing|
101
- dest = thing.destination(destination)
100
+ dest = if thing.method(:destination).arity == 1
101
+ thing.destination(destination)
102
+ else
103
+ thing.destination
104
+ end
102
105
  if urls[dest]
103
106
  urls[dest] << thing.path
104
107
  else
@@ -110,8 +113,8 @@ module Bridgetown
110
113
 
111
114
  def case_insensitive_urls(things, _destination)
112
115
  things.each_with_object({}) do |thing, memo|
113
- dest = thing.destination.output_path
114
- (memo[dest.downcase] ||= []) << dest
116
+ dest = thing.destination&.output_path
117
+ (memo[dest.downcase] ||= []) << dest if dest
115
118
  end
116
119
  end
117
120
 
@@ -0,0 +1,27 @@
1
+ const build = require("./config/esbuild.defaults.js")
2
+
3
+ // Update this if you need to configure a destination folder other than `output`
4
+ const outputFolder = "output"
5
+
6
+ // You can customize this as you wish, perhaps to add new esbuild plugins.
7
+ //
8
+ // Eg:
9
+ //
10
+ // ```
11
+ // const path = require("path")
12
+ // const esbuildCopy = require('esbuild-plugin-copy').default
13
+ // const esbuildOptions = {
14
+ // plugins: [
15
+ // esbuildCopy({
16
+ // assets: {
17
+ // from: [path.resolve(__dirname, 'node_modules/somepackage/files/*')],
18
+ // to: [path.resolve(__dirname, 'output/_bridgetown/somepackage/files')],
19
+ // },
20
+ // verbose: false
21
+ // }),
22
+ // ]
23
+ // }
24
+ // ```
25
+ const esbuildOptions = {}
26
+
27
+ build(outputFolder, esbuildOptions)
@@ -0,0 +1,216 @@
1
+ // This file is created and managed by Bridgetown.
2
+ // Instead of editing this file, add your overrides to `esbuild.config.js`
3
+ //
4
+ // To update this file to the latest version provided by Bridgetown,
5
+ // run `bridgetown esbuild update`. Any changes to this file will be overwritten
6
+ // when an update is applied hence we strongly recommend adding overrides to
7
+ // `esbuild.config.js` instead of editing this file.
8
+ //
9
+ // Shipped with Bridgetown v<%= Bridgetown::VERSION %>
10
+
11
+ const path = require("path")
12
+ const fsLib = require("fs")
13
+ const fs = fsLib.promises
14
+ const glob = require("glob")
15
+ const postcss = require("postcss")
16
+ const postCssImport = require("postcss-import")
17
+ const readCache = require("read-cache")
18
+
19
+ // Glob plugin derived from:
20
+ // https://github.com/thomaschaaf/esbuild-plugin-import-glob
21
+ // https://github.com/xiaohui-zhangxh/jsbundling-rails/commit/b15025dcc20f664b2b0eb238915991afdbc7cb58
22
+ const importGlobPlugin = () => ({
23
+ name: "import-glob",
24
+ setup: (build) => {
25
+ build.onResolve({ filter: /\*/ }, async (args) => {
26
+ if (args.resolveDir === "") {
27
+ return; // Ignore unresolvable paths
28
+ }
29
+
30
+ const adjustedPath = args.path.replace(/^bridgetownComponents\//, "../../src/_components/")
31
+
32
+ return {
33
+ path: adjustedPath,
34
+ namespace: "import-glob",
35
+ pluginData: {
36
+ path: adjustedPath,
37
+ resolveDir: args.resolveDir,
38
+ },
39
+ }
40
+ })
41
+
42
+ build.onLoad({ filter: /.*/, namespace: "import-glob" }, async (args) => {
43
+ const files = glob.sync(args.pluginData.path, {
44
+ cwd: args.pluginData.resolveDir,
45
+ }).sort()
46
+
47
+ const importerCode = `
48
+ ${files
49
+ .map((module, index) => `import * as module${index} from '${module}'`)
50
+ .join(';')}
51
+ const modules = {${files
52
+ .map((module, index) => `
53
+ "${module.replace("../../src/_components/", "")}": module${index},`)
54
+ .join("")}
55
+ };
56
+ export default modules;
57
+ `
58
+
59
+ return { contents: importerCode, resolveDir: args.pluginData.resolveDir }
60
+ })
61
+ },
62
+ })
63
+
64
+ const postCssPlugin = (options) => ({
65
+ name: "postcss",
66
+ async setup(build) {
67
+ // Process .css files with PostCSS
68
+ build.onLoad({ filter: /\.(css)$/ }, async (args) => {
69
+ const additionalFilePaths = []
70
+ const css = await fs.readFile(args.path, "utf8")
71
+
72
+ // Configure import plugin so PostCSS can properly resolve `@import`ed CSS files
73
+ const importPlugin = postCssImport({
74
+ filter: itemPath => {
75
+ // We'll want to track any imports later when in watch mode
76
+ additionalFilePaths.push(path.resolve(path.dirname(args.path), itemPath))
77
+ return true
78
+ },
79
+ load: async filename => {
80
+ let contents = await readCache(filename, "utf-8")
81
+ const filedir = path.dirname(filename)
82
+
83
+ // We need to transform `url(...)` in imported CSS so the filepaths are properly
84
+ // relative to the entrypoint. Seems icky to have to hack this! C'est la vie...
85
+ contents = contents.replace(/url\(['"]?\.\/(.*?)['"]?\)/g, (_match, p1) => {
86
+ const relpath = path.relative(args.path, path.resolve(filedir, p1)).replace(/^\.\.\//, "")
87
+ return `url("${relpath}")`
88
+ })
89
+ return contents
90
+ }
91
+ })
92
+
93
+ // Process the file through PostCSS
94
+ const result = await postcss([importPlugin, ...options.plugins]).process(css, {
95
+ map: true,
96
+ ...options.options,
97
+ from: args.path,
98
+ });
99
+
100
+ return {
101
+ contents: result.css,
102
+ loader: "css",
103
+ watchFiles: [args.path, ...additionalFilePaths],
104
+ }
105
+ })
106
+ },
107
+ })
108
+
109
+ // Set up defaults and generate frontend bundling manifest file
110
+ const bridgetownPreset = (outputFolder) => ({
111
+ name: "bridgetownPreset",
112
+ async setup(build) {
113
+ // Ensure any imports anywhere starting with `/` are left verbatim
114
+ // so they can be used in-browser for actual `src` repo files
115
+ build.onResolve({ filter: /^\// }, args => {
116
+ return { path: args.path, external: true }
117
+ })
118
+
119
+ build.onStart(() => {
120
+ console.log("esbuild: frontend bundling started...")
121
+ })
122
+
123
+ // Generate the final output manifest
124
+ build.onEnd(async (result) => {
125
+ if (!result.metafile) {
126
+ console.warn("esbuild: build process error, cannot write manifest")
127
+ return
128
+ }
129
+
130
+ const manifest = {}
131
+ const entrypoints = []
132
+
133
+ // We don't need `frontend/` cluttering up everything
134
+ const stripPrefix = (str) => str.replace(/^frontend\//, "")
135
+
136
+ // For calculating the file size of bundle output
137
+ const fileSize = (path) => {
138
+ const { size } = fsLib.statSync(path)
139
+ const i = Math.floor(Math.log(size) / Math.log(1024))
140
+ return (size / Math.pow(1024, i)).toFixed(2) * 1 + ['B', 'KB', 'MB', 'GB', 'TB'][i]
141
+ }
142
+
143
+ // Let's loop through all the various outputs
144
+ for (const key in result.metafile.outputs) {
145
+ const value = result.metafile.outputs[key]
146
+ const inputs = Object.keys(value.inputs)
147
+ const pathShortener = new RegExp(`^${outputFolder}\\/_bridgetown\\/static\\/`, "g")
148
+ const outputPath = key.replace(pathShortener, "")
149
+
150
+ if (value.entryPoint) {
151
+ // We have an entrypoint!
152
+ manifest[stripPrefix(value.entryPoint)] = outputPath
153
+ entrypoints.push([outputPath, fileSize(key)])
154
+ } else if (key.match(/index(\.js)?\.[^-.]*\.css/) && inputs.find(item => item.endsWith("index.css"))) {
155
+ // Special treatment for index.css
156
+ manifest[stripPrefix(inputs.find(item => item.endsWith("index.css")))] = outputPath
157
+ entrypoints.push([outputPath, fileSize(key)])
158
+ } else if (inputs.length > 0) {
159
+ // Naive implementation, we'll just grab the first input and hope it's accurate
160
+ manifest[stripPrefix(inputs[0])] = outputPath
161
+ }
162
+ }
163
+
164
+ const manifestFolder = path.join(process.cwd(), ".bridgetown-cache", "frontend-bundling")
165
+ await fs.mkdir(manifestFolder, { recursive: true })
166
+ await fs.writeFile(path.join(manifestFolder, "manifest.json"), JSON.stringify(manifest))
167
+
168
+ console.log("esbuild: frontend bundling complete!")
169
+ console.log("esbuild: entrypoints processed:")
170
+ entrypoints.forEach(entrypoint => {
171
+ const [entrypointName, entrypointSize] = entrypoint
172
+ console.log(` - ${entrypointName}: ${entrypointSize}`)
173
+ })
174
+ })
175
+ }
176
+ })
177
+
178
+ // Load the PostCSS config from postcss.config.js or whatever else is a supported location/format
179
+ const postcssrc = require("postcss-load-config")
180
+ const postCssConfig = postcssrc.sync()
181
+
182
+ module.exports = (outputFolder, esbuildOptions) => {
183
+ esbuildOptions.plugins = esbuildOptions.plugins || []
184
+ // Add the PostCSS & glob plugins to the top of the plugin stack
185
+ esbuildOptions.plugins.unshift(postCssPlugin(postCssConfig))
186
+ esbuildOptions.plugins.unshift(importGlobPlugin())
187
+ // Add the Bridgetown preset to the bottom of the plugin stack
188
+ esbuildOptions.plugins.push(bridgetownPreset(outputFolder))
189
+
190
+ // esbuild, take it away!
191
+ require("esbuild").build({
192
+ bundle: true,
193
+ loader: {
194
+ ".jpg": "file",
195
+ ".png": "file",
196
+ ".gif": "file",
197
+ ".svg": "file",
198
+ ".woff": "file",
199
+ ".woff2": "file",
200
+ ".ttf": "file",
201
+ ".eot": "file",
202
+ },
203
+ resolveExtensions: [".tsx",".ts",".jsx",".js",".css",".json",".js.rb"],
204
+ nodePaths: ["frontend/javascript", "frontend/styles"],
205
+ watch: process.argv.includes("--watch"),
206
+ minify: process.argv.includes("--minify"),
207
+ sourcemap: true,
208
+ target: "es2016",
209
+ entryPoints: ["frontend/javascript/index.js"],
210
+ entryNames: "[dir]/[name].[hash]",
211
+ outdir: path.join(process.cwd(), `${outputFolder}/_bridgetown/static`),
212
+ publicPath: "/_bridgetown/static",
213
+ metafile: true,
214
+ ...esbuildOptions,
215
+ }).catch(() => process.exit(1))
216
+ }
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Layout/LineLength
4
+
5
+ if package_json["devDependencies"].key?("sass")
6
+ say "Unable to migrate, project uses Sass. Please migrate to PostCSS first before migrating to esbuild."
7
+ return
8
+ end
9
+
10
+ remove_file "webpack.config.js"
11
+ remove_file "config/webpack.defaults.js"
12
+
13
+ apply find_in_source_paths("setup.rb"), verbose: false
14
+
15
+ default_postcss_config = File.expand_path("../../../site_template/postcss.config.js.erb", __dir__)
16
+ template default_postcss_config, "postcss.config.js"
17
+
18
+ unless Bridgetown.environment.test?
19
+ required_packages = %w(esbuild glob postcss postcss-flexbugs-fixes postcss-preset-env postcss-import postcss-load-config)
20
+ redundant_packages = %w(esbuild-loader webpack webpack-cli webpack-manifest-plugin webpack-merge css-loader file-loader mini-css-extract-plugin postcss-loader)
21
+
22
+ say "Installing required packages"
23
+
24
+ gsub_file "package.json", %r! "postcss-focus-within": "^4.0.0",?!, ""
25
+
26
+ run "yarn add -D #{required_packages.join(" ")}"
27
+
28
+ packages_to_remove = package_json["devDependencies"].slice(*redundant_packages).keys
29
+ unless packages_to_remove.empty?
30
+ confirm = ask "\nThe following packages will be removed: \n\n#{packages_to_remove.join("\n")}\n\nWould you like to continue? [Yn]"
31
+ return unless confirm.casecmp?("Y")
32
+
33
+ run "yarn remove #{packages_to_remove.join(" ")}"
34
+ end
35
+ end
36
+
37
+ gsub_file "Rakefile", %(desc "Build the frontend with Webpack for deployment"), %(desc "Build the frontend with esbuild for deployment")
38
+ gsub_file "Rakefile", %(desc "Watch the frontend with Webpack during development"), %(desc "Watch the frontend with esbuild during development")
39
+ gsub_file "Rakefile", %(sh "yarn run webpack-build"), %(sh "yarn run esbuild")
40
+ gsub_file "Rakefile", %(sh "yarn run webpack-dev --color"), %(sh "yarn run esbuild-dev")
41
+ gsub_file "package.json", %("webpack-build": "webpack --mode production"), %("esbuild": "node esbuild.config.js --minify")
42
+ gsub_file "package.json", %("webpack-dev": "webpack --mode development -w"), %("esbuild-dev": "node esbuild.config.js --watch")
43
+
44
+ say "🎉 Migration steps to esbuild finished!"
45
+ say "Make sure you replace your `webpack_path` helpers with `asset_path` helpers in your templates"
46
+
47
+ # rubocop:enable Layout/LineLength
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ template "esbuild.defaults.js.erb", "config/esbuild.defaults.js"
4
+ copy_file "esbuild.config.js", force: true
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ template "esbuild.defaults.js.erb", "config/esbuild.defaults.js", force: true
4
+ say "🎉 esbuild configuration updated successfully!"