bridgetown-core 1.0.0 → 1.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/lib/bridgetown-core/collection.rb +37 -20
  4. data/lib/bridgetown-core/commands/concerns/actions.rb +3 -2
  5. data/lib/bridgetown-core/commands/configure.rb +1 -1
  6. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +95 -12
  7. data/lib/bridgetown-core/commands/new.rb +10 -9
  8. data/lib/bridgetown-core/commands/plugins.rb +2 -0
  9. data/lib/bridgetown-core/commands/start.rb +3 -0
  10. data/lib/bridgetown-core/commands/webpack/update.rb +2 -2
  11. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +11 -2
  12. data/lib/bridgetown-core/component.rb +13 -7
  13. data/lib/bridgetown-core/concerns/localizable.rb +20 -0
  14. data/lib/bridgetown-core/concerns/prioritizable.rb +44 -0
  15. data/lib/bridgetown-core/concerns/publishable.rb +11 -1
  16. data/lib/bridgetown-core/concerns/site/configurable.rb +2 -10
  17. data/lib/bridgetown-core/concerns/site/localizable.rb +5 -1
  18. data/lib/bridgetown-core/concerns/site/ssr.rb +3 -3
  19. data/lib/bridgetown-core/concerns/site/writable.rb +28 -0
  20. data/lib/bridgetown-core/configuration.rb +2 -0
  21. data/lib/bridgetown-core/configurations/bt-postcss/postcss.config.js +5 -3
  22. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -1
  23. data/lib/bridgetown-core/configurations/lit/esbuild-plugins.js +21 -0
  24. data/lib/bridgetown-core/configurations/lit/happy-days.lit.js +26 -0
  25. data/lib/bridgetown-core/configurations/lit/lit-components-entry.js +1 -0
  26. data/lib/bridgetown-core/configurations/lit/lit-ssr.config.js +6 -0
  27. data/lib/bridgetown-core/configurations/lit.rb +95 -0
  28. data/lib/bridgetown-core/configurations/open-props/variables.css.erb +11 -0
  29. data/lib/bridgetown-core/configurations/open-props.rb +21 -0
  30. data/lib/bridgetown-core/configurations/ruby2js/hello_world.js.rb +9 -0
  31. data/lib/bridgetown-core/configurations/ruby2js.rb +67 -0
  32. data/lib/bridgetown-core/configurations/shoelace.rb +50 -0
  33. data/lib/bridgetown-core/configurations/tailwindcss.rb +16 -2
  34. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +1 -1
  35. data/lib/bridgetown-core/drops/generated_page_drop.rb +2 -1
  36. data/lib/bridgetown-core/drops/resource_drop.rb +2 -1
  37. data/lib/bridgetown-core/errors.rb +5 -5
  38. data/lib/bridgetown-core/filters/translation_filters.rb +11 -0
  39. data/lib/bridgetown-core/filters/url_filters.rb +37 -10
  40. data/lib/bridgetown-core/filters.rb +3 -0
  41. data/lib/bridgetown-core/frontmatter_defaults.rb +14 -8
  42. data/lib/bridgetown-core/generated_page.rb +1 -0
  43. data/lib/bridgetown-core/kramdown/parser/gfm.rb +36 -0
  44. data/lib/bridgetown-core/model/base.rb +1 -2
  45. data/lib/bridgetown-core/plugin.rb +6 -37
  46. data/lib/bridgetown-core/plugin_manager.rb +3 -2
  47. data/lib/bridgetown-core/rack/boot.rb +5 -0
  48. data/lib/bridgetown-core/rack/logger.rb +14 -4
  49. data/lib/bridgetown-core/rack/roda.rb +102 -8
  50. data/lib/bridgetown-core/rack/routes.rb +67 -2
  51. data/lib/bridgetown-core/resource/base.rb +4 -6
  52. data/lib/bridgetown-core/resource/destination.rb +18 -0
  53. data/lib/bridgetown-core/resource/permalink_processor.rb +6 -4
  54. data/lib/bridgetown-core/resource/relations.rb +1 -1
  55. data/lib/bridgetown-core/utils/aux.rb +2 -1
  56. data/lib/bridgetown-core/utils/require_gems.rb +3 -6
  57. data/lib/bridgetown-core/utils.rb +24 -11
  58. data/lib/bridgetown-core/version.rb +2 -2
  59. data/lib/bridgetown-core/watcher.rb +19 -6
  60. data/lib/bridgetown-core.rb +8 -2
  61. data/lib/site_template/README.md +2 -2
  62. data/lib/site_template/bridgetown.config.yml +3 -0
  63. data/lib/site_template/frontend/javascript/index.js.erb +1 -0
  64. data/lib/site_template/frontend/styles/syntax-highlighting.css +77 -0
  65. data/lib/site_template/package.json.erb +18 -17
  66. data/lib/site_template/server/roda_app.rb +3 -6
  67. data/lib/site_template/src/404.html +2 -1
  68. data/lib/site_template/src/500.html +10 -0
  69. metadata +20 -5
  70. data/lib/bridgetown-core/publisher.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdb62333635d80ceb9561a0cd9be68f0220ea729c8ac4505bb8e4460894075e1
