bridgetown-core 1.0.0.alpha9 → 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/bin/bridgetown +6 -1
  4. data/bridgetown-core.gemspec +4 -3
  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/console.rb +1 -0
  10. data/lib/bridgetown-core/commands/esbuild/esbuild.config.js +27 -0
  11. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +216 -0
  12. data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +47 -0
  13. data/lib/bridgetown-core/commands/esbuild/setup.rb +4 -0
  14. data/lib/bridgetown-core/commands/esbuild/update.rb +4 -0
  15. data/lib/bridgetown-core/commands/esbuild.rb +83 -0
  16. data/lib/bridgetown-core/commands/new.rb +80 -10
  17. data/lib/bridgetown-core/commands/plugins.rb +1 -1
  18. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +1 -1
  19. data/lib/bridgetown-core/commands/webpack/update.rb +3 -3
  20. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +1 -1
  21. data/lib/bridgetown-core/commands/webpack.rb +3 -3
  22. data/lib/bridgetown-core/component.rb +9 -3
  23. data/lib/bridgetown-core/concerns/site/configurable.rb +6 -0
  24. data/lib/bridgetown-core/concerns/site/content.rb +4 -4
  25. data/lib/bridgetown-core/concerns/site/extensible.rb +8 -0
  26. data/lib/bridgetown-core/concerns/site/processable.rb +23 -4
  27. data/lib/bridgetown-core/concerns/site/ssr.rb +2 -17
  28. data/lib/bridgetown-core/configurations/minitesting.rb +1 -1
  29. data/lib/bridgetown-core/configurations/purgecss.rb +2 -1
  30. data/lib/bridgetown-core/configurations/render/render.yaml.erb +3 -0
  31. data/lib/bridgetown-core/configurations/stimulus.rb +41 -12
  32. data/lib/bridgetown-core/configurations/tailwindcss/css_imports.css +5 -0
  33. data/lib/bridgetown-core/configurations/tailwindcss.rb +31 -2
  34. data/lib/bridgetown-core/configurations/turbo/turbo_transitions.js +48 -0
  35. data/lib/bridgetown-core/configurations/turbo.rb +15 -5
  36. data/lib/bridgetown-core/configurations/vercel/vercel.json +45 -0
  37. data/lib/bridgetown-core/configurations/vercel/vercel_url.rb +12 -0
  38. data/lib/bridgetown-core/configurations/vercel.rb +4 -0
  39. data/lib/bridgetown-core/converters/erb_templates.rb +7 -9
  40. data/lib/bridgetown-core/converters/ruby_templates.rb +1 -1
  41. data/lib/bridgetown-core/converters/serbea_templates.rb +5 -8
  42. data/lib/bridgetown-core/drops/drop.rb +1 -1
  43. data/lib/bridgetown-core/drops/resource_drop.rb +28 -5
  44. data/lib/bridgetown-core/errors.rb +21 -0
  45. data/lib/bridgetown-core/generators/prototype_generator.rb +3 -3
  46. data/lib/bridgetown-core/helpers.rb +3 -2
  47. data/lib/bridgetown-core/hooks.rb +51 -20
  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 +3 -1
  56. data/lib/bridgetown-core/ruby_template_view.rb +11 -0
  57. data/lib/bridgetown-core/site.rb +5 -0
  58. data/lib/bridgetown-core/tags/{webpack_path.rb → asset_path.rb} +7 -9
  59. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -1
  60. data/lib/bridgetown-core/utils/loaders_manager.rb +17 -0
  61. data/lib/bridgetown-core/utils.rb +88 -30
  62. data/lib/bridgetown-core/version.rb +1 -1
  63. data/lib/bridgetown-core/watcher.rb +74 -70
  64. data/lib/bridgetown-core.rb +1 -0
  65. data/lib/site_template/Gemfile.erb +17 -11
  66. data/lib/site_template/README.md +2 -2
  67. data/lib/site_template/{Rakefile → Rakefile.erb} +15 -0
  68. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.erb +11 -0
  69. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.rb +5 -0
  70. data/lib/site_template/TEMPLATES/erb/_layouts/default.erb +15 -0
  71. data/lib/site_template/TEMPLATES/erb/_layouts/page.erb +7 -0
  72. data/lib/site_template/TEMPLATES/erb/_layouts/post.erb +7 -0
  73. data/lib/site_template/TEMPLATES/erb/_partials/_footer.erb +3 -0
  74. data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +10 -0
  75. data/lib/site_template/{src → TEMPLATES/liquid}/_components/footer.liquid +0 -0
  76. data/lib/site_template/TEMPLATES/liquid/_components/head.liquid +10 -0
  77. data/lib/site_template/TEMPLATES/liquid/_components/navbar.liquid +11 -0
  78. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/default.liquid +2 -2
  79. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/page.liquid +0 -0
  80. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/post.liquid +0 -0
  81. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.rb +5 -0
  82. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.serb +11 -0
  83. data/lib/site_template/TEMPLATES/serbea/_layouts/default.serb +15 -0
  84. data/lib/site_template/TEMPLATES/serbea/_layouts/page.serb +7 -0
  85. data/lib/site_template/TEMPLATES/serbea/_layouts/post.serb +7 -0
  86. data/lib/site_template/TEMPLATES/serbea/_partials/_footer.serb +3 -0
  87. data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +10 -0
  88. data/lib/site_template/frontend/javascript/index.js.erb +7 -3
  89. data/lib/site_template/frontend/styles/index.css +71 -6
  90. data/lib/site_template/package.json.erb +24 -9
  91. data/lib/site_template/ruby-version.erb +1 -0
  92. data/lib/site_template/server/roda_app.rb +5 -3
  93. data/lib/site_template/server/routes/hello.rb.sample +1 -1
  94. data/lib/site_template/src/images/logo.svg +91 -0
  95. data/lib/site_template/src/index.md.erb +22 -0
  96. data/lib/site_template/src/posts.md.erb +28 -0
  97. metadata +70 -22
  98. data/lib/bridgetown-core/configurations/swup.rb +0 -37
  99. data/lib/site_template/frontend/styles/index.scss +0 -17
  100. data/lib/site_template/src/_components/head.liquid +0 -10
  101. data/lib/site_template/src/_components/navbar.liquid +0 -5
  102. data/lib/site_template/src/_layouts/home.liquid +0 -7
  103. data/lib/site_template/src/images/.keep +0 -1
  104. data/lib/site_template/src/index.md +0 -7
  105. data/lib/site_template/src/posts.md +0 -14
