bridgetown-core 1.0.0.alpha11 → 1.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/bin/bridgetown +6 -1
  4. data/bridgetown-core.gemspec +3 -3
  5. data/lib/bridgetown-core/commands/base.rb +18 -18
  6. data/lib/bridgetown-core/commands/build.rb +1 -1
  7. data/lib/bridgetown-core/commands/clean.rb +2 -2
  8. data/lib/bridgetown-core/commands/esbuild/esbuild.config.js +27 -0
  9. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +216 -0
  10. data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +47 -0
  11. data/lib/bridgetown-core/commands/esbuild/setup.rb +4 -0
  12. data/lib/bridgetown-core/commands/esbuild/update.rb +4 -0
  13. data/lib/bridgetown-core/commands/esbuild.rb +83 -0
  14. data/lib/bridgetown-core/commands/new.rb +80 -10
  15. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +1 -1
  16. data/lib/bridgetown-core/commands/webpack/update.rb +3 -3
  17. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +1 -1
  18. data/lib/bridgetown-core/commands/webpack.rb +3 -3
  19. data/lib/bridgetown-core/component.rb +9 -3
  20. data/lib/bridgetown-core/concerns/site/configurable.rb +4 -0
  21. data/lib/bridgetown-core/concerns/site/content.rb +4 -4
  22. data/lib/bridgetown-core/configurations/purgecss.rb +2 -1
  23. data/lib/bridgetown-core/configurations/stimulus.rb +40 -12
  24. data/lib/bridgetown-core/configurations/tailwindcss/css_imports.css +5 -0
  25. data/lib/bridgetown-core/configurations/tailwindcss.rb +31 -2
  26. data/lib/bridgetown-core/configurations/turbo/turbo_transitions.js +48 -0
  27. data/lib/bridgetown-core/configurations/turbo.rb +15 -5
  28. data/lib/bridgetown-core/converters/erb_templates.rb +1 -1
  29. data/lib/bridgetown-core/converters/ruby_templates.rb +1 -1
  30. data/lib/bridgetown-core/converters/serbea_templates.rb +1 -1
  31. data/lib/bridgetown-core/errors.rb +21 -0
  32. data/lib/bridgetown-core/helpers.rb +3 -2
  33. data/lib/bridgetown-core/model/origin.rb +4 -6
  34. data/lib/bridgetown-core/rack/boot.rb +5 -9
  35. data/lib/bridgetown-core/ruby_template_view.rb +4 -0
  36. data/lib/bridgetown-core/tags/{webpack_path.rb → asset_path.rb} +7 -9
  37. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -1
  38. data/lib/bridgetown-core/utils.rb +63 -9
  39. data/lib/bridgetown-core/version.rb +1 -1
  40. data/lib/bridgetown-core/watcher.rb +34 -34
  41. data/lib/bridgetown-core.rb +1 -0
  42. data/lib/site_template/Gemfile.erb +17 -11
  43. data/lib/site_template/README.md +2 -2
  44. data/lib/site_template/{Rakefile → Rakefile.erb} +15 -0
  45. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.erb +11 -0
  46. data/lib/site_template/TEMPLATES/erb/_components/shared/navbar.rb +5 -0
  47. data/lib/site_template/TEMPLATES/erb/_layouts/default.erb +15 -0
  48. data/lib/site_template/TEMPLATES/erb/_layouts/page.erb +7 -0
  49. data/lib/site_template/TEMPLATES/erb/_layouts/post.erb +7 -0
  50. data/lib/site_template/TEMPLATES/erb/_partials/_footer.erb +3 -0
  51. data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +10 -0
  52. data/lib/site_template/{src → TEMPLATES/liquid}/_components/footer.liquid +0 -0
  53. data/lib/site_template/TEMPLATES/liquid/_components/head.liquid +10 -0
  54. data/lib/site_template/TEMPLATES/liquid/_components/navbar.liquid +11 -0
  55. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/default.liquid +2 -2
  56. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/page.liquid +0 -0
  57. data/lib/site_template/{src → TEMPLATES/liquid}/_layouts/post.liquid +0 -0
  58. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.rb +5 -0
  59. data/lib/site_template/TEMPLATES/serbea/_components/shared/navbar.serb +11 -0
  60. data/lib/site_template/TEMPLATES/serbea/_layouts/default.serb +15 -0
  61. data/lib/site_template/TEMPLATES/serbea/_layouts/page.serb +7 -0
  62. data/lib/site_template/TEMPLATES/serbea/_layouts/post.serb +7 -0
  63. data/lib/site_template/TEMPLATES/serbea/_partials/_footer.serb +3 -0
  64. data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +10 -0
  65. data/lib/site_template/frontend/javascript/index.js.erb +7 -3
  66. data/lib/site_template/frontend/styles/index.css +71 -6
  67. data/lib/site_template/package.json.erb +24 -9
  68. data/lib/site_template/ruby-version.erb +1 -0
  69. data/lib/site_template/server/roda_app.rb +5 -3
  70. data/lib/site_template/server/routes/hello.rb.sample +1 -1
  71. data/lib/site_template/src/images/logo.svg +91 -0
  72. data/lib/site_template/src/index.md.erb +22 -0
  73. data/lib/site_template/src/posts.md.erb +28 -0
  74. metadata +53 -22
  75. data/lib/bridgetown-core/configurations/swup.rb +0 -37
  76. data/lib/site_template/frontend/styles/index.scss +0 -17
  77. data/lib/site_template/src/_components/head.liquid +0 -10
  78. data/lib/site_template/src/_components/navbar.liquid +0 -5
  79. data/lib/site_template/src/_layouts/home.liquid +0 -7
  80. data/lib/site_template/src/images/.keep +0 -1
  81. data/lib/site_template/src/index.md +0 -7
  82. data/lib/site_template/src/posts.md +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09c13a3ec4bb37595ede90e5536eca3159812d06c482397d971d1130eab3ceab'