4
- data.tar.gz: f7377127b4d64846e694d8ba4c032706ed161ea1595cf8dbf3eca3d2b6e4692d
3
+ metadata.gz: 95b4ce1888886fbccd72391216d1298ce7d20e6bfb506ceedab3208881b4d25c
4
+ data.tar.gz: 712ddfbba10913becc4fb800a499ce602d9e2848f395b87cf8c205d97000ab2e
5
5
  SHA512:
6
- metadata.gz: 051a34337053c1370745d37a7cc3def36e1623193e4c03e0b1006d06280303ad5442c289465185314f916dbcf2aa1b1123990ca196041b03bf3804a03b36f695
7
- data.tar.gz: d5adcc3f8c7c7938bbc220329c002c7cea281f4e21f8ea2bab685dabaffe48c5acca3998482d1e0ec6d0c7c172751c0c6b34481821f51b5d1ccc687b137e55a5
6
+ metadata.gz: 1efd58dbca74ae1f3903bd91e225c28abb74131a5b1bc1885b7cac696d5f97a6a1ee7b973fed4d9ad2a90fec9ccc610f4ab19c4cb60666bfeafc0f4cda28f715
7
+ data.tar.gz: 545fe04a5338166bf02927395c131d65a822b524b551865bc558dd1e4ffa4c1438ace43bad4fe09a29e980c77d458bcc9876a249bbf4598d45764f471693521b
data/.rubocop.yml CHANGED
@@ -11,12 +11,17 @@ AllCops:
11
11
  - vendor/**/*
12
12
  - tmp/**/*
13
13
  - test/source/**/*
14
- - test/resources/src/_pages/*.rb
14
+ - test/resources/src/**/*.rb
15
+ - lib/bridgetown-core/commands/base.rb
16
+ - lib/bridgetown-core/commands/plugins.rb
17
+ - lib/bridgetown-core/configurations/ruby2js/**/*
18
+ - lib/bridgetown-core/rack/roda.rb
15
19
  - lib/site_template/TEMPLATES/**/*
16
20
  - lib/site_template/Rakefile
17
21
  - lib/site_template/config.ru
18
22
  - lib/site_template/config/**/*
19
23
  - lib/site_template/plugins/site_builder.rb
24
+ - lib/site_template/server/roda_app.rb
20
25
 
21
26
  Lint/ConstantDefinitionInBlock:
22
27
  Exclude:
@@ -20,11 +20,11 @@ module Bridgetown
20
20
  end
21
21
 
22
22
  def builtin?
23
- label.in? %w(posts pages data).freeze
23
+ @is_builtin ||= label.in?(%w(posts pages data).freeze)
24
24
  end
25
25
 
26
26
  def data?
27
- label == "data"
27
+ @is_data ||= label == "data"
28
28
  end
29
29
 
30
30
  # Fetch the Resources in this collection.
@@ -215,7 +215,7 @@ module Bridgetown
215
215
  # Used by Resource's permalink processor
216
216
  # @return [String]
217
217
  def default_permalink
218
- metadata.fetch("permalink", "/:collection/:path/")
218
+ metadata.fetch("permalink", "/:locale/:collection/:path/")
219
219
  end
220
220
 
221
221
  # Extract options for this collection from the site configuration.
@@ -270,32 +270,29 @@ module Bridgetown
270
270
 