@@ -24,6 +24,14 @@ module Bridgetown
24
24
  aliases: "-c",
25
25
  banner: "CONFIGURATION(S)",
26
26
  desc: "Comma separated list of bundled configurations to perform"
27
+ class_option :templates,
28
+ aliases: "-t",
29
+ banner: "liquid|erb|serbea",
30
+ desc: "Preferred template engine (defaults to Liquid)"
31
+ class_option :"frontend-bundling",
32
+ aliases: "-e",
33
+ banner: "esbuild|webpack",
34
+ desc: "Choose your frontend bundling stack (defaults to esbuild)"
27
35
  class_option :force,
28
36
  type: :boolean,
29
37
  desc: "Force creation even if PATH already exists"
@@ -33,9 +41,9 @@ module Bridgetown
33
41
  class_option :"skip-yarn",
34
42
  type: :boolean,
35
43
  desc: "Skip 'yarn install'"
36
- class_option :"use-postcss",
44
+ class_option :"use-sass",
37
45
  type: :boolean,
38
- desc: "Create an empty PostCSS configuration instead of using Sass"
46
+ desc: "(Webpack only) Create a Sass configuration instead of using PostCSS"
39
47
 
40
48
  DOCSURL = "https://bridgetownrb.com/docs"
41
49
 
@@ -54,6 +62,11 @@ module Bridgetown
54
62
  def new_site
55
63
  raise ArgumentError, "You must specify a path." if args.empty?
56
64
 
65
+ if frontend_bundling_option != "webpack" && options["use-sass"]
66
+ raise ArgumentError,
67
+ "To install Sass, you must choose Webpack (-e webpack) as your frontend bundler"
68
+ end
69
+
57
70
  new_site_path = File.expand_path(args.join(" "), Dir.pwd)
58
71
  @site_name = new_site_path.split(File::SEPARATOR).last
59
72
 
@@ -70,6 +83,8 @@ module Bridgetown
70
83
  say_status :create, new_site_path
71
84
  create_site new_site_path
72
85
  after_install new_site_path, args.join(" "), options
86
+ rescue ArgumentError => e
87
+ say_status :alert, e.message, :red
73
88
  end