4
- data.tar.gz: 48cd4b6488ba57a185e510f00e6986b8514ad33887b7710431c40d9efcae4f45
3
+ metadata.gz: b6953f85017e90090c0078b710b3e447b69366bd9fed38bd5e307ee72ae3181c
4
+ data.tar.gz: 863dcdcea016110ae4e05922f7357b866bd2a77998b5da78ffb92819238c59c4
5
5
  SHA512:
6
- metadata.gz: '008f32b43e009a8349bc69fe01277c9a7ebdef2c7062d8c0dc331826d0eac394491a75b48892629d5a835eeef12e435c573d4c811ec33441555ec820870157d6'
7
- data.tar.gz: b6cf7933d50093c1332b1b39f5764768a3d8cdc3ff91b115e3d31790afa350826815f30e7d3e8c3891ddffea236f40b8e5b52268ec8eb019b4e20f319f1171ef
6
+ metadata.gz: eb6a1aa56f1544fcc37c4e204df417b5d7d37fa0e219e6a484872cdf4defee1c165fda09f4f30486d64635ef9ab6cf6db3edc8c63316dd3e61ab37be1394443c
7
+ data.tar.gz: 81b03e750b6fe6b25c1fbb2e62350f2c2776bf4902c236c5299f90c653720037e74ae8500bf71d928825efd3d83c651ad1d80523cb1362a1db2100d8f88daef9
data/.rubocop.yml CHANGED
@@ -12,6 +12,7 @@ AllCops:
12
12
  - tmp/**/*
13
13
  - test/source/**/*
14
14
  - test/resources/src/_pages/*.rb
15
+ - lib/site_template/TEMPLATES/**/*
15
16
  - lib/site_template/Rakefile
16
17
  - lib/site_template/config.ru
17
18
  - lib/site_template/config/**/*
data/bin/bridgetown CHANGED
@@ -34,4 +34,9 @@ end
34
34
  ENV["RACK_ENV"] = ENV["BRIDGETOWN_ENV"]
35
35
 
36
36
  require "bridgetown-core/commands/base"
37
- 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,15 +30,15 @@ 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")
@@ -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
@@ -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!"
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Commands
5
+ class Esbuild < Thor::Group
6
+ include Thor::Actions
7
+ extend Summarizable
8
+
9
+ Registrations.register do
10
+ register(Esbuild, "esbuild", "esbuild ACTION", Esbuild.summary)
11
+ end
12
+
13
+ def self.banner
14
+ "bridgetown esbuild ACTION"
15
+ end
16
+ summary "Perform actions on the Bridgetown esbuild configuration"
17
+
18
+ def self.exit_on_failure?
19
+ true
20
+ end
21
+
22
+ def esbuild
23
+ @logger = Bridgetown.logger
24
+ return show_actions if args.empty?
25
+
26
+ action = args.first
27
+ if supported_actions.include?(action)
28
+ perform action
29
+ else
30
+ @logger.error "Error:".red, "🚨 Please enter a valid action."
31
+ say "\n"
32
+ show_actions
33
+ end
34
+ end
35
+
36
+ def self.source_root
37
+ File.expand_path("./esbuild", __dir__)
38
+ end
39
+
40
+ def self.destination_root
41
+ config.root_dir
42
+ end
43
+
44
+ protected
45
+
46
+ def config
47
+ @config ||= Bridgetown.configuration({ root_dir: Dir.pwd })
48
+ end
49
+
50
+ def package_json
51
+ @package_json ||= begin
52
+ package_json_file = File.read(Bridgetown.sanitized_path(config.root_dir, "package.json"))
53
+ JSON.parse(package_json_file)
54
+ end
55
+ end
56
+
57
+ def perform(action)
58
+ automation = find_in_source_paths("#{action}.rb")
59
+ inside(New.created_site_dir || Dir.pwd) do
60
+ apply automation, verbose: false
61
+ end
62
+ end
63
+
64
+ def show_actions
65
+ say "Available actions:\n".bold
66
+
67
+ longest_action = supported_actions.keys.max_by(&:size).size
68
+ supported_actions.each do |action, description|
69
+ say "#{action.ljust(longest_action).to_s.bold.blue}\t# #{description}"
70
+ end
71
+ end
72
+
73
+ def supported_actions
74
+ {
75
+ setup: "Sets up an esbuild integration with Bridgetown in your project",
76
+ update: "Updates the Bridgetown esbuild defaults to the latest available version",
77
+ "migrate-from-webpack":
78
+ "Removes Webpack from your project and installs/configures esbuild",
79
+ }.with_indifferent_access
80
+ end
81
+ end
82
+ end
83
+ end