271
271
  # Read in resource from repo path
272
272
  # @param full_path [String]
273
- def read_resource(full_path, manifest: nil) # rubocop:todo Metrics/AbcSize
274
- scheme = manifest ? "plugin" : "repo"
275
- id = +"#{scheme}://#{label}.collection/"
276
- id += "#{manifest.origin}/" if manifest
277
- id += Addressable::URI.escape(
278
- Pathname(full_path).relative_path_from(
279
- manifest ? Pathname(manifest.content) : Pathname(site.source)
280
- ).to_s
281
- ).gsub("#", "%23")
282
- model = Bridgetown::Model::Base.find(id)
283
-
284
- if model.attributes.key?(:locale) && model.locale.to_sym == :multi
273
+ def read_resource(full_path, manifest: nil)
274
+ model_relative_path = relative_model_path_for(full_path, manifest: manifest)
275
+ model = Bridgetown::Model::Base.find(model_id_from_relative_path(model_relative_path,
276
+ manifest: manifest))
277
+
278
+ if model_is_multi_locale?(model, model_relative_path)
285
279
  site.config.available_locales.each do |locale|
286
280
  model.locale = locale
287
- add_model_resource model
281
+ add_resource_from_model model
288
282
  end
289
283
  return
290
284
  end
291
285
 
292
- add_model_resource model
286
+ add_resource_from_model model
293
287
  end
294
288
 
295
- def add_model_resource(model)
296
- resource = model.to_resource.read!
297
- resources << resource if site.config.unpublished || resource.published?
289
+ # @param model [Bridgetown::Model::Base]
290
+ def add_resource_from_model(model)
291
+ model.to_resource.read!.tap do |resource|
292
+ resources << resource if resource.publishable?
293
+ end
298
294
  end
295
+ alias_method :add_model_resource, :add_resource_from_model
299
296
 
300
297
  def sort_resources!
301
298
  if metadata["sort_by"].is_a?(String)
@@ -365,5 +362,25 @@ module Bridgetown
365
362
  self
366
363
  )
367
364
  end
365
+
366
+ def relative_model_path_for(full_path, manifest: nil)
367
+ Pathname(full_path).relative_path_from(
368
+ manifest ? Pathname(manifest.content) : Pathname(site.source)
369
+ ).to_s
370
+ end
371
+
372
+ def model_id_from_relative_path(model_relative_path, manifest: nil)
373
+ scheme = manifest ? "plugin" : "repo"
374
+ id = +"#{scheme}://#{label}.collection/"
375
+ id += "#{manifest.origin}/" if manifest
376
+ id += Addressable::URI.escape(model_relative_path).gsub("#", "%23")
377
+ id
378
+ end
379
+
380
+ def model_is_multi_locale?(model, model_relative_path)
381
+ (model.attributes.key?(:locale) && model.locale.to_sym == :multi) ||
382
+ File.extname(File.basename(model_relative_path, ".*")) == ".multi" ||
383
+ site.frontmatter_defaults.all(model_relative_path, label.to_sym)["locale"].to_s == "multi"
384
+ end
368
385
  end
369
386
  end
@@ -54,7 +54,8 @@ module Bridgetown
54
54
 
55
55
  def add_bridgetown_plugin(gemname, version: nil)
56
56
  version = " -v \"#{version}\"" if version
57
- run "bundle add #{gemname}#{version} -g bridgetown_plugins"
57
+ run "bundle add #{gemname}#{version} -g bridgetown_plugins",
58
+ env: { "BUNDLE_GEMFILE" => File.join(destination_root, "Gemfile") }
58
59
  rescue SystemExit
59
60
  say_status :run, "Gem not added due to bundler error", :red
60
61
  end
@@ -79,7 +80,7 @@ module Bridgetown
79
80
 
80
81
  def determine_remote_filename(arg)
81
82
  if arg.end_with?(".rb")