74
89
 
75
90
  protected
@@ -78,24 +93,79 @@ module Bridgetown
78
93
  !options["force"] && Dir.exist?(path)
79
94
  end
80
95
 
96
+ def frontend_bundling_option
97
+ options["frontend-bundling"] == "webpack" ? "webpack" : "esbuild"
98
+ end
99
+
100
+ def postcss_option
101
+ !(frontend_bundling_option == "webpack" && options["use-sass"])
102
+ end
103
+
81
104
  def create_site(new_site_path)
82
- directory ".", ".", exclude_pattern: %r!\.erb|DS_Store$|\.(s[ac]|c)ss$!
105
+ directory ".", ".", exclude_pattern: %r!\.erb|TEMPLATES|DS_Store$|\.(s[ac]|c)ss$!
83
106
  FileUtils.chmod_R "u+w", new_site_path
84
107
 
85
108
  template(
86
109
  "src/_posts/0000-00-00-welcome-to-bridgetown.md.erb",
87
110
  "src/_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-bridgetown.md"
88
111
  )
112
+ template("ruby-version.erb", ".ruby-version")
89
113
  template("Gemfile.erb", "Gemfile")
114
+ template("Rakefile.erb", "Rakefile")
90
115
  template("package.json.erb", "package.json")
91
116
  template("frontend/javascript/index.js.erb", "frontend/javascript/index.js")
117
+ template("src/index.md.erb", "src/index.md")
118
+ template("src/posts.md.erb", "src/posts.md")
119
+
120
+ case options["templates"]
121
+ when "erb"
122
+ setup_erb_templates
123
+ when "serbea"
124
+ setup_serbea_templates
125
+ else
126
+ setup_liquid_templates
127
+ end
128
+
129
+ if frontend_bundling_option == "esbuild"
130
+ configure_postcss
131
+ invoke(Esbuild, ["setup"], {})
132
+ else
133
+ postcss_option ? configure_postcss : configure_sass
134
+ invoke(Webpack, ["setup"], {})
135
+ end
136
+ end
137
+
138
+ def setup_erb_templates
139
+ directory "TEMPLATES/erb/_layouts", "src/_layouts"
140
+ directory "TEMPLATES/erb/_components", "src/_components"
141
+ directory "TEMPLATES/erb/_partials", "src/_partials"
142
+ gsub_file "bridgetown.config.yml", %r!permalink: pretty\n!, <<~YML
143
+ permalink: pretty
144
+ template_engine: erb
145
+ YML
146
+ end
147
+
148
+ def setup_serbea_templates
149
+ directory "TEMPLATES/serbea/_layouts", "src/_layouts"
150
+ directory "TEMPLATES/serbea/_components", "src/_components"
151
+ directory "TEMPLATES/serbea/_partials", "src/_partials"
152
+ gsub_file "bridgetown.config.yml", %r!permalink: pretty\n!, <<~YML
153
+ permalink: pretty
154
+ template_engine: serbea
155
+ YML
156
+ end
92
157
 
93
- options["use-postcss"] ? configure_postcss : configure_sass
94
- invoke(Webpack, ["setup"], {})
158
+ def setup_liquid_templates
159
+ directory "TEMPLATES/liquid/_layouts", "src/_layouts"
160
+ directory "TEMPLATES/liquid/_components", "src/_components"
161
+ gsub_file "bridgetown.config.yml", %r!permalink: pretty\n!, <<~YML
162
+ permalink: pretty
163
+ template_engine: liquid
164
+ YML
95
165
  end
96
166
 
97
167
  def configure_sass
98
- copy_file("frontend/styles/index.scss")
168
+ copy_file("frontend/styles/index.css", "frontend/styles/index.scss")
99
169
  end
100
170
 
101
171
  def configure_postcss
@@ -159,9 +229,9 @@ module Bridgetown
159
229
  end
160
230
  @skipped_bundle = false
161
231
  rescue LoadError
162
- say_status :run, "Could not load Bundler. Bundle install skipped.", :red
232
+ say_status :alert, "Could not load Bundler. Bundle install skipped.", :red
163
233
  rescue SystemExit
164
- say_status :run, "Problem occured while running bundle install.", :red
234
+ say_status :alert, "Problem occured while running bundle install.", :red
165
235
  end
166
236
 
167
237
  def git_init(path)
@@ -171,7 +241,7 @@ module Bridgetown
171
241
  end
172
242
  end
173
243
  rescue SystemExit
174
- say_status :run, "Could not load git. git init skipped.", :red
244
+ say_status :alert, "Could not load git. git init skipped.", :red
175
245
  end
176
246
 
177
247
  def yarn_install(path)
@@ -182,7 +252,7 @@ module Bridgetown
182
252
  end
183
253
  @skipped_yarn = false
184
254
  rescue SystemExit
185
- say_status :run, "Could not load yarn. yarn install skipped.", :red
255
+ say_status :alert, "Could not load yarn. yarn install skipped.", :red
186
256
  end
187
257
  end
188
258
  end
@@ -187,7 +187,7 @@ module Bridgetown
187
187
  say_status "Done!", "Have fun writing your new #{name} plugin :)"
188
188
  say_status "Remember:", "Don't forget to rename the SamplePlugin" \
189
189
  " code identifiers and paths to your own" \
190
- " indentifer, as well as update your README " \
190
+ " indentifer, as well as update your README" \
191
191
  " and CHANGELOG files as necessary."
192
192
  end
193
193
 
@@ -6,7 +6,7 @@ template default_postcss_config, "postcss.config.js"
6
6
  template "webpack.defaults.js.erb", "config/webpack.defaults.js", force: true
7
7
 
8
8
  unless Bridgetown.environment.test?
9
- packages = %w(postcss@8.3.0 postcss-loader@4.3.0 postcss-flexbugs-fixes postcss-preset-env)
9
+ packages = %w(postcss postcss-loader postcss-flexbugs-fixes postcss-preset-env)
10
10
  run "yarn add -D #{packages.join(" ")}"
11
11
  run "yarn remove sass sass-loader"
12
12
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  # rubocop:disable Layout/LineLength
4
4
 
5
- required_packages = %w(esbuild esbuild-loader webpack@5.39.1 webpack-cli@4.7.2 webpack-manifest-plugin@3.1.1)
6
- redundant_packages = %w(@babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime @babel/preset-env babel-loader)
7
-
8
5
  template "webpack.defaults.js.erb", "config/webpack.defaults.js", force: true
9
6
  say "🎉 Webpack configuration updated successfully!"
10
7
 
11
8
  return if Bridgetown.environment.test?
12
9
 
10
+ required_packages = %w(esbuild esbuild-loader webpack@5.39.1 webpack-cli@4.7.2 webpack-manifest-plugin@3.1.1)
11
+ redundant_packages = %w(@babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime @babel/preset-env babel-loader)
12
+
13
13
  say "Installing required packages"
14
14
  run "yarn add -D #{required_packages.join(" ")}"
15
15
 
@@ -119,7 +119,7 @@ module.exports = {
119
119
  filename: "../css/[name].[contenthash].css",
120
120
  }),
121
121
  new WebpackManifestPlugin({
122
- fileName: path.resolve(rootDir, ".bridgetown-webpack", "manifest.json"),
122
+ fileName: path.resolve(rootDir, ".bridgetown-cache", "frontend-bundling", "manifest.json"),
123
123
  }),
124
124
  ],