82
- arg.split("/").yield_self do |segments|
83
+ arg.split("/").then do |segments|
83
84
  arg.sub!(%r!/#{segments.last}$!, "")
84
85
  segments.last
85
86
  end
@@ -60,7 +60,7 @@ module Bridgetown
60
60
 
61
61
  def configurations
62
62
  inside self.class.source_root do
63
- return Dir.glob("*.rb").map { |file| file.sub(".rb", "") }
63
+ return Dir.glob("*.rb").map { |file| file.sub(".rb", "") }.sort
64
64
  end
65
65
  end
66
66
 
@@ -11,11 +11,33 @@
11
11
  const path = require("path")
12
12
  const fsLib = require("fs")
13
13
  const fs = fsLib.promises
14
+ const { pathToFileURL, fileURLToPath } = require("url")
14
15
  const glob = require("glob")
15
16
  const postcss = require("postcss")
16
17
  const postCssImport = require("postcss-import")
17
18
  const readCache = require("read-cache")
18
19
 
20
+ // Detect if an NPM package is available
21
+ const moduleAvailable = name => {
22
+ try {
23
+ require.resolve(name)
24
+ return true
25
+ } catch (e) { }
26
+ return false
27
+ }
28
+
29
+ // Generate a Source Map URL (used by the Sass plugin)
30
+ const generateSourceMappingURL = sourceMap => {
31
+ const data = Buffer.from(JSON.stringify(sourceMap), "utf-8").toString("base64")
32
+ return `/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${data} */`
33
+ }
34
+
35
+ // Import Sass if available
36
+ let sass
37
+ if (moduleAvailable("sass")) {
38
+ sass = require("sass")
39
+ }
40
+
19
41
  // Glob plugin derived from:
20
42
  // https://github.com/thomaschaaf/esbuild-plugin-import-glob
21
43
  // https://github.com/xiaohui-zhangxh/jsbundling-rails/commit/b15025dcc20f664b2b0eb238915991afdbc7cb58
@@ -61,24 +83,23 @@ const importGlobPlugin = () => ({
61
83
  },
62
84
  })
63
85
 