125
125
  module: {
@@ -13,7 +13,7 @@ module Bridgetown
13
13
  def self.banner
14
14
  "bridgetown webpack ACTION"
15
15
  end
16
- summary "Perform actions on the bridgetown webpack configuration"
16
+ summary "Perform actions on the Bridgetown Webpack configuration"
17
17
 
18
18
  def self.exit_on_failure?
19
19
  true
@@ -72,8 +72,8 @@ module Bridgetown
72
72
 
73
73
  def supported_actions
74
74
  {
75
- setup: "Sets up a webpack integration with Bridgetown in your project",
76
- update: "Updates the Bridgetown webpack defaults to the latest available version",
75
+ setup: "Sets up a Webpack integration with Bridgetown in your project",
76
+ update: "Updates the Bridgetown Webpack defaults to the latest available version",
77
77
  "enable-postcss": "Configures PostCSS in your project",
78
78
  }.with_indifferent_access
79
79
  end
@@ -91,6 +91,12 @@ module Bridgetown
91
91
  def supported_template_extensions
92
92
  %w(erb serb slim haml)
93
93
  end
94
+
95
+ def path_for_errors
96
+ component_template_path
97
+ rescue RuntimeError
98
+ source_location
99
+ end
94
100
  end
95
101
 
96
102
  # If a content block was originally passed into via `render`, capture its output.
@@ -133,7 +139,7 @@ module Bridgetown
133
139
  rescue StandardError => e
134
140
  Bridgetown.logger.error "Component error:",
135
141
  "#{self.class} encountered an error while "\
136
- "rendering `#{self.class.component_template_path}'"
142
+ "rendering `#{self.class.path_for_errors}'"
137
143
  raise e
138
144
  end
139
145
 
@@ -165,7 +171,7 @@ module Bridgetown
165
171
  end
166
172
 
167
173
  def method_missing(method, *args, **kwargs, &block)
168
- if helpers.respond_to?(method.to_sym)
174
+ if view_context && helpers.respond_to?(method.to_sym)
169
175
  helpers.send method.to_sym, *args, **kwargs, &block
170
176
  else
171
177
  super
@@ -173,7 +179,7 @@ module Bridgetown
173
179
  end
174
180
 
175
181
  def respond_to_missing?(method, include_private = false)
176
- helpers.respond_to?(method.to_sym, include_private) || super
182
+ (view_context && helpers.respond_to?(method.to_sym, include_private)) || super
177
183
  end
178
184
  end
179
185
  end
@@ -91,6 +91,8 @@ class Bridgetown::Site
91
91
  # {Bridgetown.sanitized_path} method.
92
92
  # @return [Array<String>] Return an array of updated paths if multiple paths given.
93
93
  def in_source_dir(*paths)
94
+ # TODO: this operation is expensive across thousands of iterations. Look for ways
95
+ # to workaround use of this wherever possible...
94
96
  paths.reduce(source) do |base, path|
95
97
  Bridgetown.sanitized_path(base, path.to_s)
96
98
  end
@@ -146,6 +148,10 @@ class Bridgetown::Site
146
148
  @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str)
147
149
  end
148
150
 
151
+ def frontend_bundling_path
152
+ in_root_dir(".bridgetown-cache", "frontend-bundling")
153
+ end
154
+
149
155
  private
150
156
 
151
157
  # Disable Marshaling cache to disk in Safe Mode
@@ -67,7 +67,7 @@ class Bridgetown::Site
67
67
 
68
68
  # @return [Array<Bridgetown::Resource::TaxonomyType>]
69
69
  def taxonomy_types
70
- @taxonomy_types ||= config.taxonomies.map do |label, key_or_metadata|
70
+ @taxonomy_types ||= config.taxonomies.to_h do |label, key_or_metadata|
71
71
  key = key_or_metadata
72
72
  tax_metadata = if key_or_metadata.is_a? Hash
73
73
  key = key_or_metadata["key"]
@@ -79,7 +79,7 @@ class Bridgetown::Site
79
79
  [label, Bridgetown::Resource::TaxonomyType.new(
80
80
  site: self, label: label, key: key, metadata: tax_metadata
81
81
  ),]
82
- end.to_h.with_dot_access
82
+ end.with_dot_access
83
83
  end
84
84
 
85
85
  # Get all loaded resources.
@@ -110,11 +110,11 @@ class Bridgetown::Site
110
110
  generated_pages << generated_page
111
111
  end
112
112
 
113
- # Loads and memoizes the parsed Webpack manifest file (if available)
113
+ # Loads and memoizes the parsed frontend bundler manifest file (if available)
114
114
  # @return [Hash]
115
115
  def frontend_manifest
116
116
  @frontend_manifest ||= begin
117
- manifest_file = in_root_dir(".bridgetown-webpack", "manifest.json")
117
+ manifest_file = File.join(frontend_bundling_path, "manifest.json")
118
118
 
119
119
  JSON.parse(File.read(manifest_file)) if File.exist?(manifest_file)
120
120
  end
@@ -56,5 +56,13 @@ class Bridgetown::Site
56
56
  c.new(config)
57
57
  end
58
58
  end
59
+
60
+ # Shorthand for registering a site hook via {Bridgetown::Hooks}
61
+ # @param event [Symbol] name of the event (`:pre_read`, `:post_render`, etc.)
62
+ # @yield the block will be called when the event is triggered
63
+ # @yieldparam site the site which triggered the event hook
64
+ def on(event, reloadable: false, &block)
65
+ Bridgetown::Hooks.register_one :site, event, reloadable: reloadable, &block
66
+ end
59
67
  end
60
68
  end
@@ -23,9 +23,9 @@ class Bridgetown::Site
23
23
 
24
24
  # Reset all in-memory data and content.
25
25
  #
26
-
26
+ # @param soft [Boolean] if true, persist some state and do a light refresh of layouts and data
27
27
  # @return [void]
28
- def reset(soft: false)
28
+ def reset(soft: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
29
29
  self.time = Time.now
30
30
  if config["time"]
31
31
  self.time = Bridgetown::Utils.parse_date(
@@ -41,12 +41,31 @@ class Bridgetown::Site
41
41
  @documents = nil
42
42
  @docs_to_write = nil
43
43
  @liquid_renderer.reset
44
- frontmatter_defaults.reset unless soft
44
+ tmp_cache.clear
45
+
46
+ if soft
47
+ refresh_layouts_and_data
48
+ else
49
+ frontmatter_defaults.reset
50
+ Bridgetown::Cache.clear_if_config_changed config
51
+ end
45
52
 
46
- Bridgetown::Cache.clear_if_config_changed config unless soft
47
53
  Bridgetown::Hooks.trigger :site, (soft ? :after_soft_reset : :after_reset), self
48
54
  end
49
55
 
56
+ # Read layouts and merge any new data collection contents into the site data
57
+ def refresh_layouts_and_data
58
+ reader.read_layouts
59
+
60
+ collections.data.tap do |coll|
61
+ coll.resources.clear
62
+ coll.read
63
+ coll.merge_data_resources.each do |k, v|
64
+ data[k] = v # refresh site data
65
+ end
66
+ end
67
+ end
68
+
50
69
  # Read data from disk and load it into internal memory.
51
70
  # @return [void]
52
71
  def read
@@ -32,7 +32,7 @@ class Bridgetown::Site
32
32
  @ssr_enabled = true
33
33
  end
34
34
 
35
- def ssr_setup(&block) # rubocop:disable Metrics/AbcSize
35
+ def ssr_setup
36
36
  config.serving = true
37
37
  Bridgetown::Hooks.trigger :site, :pre_read, self
38
38
  defaults_reader.tap do |d|
@@ -46,27 +46,12 @@ class Bridgetown::Site
46
46
  end
47
47
  Bridgetown::Hooks.trigger :site, :post_read, self
48
48
 
49
- hook = block&.(self) # provide additional setup hook
49
+ yield self if block_given? # provide additional setup hook
50
50
  return if Bridgetown.env.production?
51
51
 
52
- @ssr_reload_hook = hook if hook.is_a?(Proc) && hook.lambda?
53
52
  Bridgetown::Watcher.watch(self, config)
54
53
  end
55
54
 
56
- def ssr_reload
57
- reset soft: true
58
- reader.read_layouts
59
-
60
- collections.data.tap do |coll|
61
- coll.resources.clear
62
- coll.read
63
- coll.merge_data_resources.each do |k, v|
64
- data[k] = v
65
- end
66
- end
67
- @ssr_reload_hook.() if @ssr_reload_hook.is_a?(Proc)
68
- end
69
-
70
55
  def disable_ssr
71
56
  Bridgetown.logger.info "SSR:", "now disabled."
72
57
  @ssr_enabled = false
@@ -82,7 +82,7 @@ create_file "plugins/test_output.rb" do
82
82
  <<~RUBY
83
83
  module TestOutput
84
84
  unless Bridgetown.env.development?
85
- Bridgetown::Hooks.register :site, :post_write do
85
+ Bridgetown::Hooks.register_one :site, :post_write do
86
86
  # Load test suite to run on exit
87
87
  require "nokogiri"
88
88
  Dir["test/**/*.rb"].each { |file| require_relative("../\#{file}") }
@@ -22,9 +22,10 @@ create_builder "purgecss.rb" do
22
22
  PURGE
23
23
  File.write(purgecss_file, config_js.strip)
24
24
  end
25
- manifest_file = site.in_root_dir(".bridgetown-webpack", "manifest.json")
25
+ manifest_file = File.join(site.frontend_bundling_path, "manifest.json")
26
26
  if File.exist?(manifest_file)
27
27
  manifest = JSON.parse(File.read(manifest_file))
28
+ # TODO: make this work with esbuild too
28
29
  css_file = manifest["main.css"].split("/").last
29
30
  css_path = ["output", "_bridgetown", "static", "css", css_file].join("/")
30
31
  Bridgetown.logger.info "PurgeCSS", "Purging \#{css_file}"
@@ -5,6 +5,9 @@ services:
5
5
  buildCommand: bin/bridgetown deploy
6
6
  staticPublishPath: ./output
7
7
  pullRequestPreviewsEnabled: true
8
+ envVars:
9
+ - key: BRIDGETOWN_ENV
10
+ value: production
8
11
  headers:
9
12
  - path: /*
10
13
  name: X-Frame-Options
@@ -4,25 +4,54 @@ require "fileutils"
4
4
 
5
5
  say "Installing Stimulus...", :green
6
6
 
7
- run("yarn add stimulus")
7
+ run("yarn add @hotwired/stimulus")
8
+ if Bridgetown::Utils.frontend_bundler_type == :webpack
9
+ run("yarn add @hotwired/stimulus-webpack-helpers")
10
+ end
8
11
 
9
12
  say 'Adding Stimulus to "frontend/javascript/index.js"...', :magenta
10
13
 
11
14
  javascript_import do
12
- <<~JS
13
- import { Application } from "stimulus"
14
- import { definitionsFromContext } from "stimulus/webpack-helpers"
15
- JS
15
+ if Bridgetown::Utils.frontend_bundler_type == :esbuild
16
+ <<~JS
17
+ import { Application } from "@hotwired/stimulus"
18
+ JS
19
+ else
20
+ <<~JS
21
+ import { Application } from "@hotwired/stimulus"
22
+ import { definitionsFromContext } from "@hotwired/stimulus-webpack-helpers"
23
+ JS
24
+ end
16
25
  end
17
26
 
18
27
  javascript_dir = File.join("frontend", "javascript")
19
28
 
20
29
  append_to_file(File.join(javascript_dir, "index.js")) do
21
- <<~JS
22
- const application = Application.start()
23
- const context = require.context("./controllers", true, /\.js$/)
24
- application.load(definitionsFromContext(context))
25
- JS
30
+ if Bridgetown::Utils.frontend_bundler_type == :esbuild
31
+ <<~JS
32
+
33
+ window.Stimulus = Application.start()
34
+
35
+ import controllers from "./controllers/**/*.{js,js.rb}"
36
+ Object.entries(controllers).forEach(([filename, controller]) => {
37
+ if (filename.includes("_controller.") || filename.includes("-controller.")) {
38
+ const identifier = filename.replace("./controllers/", "")
39
+ .replace(/[_\-]controller\..*$/, "")
40
+ .replace("_", "-")
41
+ .replace("/", "--")
42
+
43
+ Stimulus.register(identifier, controller.default)
44
+ }
45
+ })
46
+ JS
47
+ else
48
+ <<~JS
49
+
50
+ window.Stimulus = Application.start()
51
+ const context = require.context("./controllers", true, /\.js$/)
52
+ Stimulus.load(definitionsFromContext(context))
53
+ JS
54
+ end
26
55
  end
27
56
 
28
57
  controller_dir = File.join(javascript_dir, "controllers")
@@ -33,7 +62,7 @@ FileUtils.mkdir_p(controller_dir)
33
62
  say "Creating an example Stimulus Controller for you!...", :magenta
34
63
  create_file(File.join(controller_dir, "example_controller.js")) do
35
64
  <<~JS
36
- import { Controller } from "stimulus"
65
+ import { Controller } from "@hotwired/stimulus"
37
66
  export default class extends Controller {
38
67
  connect() {
39
68
  console.log("Hello, Stimulus!", this.element)
@@ -46,4 +75,4 @@ say "Stimulus successfully added", :green
46
75
 
47
76
  say "To start adding controllers, visit the `./frontend/javascript/controllers/` directory", :blue
48
77
  say "Make sure your controllers follow the `[name]_controller.js` convention", :blue
49
- say 'For further reading, check out "https://stimulus.hotwire.dev/"', :blue
78
+ say 'For further reading, check out "https://stimulus.hotwired.dev/"', :blue
@@ -1,3 +1,8 @@
1
+ /* If you need to add @import statements, do so up here */
2
+
3
+ @import "jit-refresh.css"; /* triggers frontend rebuilds */
4
+
5
+ /* Set up Tailwind imports */
1
6
  @tailwind base;
2
7
  @tailwind components;
3
8
  @tailwind utilities;
@@ -11,15 +11,22 @@ unless File.exist?("postcss.config.js")
11
11
  return
12
12
  end
13
13
 
14
+ say_status :tailwind, "Installing Tailwind CSS..."
15
+
14
16
  confirm = ask "This configuration will ovewrite your existing #{"postcss.config.js".bold.white}. Would you like to continue? [Yn]"
15
17
  return unless confirm.casecmp?("Y")
16
18
 
17
19
  run "yarn add -D tailwindcss"
18
20
  run "npx tailwindcss init"
19
21
 
20
- copy_file in_templates_dir("postcss.config.js"), "postcss.config.js", force: true
22
+ gsub_file "tailwind.config.js", "content: [],", <<~JS.strip
23
+ content: [
24
+ './src/**/*.{html,md,liquid,erb,serb}',
25
+ './frontend/javascript/**/*.js',
26
+ ],
27
+ JS
21
28
 
22
- run "bundle exec bridgetown configure purgecss"
29
+ copy_file in_templates_dir("postcss.config.js"), "postcss.config.js", force: true
23
30
 
24
31
  if File.exist?("frontend/styles/index.css")
25
32
  prepend_to_file "frontend/styles/index.css",
@@ -29,4 +36,26 @@ else
29
36
  say File.read(in_templates_dir("/css_imports.css"))
30
37
  end
31
38
 
39
+ create_file "frontend/styles/jit-refresh.css", "/* #{Time.now.to_i} */"
40
+
41
+ create_builder "tailwind_jit.rb" do
42
+ <<~RUBY
43
+ class Builders::TailwindJit < SiteBuilder
44
+ def build
45
+ hook :site, :pre_reload do |_, paths|
46
+ # Don't trigger refresh if it's a frontend-only change
47
+ next if paths.length == 1 && paths.first.ends_with?("manifest.json")
48
+
49
+ # Save out a comment file to trigger Tailwind's JIT
50
+ refresh_file = site.in_root_dir("frontend", "styles", "jit-refresh.css")
51
+ File.write refresh_file, "/* \#{Time.now.to_i} */"
52
+ throw :halt # don't continue the build, wait for watcher rebuild
53
+ end
54
+ end
55
+ end
56
+ RUBY
57
+ end
58
+
59
+ say_status :tailwind, "Tailwind CSS is now configured."
60
+
32
61
  # rubocop:enable all
@@ -0,0 +1,48 @@
1
+ document.addEventListener("turbo:visit", () => {
2
+ let main = document.querySelector("main");
3
+ if (main.dataset.turboTransition == "false") return;
4
+
5
+ let [movement, scale] = ["15px", "0.99"];
6
+
7
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
8
+ [movement, scale] = ["7px", "1"]
9
+ };
10
+
11
+ main.style.transformOrigin = "50% 0%";
12
+ main.dataset.animatingOut = true;
13
+
14
+ main.animate(
15
+ [
16
+ { opacity: 1, transform: "translateY(0px) scale(1)" },
17
+ { opacity: 0, transform: `translateY(${movement}) scale(${scale})` }
18
+ ],
19
+ { duration: 300, easing: "cubic-bezier(0.45, 0, 0.55, 1)" }
20
+ );
21
+
22
+ Promise.all(main.getAnimations().map(animation => animation.finished)).then(() => {
23
+ if (main.dataset.animatingOut) main.style.visibility = "hidden"
24
+ })
25
+ });
26
+
27
+ document.addEventListener("turbo:load", () => {
28
+ let main = document.querySelector("main");
29
+ if (main.dataset.turboTransition == "false") return;
30
+
31
+ let [movement, scale] = ["-10px", "0.99"];
32
+
33
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
34
+ [movement, scale] = ["-5px", "1"]
35
+ };
36
+
37
+ main.style.visibility = "visible";
38
+ main.style.transformOrigin = "50% 0%";
39
+ delete main.dataset.animatingOut;
40
+
41
+ main.animate(
42
+ [
43
+ { opacity: 0, transform: `translateY(${movement}) scale(${scale})` },
44
+ { opacity: 1, transform: "translateY(0px) scale(1)" }
45
+ ],
46
+ { duration: 150, easing: "cubic-bezier(0.45, 0, 0.55, 1)" }
47
+ )
48
+ })