64
- const postCssPlugin = (options) => ({
86
+ // Plugin for PostCSS
87
+ const postCssPlugin = (options, configuration) => ({
65
88
  name: "postcss",
66
89
  async setup(build) {
67
90
  // Process .css files with PostCSS
68
- build.onLoad({ filter: /\.(css)$/ }, async (args) => {
91
+ build.onLoad({ filter: (configuration.filter || /\.css$/) }, async (args) => {
69
92
  const additionalFilePaths = []
70
93
  const css = await fs.readFile(args.path, "utf8")
71
94
 
72
95
  // Configure import plugin so PostCSS can properly resolve `@import`ed CSS files
73
96
  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
- },
97
+ filter: itemPath => !itemPath.startsWith("/"), // ensure it doesn't try to import source-relative paths
79
98
  load: async filename => {
80
99
  let contents = await readCache(filename, "utf-8")
81
100
  const filedir = path.dirname(filename)
101
+ // We'll want to track any imports later when in watch mode:
102
+ additionalFilePaths.push(filename)
82
103
 
83
104
  // We need to transform `url(...)` in imported CSS so the filepaths are properly
84
105
  // relative to the entrypoint. Seems icky to have to hack this! C'est la vie...
@@ -106,6 +127,65 @@ const postCssPlugin = (options) => ({
106
127
  },
107
128
  })
108
129
 
130
+ // Plugin for Sass
131
+ const sassPlugin = (options) => ({
132
+ name: "sass",
133
+ async setup(build) {
134
+ // Process .scss and .sass files with Sass
135
+ build.onLoad({ filter: /\.(sass|scss)$/ }, async (args) => {
136
+ if (!sass) {
137
+ console.error("error: Sass is not installed. Try running `yarn add sass` and then building again.")
138
+ return
139
+ }
140
+
141
+ const modulesFolder = pathToFileURL("node_modules/")
142
+
143
+ const localOptions = {
144
+ importers: [{
145
+ // An importer that redirects relative URLs starting with "~" to
146
+ // `node_modules`.
147
+ findFileUrl(url) {
148
+ if (!url.startsWith('~')) return null
149
+ return new URL(url.substring(1), modulesFolder)
150
+ }
151
+ }],
152
+ sourceMap: true,
153
+ ...options
154
+ }
155
+ const result = sass.compile(args.path, localOptions)
156
+
157
+ const watchPaths = result.loadedUrls
158
+ .filter((x) => x.protocol === "file:" && !x.pathname.startsWith(modulesFolder.pathname))
159
+ .map((x) => x.pathname)
160
+
161
+ let cssOutput = result.css.toString()
162
+
163
+ if (result.sourceMap) {
164
+ const basedir = process.cwd()
165
+ const sourceMap = result.sourceMap
166
+
167
+ const promises = sourceMap.sources.map(async source => {
168
+ const sourceFile = await fs.readFile(fileURLToPath(source), "utf8")
169
+ return sourceFile
170
+ })
171
+ sourceMap.sourcesContent = await Promise.all(promises)
172
+
173
+ sourceMap.sources = sourceMap.sources.map(source => {
174
+ return path.relative(basedir, fileURLToPath(source))
175
+ })
176
+
177
+ cssOutput += '\n' + generateSourceMappingURL(sourceMap)
178
+ }
179
+
180
+ return {
181
+ contents: cssOutput,
182
+ loader: "css",
183
+ watchFiles: [args.path, ...watchPaths],
184
+ }
185
+ })
186
+ },
187
+ })
188
+
109
189
  // Set up defaults and generate frontend bundling manifest file
110
190
  const bridgetownPreset = (outputFolder) => ({
111
191
  name: "bridgetownPreset",
@@ -151,9 +231,9 @@ const bridgetownPreset = (outputFolder) => ({
151
231
  // We have an entrypoint!
152
232
  manifest[stripPrefix(value.entryPoint)] = outputPath
153
233
  entrypoints.push([outputPath, fileSize(key)])
154
- } else if (key.match(/index(\.js)?\.[^-.]*\.css/) && inputs.find(item => item.endsWith("index.css"))) {
234
+ } else if (key.match(/index(\.js)?\.[^-.]*\.css/) && inputs.find(item => item.match(/\.(s?css|sass)$/))) {
155
235
  // Special treatment for index.css
156
- manifest[stripPrefix(inputs.find(item => item.endsWith("index.css")))] = outputPath
236
+ manifest[stripPrefix(inputs.find(item => item.match(/\.(s?css|sass)$/)))] = outputPath
157
237
  entrypoints.push([outputPath, fileSize(key)])
158
238
  } else if (inputs.length > 0) {
159
239
  // Naive implementation, we'll just grab the first input and hope it's accurate
@@ -182,9 +262,12 @@ const postCssConfig = postcssrc.sync()
182
262
  module.exports = (outputFolder, esbuildOptions) => {
183
263
  esbuildOptions.plugins = esbuildOptions.plugins || []
184
264
  // Add the PostCSS & glob plugins to the top of the plugin stack
185
- esbuildOptions.plugins.unshift(postCssPlugin(postCssConfig))
265
+ esbuildOptions.plugins.unshift(postCssPlugin(postCssConfig, esbuildOptions.postCssPluginConfig || {}))
266
+ if (esbuildOptions.postCssPluginConfig) delete esbuildOptions.postCssPluginConfig
186
267
  esbuildOptions.plugins.unshift(importGlobPlugin())
187
- // Add the Bridgetown preset to the bottom of the plugin stack
268
+ // Add the Sass plugin
269
+ esbuildOptions.plugins.push(sassPlugin(esbuildOptions.sassOptions || {}))
270
+ // Add the Bridgetown preset
188
271
  esbuildOptions.plugins.push(bridgetownPreset(outputFolder))
189
272
 
190
273
  // esbuild, take it away!
@@ -200,7 +283,7 @@ module.exports = (outputFolder, esbuildOptions) => {
200
283
  ".ttf": "file",
201
284
  ".eot": "file",
202
285
  },
203
- resolveExtensions: [".tsx",".ts",".jsx",".js",".css",".json",".js.rb"],
286
+ resolveExtensions: [".tsx", ".ts", ".jsx", ".js", ".css", ".scss", ".sass", ".json", ".js.rb"],
204
287
  nodePaths: ["frontend/javascript", "frontend/styles"],
205
288
  watch: process.argv.includes("--watch"),
206
289
  minify: process.argv.includes("--minify"),
@@ -43,7 +43,7 @@ module Bridgetown
43
43
  desc: "Skip 'yarn install'"
44
44
  class_option :"use-sass",
45
45
  type: :boolean,
46
- desc: "(Webpack only) Create a Sass configuration instead of using PostCSS"
46
+ desc: "Set up a Sass configuration for your stylesheet"
47
47
 
48
48
  DOCSURL = "https://bridgetownrb.com/docs"
49
49
 
@@ -62,11 +62,6 @@ module Bridgetown
62
62
  def new_site
63
63
  raise ArgumentError, "You must specify a path." if args.empty?
64
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
-
70
65
  new_site_path = File.expand_path(args.join(" "), Dir.pwd)
71
66
  @site_name = new_site_path.split(File::SEPARATOR).last
72
67
 
@@ -98,7 +93,11 @@ module Bridgetown
98
93
  end
99
94
 
100
95
  def postcss_option
101
- !(frontend_bundling_option == "webpack" && options["use-sass"])
96
+ !options["use-sass"]
97
+ end
98
+
99
+ def disable_postcss?
100
+ options["use-sass"] && options["frontend-bundling"] == "webpack"
102
101
  end
103
102
 
104
103
  def create_site(new_site_path)
@@ -116,6 +115,7 @@ module Bridgetown
116
115
  template("frontend/javascript/index.js.erb", "frontend/javascript/index.js")
117
116
  template("src/index.md.erb", "src/index.md")
118
117
  template("src/posts.md.erb", "src/posts.md")
118
+ copy_file("frontend/styles/syntax-highlighting.css")
119
119
 
120
120
  case options["templates"]
121
121
  when "erb"
@@ -126,11 +126,11 @@ module Bridgetown
126
126
  setup_liquid_templates
127
127
  end
128
128
 
129
+ postcss_option ? configure_postcss : configure_sass
130
+
129
131
  if frontend_bundling_option == "esbuild"
130
- configure_postcss
131
132
  invoke(Esbuild, ["setup"], {})
132
133
  else
133
- postcss_option ? configure_postcss : configure_sass
134
134
  invoke(Webpack, ["setup"], {})
135
135
  end
136
136
  end
@@ -165,6 +165,7 @@ module Bridgetown
165
165
  end
166
166
 
167
167
  def configure_sass
168
+ template("postcss.config.js.erb", "postcss.config.js") unless disable_postcss?
168
169
  copy_file("frontend/styles/index.css", "frontend/styles/index.scss")
169
170
  end
170
171
 
@@ -120,6 +120,7 @@ module Bridgetown
120
120
  " return to your site root.")
121
121
  puts
122
122
 
123
+ # rubocop: disable Style/RedundantCondition
123
124
  Dir.chdir dir do
124
125
  ENV["BRIDGETOWN_SITE"] = site.root_dir
125
126
  if ENV["SHELL"]
@@ -128,6 +129,7 @@ module Bridgetown
128
129
  system("/bin/sh")
129
130
  end
130
131
  end
132
+ # rubocop: enable Style/RedundantCondition
131
133
 
132
134
  puts
133
135
  Bridgetown.logger.info("Done!", "You're back in #{Dir.pwd.green}")
@@ -70,6 +70,9 @@ module Bridgetown
70
70
  end
71
71
 
72
72
  cli = Puma::CLI.new puma_args
73
+ cli.launcher.events.on_stopped do
74
+ Bridgetown::Hooks.trigger :site, :server_shutdown
75
+ end
73
76
  cli.run
74
77
  end
75
78
 
@@ -7,11 +7,11 @@ say "🎉 Webpack configuration updated successfully!"
7
7
 
8
8
  return if Bridgetown.environment.test?
9
9
 
10
- required_packages = %w(esbuild esbuild-loader webpack@5.39.1 webpack-cli@4.7.2 webpack-manifest-plugin@3.1.1)
10
+ required_packages = %w(esbuild esbuild-loader css-loader@6.7.1 webpack@5.72.0 webpack-cli@4.9.2 webpack-manifest-plugin@5.0.0)
11
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
12
 
13
13
  say "Installing required packages"
14
- run "yarn add -D #{required_packages.join(" ")}"
14
+ run "yarn add -D --tilde #{required_packages.join(" ")}"
15
15
 
16
16
  packages_to_remove = package_json["devDependencies"].slice(*redundant_packages).keys
17
17
  unless packages_to_remove.empty?
@@ -41,7 +41,9 @@ const cssRules = {
41
41
  {
42
42
  loader: "css-loader",
43
43
  options: {
44
- url: url => !url.startsWith('/'),
44
+ url: {
45
+ filter: url => !url.startsWith('/')
46
+ },
45
47
  importLoaders: 1
46
48
  }
47
49
  }
@@ -49,7 +51,14 @@ const cssRules = {
49
51
  mode: '<%= self.config.uses_postcss? ? "postcss" : "sass" %>',
50
52
 
51
53
  postcss: () => {
52
- cssRules.use.push("postcss-loader")
54
+ cssRules.use.push({
55
+ loader: "postcss-loader",
56
+ options: {
57
+ postcssOptions: {
58
+ config: "postcss.config.js"
59
+ }
60
+ }
61
+ })
53
62
  return { test: cssRules.test, use: cssRules.use }
54
63
  },
55
64
 
@@ -4,7 +4,7 @@ module Bridgetown
4
4
  class Component
5
5
  extend Forwardable
6
6
 
7
- def_delegators :@view_context, :helpers, :liquid_render, :partial
7
+ def_delegators :@view_context, :liquid_render, :partial
8
8
 
9
9
  # @return [Bridgetown::Site]
10
10
  attr_reader :site # will be nil unless you explicitly set a `@site` ivar
@@ -32,14 +32,12 @@ module Bridgetown
32
32
  def renderer_for_ext(ext, &block)
33
33
  @_tmpl ||= case ext.to_s
34
34
  when "erb"
35
- include ERBCapture
36
35
  Tilt::ErubiTemplate.new(component_template_path,
37
36
  outvar: "@_erbout",
38
37
  bufval: "Bridgetown::OutputBuffer.new",
39
38
  engine_class: Bridgetown::ERBEngine,
40
39
  &block)
41
- when "serb" # requires serbea
42
- include Serbea::Helpers
40
+ when "serb"
43
41
  Tilt::SerbeaTemplate.new(component_template_path, &block)
44
42
  when "slim" # requires bridgetown-slim
45
43
  Slim::Template.new(component_template_path, &block)
@@ -166,12 +164,20 @@ module Bridgetown
166
164
  def _renderer
167
165
  @_renderer ||= begin
168
166
  ext = File.extname(self.class.component_template_path).delete_prefix(".")
169
- self.class.renderer_for_ext(ext) { self.class.component_template_content }
167
+ self.class.renderer_for_ext(ext) { self.class.component_template_content }.tap do |rn|
168
+ self.class.include(rn.is_a?(Tilt::SerbeaTemplate) ? Serbea::Helpers : ERBCapture)
169
+ end
170
170
  end
171
171
  end
172
172
 
173
+ def helpers
174
+ @helpers ||= Bridgetown::RubyTemplateView::Helpers.new(
175
+ self, view_context&.site || Bridgetown::Current.site
176
+ )
177
+ end
178
+
173
179
  def method_missing(method, *args, **kwargs, &block)
174
- if view_context && helpers.respond_to?(method.to_sym)
180
+ if helpers.respond_to?(method.to_sym)
175
181
  helpers.send method.to_sym, *args, **kwargs, &block
176
182
  else
177
183
  super
@@ -179,7 +185,7 @@ module Bridgetown
179
185
  end
180
186
 
181
187
  def respond_to_missing?(method, include_private = false)
182
- (view_context && helpers.respond_to?(method.to_sym, include_private)) || super
188
+ helpers.respond_to?(method.to_sym, include_private) || super
183
189
  end
184
190
  end
185
191
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Localizable
5
+ def all_locales
6
+ result_set = case self
7
+ when Bridgetown::Resource::Base
8
+ collection.resources
9
+ when Bridgetown::GeneratedPage
10
+ site.generated_pages
11
+ else
12
+ []
13
+ end
14
+
15
+ result_set.select { |item| item.data.slug == data.slug }.sort_by do |item|
16
+ site.config.available_locales.index item.data.locale
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Prioritizable
5
+ module ClassMethods
6
+ # @!method priorities
7
+ # @return [Hash<Symbol, Object>]
8
+
9
+ # Get or set the priority of this class. When called without an
10
+ # argument it returns the priority. When an argument is given, it will
11
+ # set the priority.
12
+ #
13
+ # @param priority [Symbol] new priority (optional)
14
+ # Valid options are: `:lowest`, `:low`, `:normal`, `:high`, `:highest`
15
+ # @return [Symbol]
16
+ def priority(priority = nil)
17
+ @priority ||= nil
18
+ @priority = priority if priority && priorities.key?(priority)
19
+ @priority || :normal
20
+ end
21
+
22
+ # Spaceship is priority [higher -> lower]
23
+ #
24
+ # @param other [Class] The class to be compared.
25
+ # @return [Integer] -1, 0, 1.
26
+ def <=>(other)
27
+ priorities[other.priority] <=> priorities[priority]
28
+ end
29
+ end
30
+
31
+ def self.included(klass)
32
+ klass.extend ClassMethods
33
+ klass.class_attribute :priorities, instance_accessor: false
34
+ end
35
+
36
+ # Spaceship is priority [higher -> lower]
37
+ #
38
+ # @param other [object] The object to be compared.
39
+ # @return [Integer] -1, 0, 1.
40
+ def <=>(other)
41
+ self.class <=> other.class
42
+ end
43
+ end
44
+ end
@@ -2,9 +2,19 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Publishable
5
- # Whether the file is published or not, as indicated in YAML front-matter
5
+ # Whether the resource is published or not, as indicated in YAML front-matter
6
6
  def published?
7
7
  !(data.key?("published") && data["published"] == false)
8
8
  end
9
+
10
+ def publishable?
11
+ return true if collection.data?
12
+ return false unless published? || @site.config.unpublished
13
+
14
+ future_allowed = collection.metadata.future || @site.config.future
15
+ this_time = date.is_a?(Date) ? date.to_time.to_i : date.to_i
16
+
17
+ future_allowed || this_time <= @site.time.to_i
18
+ end
9
19
  end
10
20
  end
@@ -38,7 +38,7 @@ class Bridgetown::Site
38
38
  # @param strip_slash_only [Boolean] set to true if you wish "/" to be returned as ""
39
39
  # @return [String]
40
40
  def base_path(strip_slash_only: false)
41
- (config[:base_path] || config[:baseurl]).yield_self do |path|
41
+ (config[:base_path] || config[:baseurl]).then do |path|
42
42
  strip_slash_only ? path.to_s.sub(%r{^/$}, "") : path
43
43
  end
44
44
  end
@@ -61,14 +61,6 @@ class Bridgetown::Site
61
61
  @frontmatter_defaults ||= Bridgetown::FrontmatterDefaults.new(self)
62
62
  end
63
63
 
64
- # Returns the current instance of {Publisher} or creates a new instance of
65
- # {Publisher} if one doesn't exist.
66
- #
67
- # @return [Publisher] Returns an instance of {Publisher}
68
- def publisher
69
- @publisher ||= Bridgetown::Publisher.new(self)
70
- end
71
-
72
64
  # Prefix a path or paths with the {#root_dir} directory.
73
65
  #
74
66
  # @see Bridgetown.sanitized_path
@@ -166,7 +158,7 @@ class Bridgetown::Site
166
158
  plugin_components_load_paths = Bridgetown::PluginManager.source_manifests
167
159
  .filter_map(&:components)
168
160
 
169
- local_components_load_paths = config["components_dir"].yield_self do |dir|
161
+ local_components_load_paths = config["components_dir"].then do |dir|
170
162
  dir.is_a?(Array) ? dir : [dir]
171
163
  end
172
164
  local_components_load_paths.map! do |dir|
@@ -7,11 +7,15 @@ class Bridgetown::Site
7
7
  def locale
8
8
  @locale ||= begin
9
9
  locale = ENV.fetch("BRIDGETOWN_LOCALE", config[:default_locale]).to_sym
10
- Dir["#{in_source_dir("_locales")}/*.yml"].each do |locale_path|
10
+ Dir["#{in_source_dir("_locales")}/*.{json,rb,yml}"].each do |locale_path|
11
11
  I18n.load_path << locale_path
12
12
  end
13
13
  I18n.available_locales = config[:available_locales]
14
14
  I18n.default_locale = locale
15
+ I18n.fallbacks = (config[:available_locales] + [:en]).uniq.to_h do |available_locale|
16
+ [available_locale, [available_locale, locale, :en].uniq]
17
+ end
18
+ locale
15
19
  end
16
20
  end
17
21