superglue 2.0.0.beta.2 → 2.0.0.rc.1

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/views/application/_humid.html.erb +1 -0
  3. data/lib/generators/superglue/install/install_generator.rb +223 -83
  4. data/lib/generators/superglue/install/templates/bun/bun.config.deepkit.js +5 -7
  5. data/lib/generators/superglue/install/templates/bun/bun.config.js +5 -7
  6. data/lib/generators/superglue/install/templates/bun/bun.config.ts.js +5 -7
  7. data/lib/generators/superglue/install/templates/bun/bun.config.typia.js +37 -0
  8. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.js +1 -1
  9. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.ts +1 -1
  10. data/lib/generators/superglue/install/templates/humid_initializer.rb +47 -0
  11. data/lib/generators/superglue/install/templates/js/application.jsx +8 -3
  12. data/lib/generators/superglue/install/templates/js/build.mjs +14 -3
  13. data/lib/generators/superglue/install/templates/js/page_to_page_mapping.js +9 -32
  14. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.js +1 -1
  15. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.ts +1 -1
  16. data/lib/generators/superglue/install/templates/rollup/rollup.config.deepkit.js +1 -1
  17. data/lib/generators/superglue/install/templates/rollup/rollup.config.js +2 -2
  18. data/lib/generators/superglue/install/templates/rollup/rollup.config.ts.js +2 -2
  19. data/lib/generators/superglue/install/templates/rollup/rollup.config.typia.js +38 -0
  20. data/lib/generators/superglue/install/templates/ssr/bun.build_ssr.js +37 -0
  21. data/lib/generators/superglue/install/templates/ssr/esbuild.build_ssr.mjs +37 -0
  22. data/lib/generators/superglue/install/templates/ssr/rollup.build_ssr.config.js +42 -0
  23. data/lib/generators/superglue/install/templates/ssr/server_rendering.jsx +22 -0
  24. data/lib/generators/superglue/install/templates/ssr/server_rendering.tsx +26 -0
  25. data/lib/generators/superglue/install/templates/ssr/shim.js +8490 -0
  26. data/lib/generators/superglue/install/templates/ssr/webpack.build_ssr.js +40 -0
  27. data/lib/generators/superglue/install/templates/ts/application.tsx +9 -5
  28. data/lib/generators/superglue/install/templates/ts/build.deepkit.mjs +13 -2
  29. data/lib/generators/superglue/install/templates/ts/build.mjs +14 -3
  30. data/lib/generators/superglue/install/templates/ts/build.typia.mjs +39 -0
  31. data/lib/generators/superglue/install/templates/ts/page_to_page_mapping.ts +11 -33
  32. data/lib/generators/superglue/install/templates/ts/tsconfig.json +1 -0
  33. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.js +1 -1
  34. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.ts +1 -1
  35. data/lib/generators/superglue/install/templates/webpack/webpack.config.typia.js +42 -0
  36. data/lib/generators/superglue/scaffold_controller/scaffold_controller_generator.rb +0 -3
  37. data/lib/generators/superglue/view_collection/view_collection_generator.rb +5 -3
  38. data/lib/superglue/engine.rb +25 -4
  39. data/lib/superglue/rendering.rb +8 -69
  40. data/lib/superglue.rb +1 -1
  41. metadata +38 -13
  42. data/lib/generators/superglue/install/templates/erb/superglue.html.erb +0 -5
  43. data/lib/superglue/resolver.rb +0 -58
  44. /data/lib/generators/superglue/view_collection/templates/js/{edit.jsx → edit.html.jsx} +0 -0
  45. /data/lib/generators/superglue/view_collection/templates/js/{index.jsx → index.html.jsx} +0 -0
  46. /data/lib/generators/superglue/view_collection/templates/js/{new.jsx → new.html.jsx} +0 -0
  47. /data/lib/generators/superglue/view_collection/templates/js/{show.jsx → show.html.jsx} +0 -0
  48. /data/lib/generators/superglue/view_collection/templates/ts/{edit.tsx → edit.html.tsx} +0 -0
  49. /data/lib/generators/superglue/view_collection/templates/ts/{index.tsx → index.html.tsx} +0 -0
  50. /data/lib/generators/superglue/view_collection/templates/ts/{new.tsx → new.html.tsx} +0 -0
  51. /data/lib/generators/superglue/view_collection/templates/ts/{show.tsx → show.html.tsx} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b145fb67a8de9d06b652077c65ca6193e060a0662d300a8b9123651886e0db7c
4
- data.tar.gz: bdb3106d98cf8c30f5efb396d21222d8ca5d750f2cbe7f3a682bca4a37259a19
3
+ metadata.gz: f28636caebe6605b85b79f28e86a49a7d96b8ebacf7e7542778ad3d20460e792
4
+ data.tar.gz: dc2a5f29d1ac8d61eb22bb77975f89873d0280202ea6be004ffaecac09c99ce1
5
5
  SHA512:
6
- metadata.gz: 38c182b8c9123751aba72d726c5d6f53152fc79de03947d8c8c1f58968436ba3c97d37fd5a22fd6ebee786ef7a5fc86f950b8ae376594fed9cd969a37a43ea41
7
- data.tar.gz: 11c8690fac03c74a48b78189ebff274bf4e6470cc6e3b7892ea9f0eaec34c3e138129af3b36cc0f87871222db7fc527a6f8fc9a375400b82b4f3b4b47a93ec4a
6
+ metadata.gz: 47eec6c67660566a23e99a91132d06529e0b51d9c01335b20c6a59454879c78cde32ba3d8fbb2741311ce6e72ec2a6309eef16ed0aae07f8ced16e2c10801d34
7
+ data.tar.gz: 81e83bbcf1f82f07b256e5312a2f0dbd647fb89231c4386f3459ca65b128c65b7248f299c8674cffa50cb8b31248f64e75af9deaf1fb37b266add3ddfeb83cc9
@@ -0,0 +1 @@
1
+ <%= Humid.render(ssr_context, render_props, request.scheme + '://' + request.host_with_port, request.fullpath).html_safe -%>
@@ -18,19 +18,23 @@ module Superglue
18
18
  required: false,
19
19
  desc: "JavaScript bundler to use (esbuild, bun, rollup, webpack). Skips interactive prompt."
20
20
 
21
- class_option :deepkit,
21
+ class_option :validator,
22
+ type: :string,
23
+ required: false,
24
+ desc: "Runtime type validator to use (deepkit, typia, none). Skips interactive prompt."
25
+
26
+ class_option :svgr,
22
27
  type: :boolean,
23
28
  required: false,
24
- desc: "Enable Deepkit runtime type validation (experimental). Skips interactive prompt."
29
+ desc: "Enable SVGR to import SVGs as React components. Skips interactive prompt."
25
30
 
26
31
  def create_files
27
32
  remove_file "#{app_js_path}/application.js"
28
33
 
29
34
  @use_typescript = options["typescript"]
30
35
  @bundler = ask_bundler
31
- @use_deepkit = @use_typescript && ask_deepkit
32
-
33
- copy_erb_files
36
+ @validator = @use_typescript ? ask_validator : "none"
37
+ @use_svgr = ask_svgr
34
38
 
35
39
  if @use_typescript
36
40
  copy_ts_files
@@ -45,6 +49,11 @@ module Superglue
45
49
  say "Copying Superglue initializer"
46
50
  copy_file "#{__dir__}/templates/initializer.rb", "config/initializers/superglue.rb"
47
51
 
52
+ say "Copying Humid initializer"
53
+ copy_file "#{__dir__}/templates/humid_initializer.rb", "config/initializers/humid.rb"
54
+
55
+ copy_ssr_files
56
+
48
57
  say "Copying application.json.props"
49
58
  copy_file "#{__dir__}/templates/application.json.props", "app/views/layouts/application.json.props"
50
59
 
@@ -54,17 +63,19 @@ module Superglue
54
63
  say "Adding required member methods to ApplicationRecord"
55
64
  add_member_methods
56
65
 
57
- say "Enabling jsx rendering defaults"
58
- insert_jsx_rendering_defaults
59
-
60
66
  install_packages
61
67
 
68
+ if @use_svgr
69
+ configure_svgr
70
+ end
71
+
62
72
  say "Superglue is Installed! 🎉", :green
63
73
  end
64
74
 
65
75
  private
66
76
 
67
77
  BUNDLERS = %w[esbuild bun rollup webpack].freeze
78
+ VALIDATORS = %w[deepkit typia none].freeze
68
79
 
69
80
  def detect_bundler
70
81
  if File.exist?("webpack.config.js")
@@ -116,16 +127,34 @@ module Superglue
116
127
  ask("Which bundler are you using?", limited_to: BUNDLERS, default: detected)
117
128
  end
118
129
 
119
- def ask_deepkit
120
- unless options["deepkit"].nil?
121
- say "Deepkit runtime type validation: #{options["deepkit"] ? "enabled" : "disabled"}", :green
122
- return options["deepkit"]
130
+ def ask_validator
131
+ if options["validator"]
132
+ validator = options["validator"]
133
+ unless VALIDATORS.include?(validator)
134
+ raise Thor::Error, "Unknown validator '#{validator}'. Must be one of: #{VALIDATORS.join(", ")}"
135
+ end
136
+ say "Runtime type validator: #{validator}", :green
137
+ return validator
138
+ end
139
+
140
+ say ""
141
+ say "Superglue can add runtime type validation during development."
142
+ say " deepkit - works with TypeScript 5 and below (uses bundler plugin)"
143
+ say " typia - works with TypeScript 6 and above (uses ttsc)"
144
+ say " none - skip runtime type validation"
145
+ ask("Which runtime type validator would you like to use?", limited_to: VALIDATORS, default: "none")
146
+ end
147
+
148
+ def ask_svgr
149
+ unless options["svgr"].nil?
150
+ say "SVGR: #{options["svgr"] ? "enabled" : "disabled"}", :green
151
+ return options["svgr"]
123
152
  end
124
153
 
125
154
  say ""
126
- say "Superglue includes an experimental Deepkit integration for runtime type"
127
- say "validation during development. This is optional and can be added later."
128
- yes?("Would you like to enable Deepkit runtime type validation? (experimental) [y/N]")
155
+ say "SVGR lets you import SVGs as React components."
156
+ say "e.g., import Logo from '@images/logo.svg'"
157
+ yes?("Would you like to enable SVGR? [y/N]")
129
158
  end
130
159
 
131
160
  def update_build_script
@@ -139,41 +168,49 @@ module Superglue
139
168
  end
140
169
  end
141
170
 
171
+ def bundler_template_for(bundler_name, base_path, variants)
172
+ if @use_typescript
173
+ variant_key = variants.key?(@validator) ? @validator : "none"
174
+ variants[variant_key]
175
+ else
176
+ base_path
177
+ end
178
+ end
179
+
142
180
  def copy_bundler_config
143
181
  case @bundler
144
182
  when "esbuild"
145
- if @use_typescript
146
- template_name = @use_deepkit ? "ts/build.deepkit.mjs" : "ts/build.mjs"
147
- say "Adding build.mjs for TypeScript compilation"
148
- copy_file "#{__dir__}/templates/#{template_name}", "build.mjs"
149
- else
150
- say "Adding build.mjs"
151
- copy_file "#{__dir__}/templates/js/build.mjs", "build.mjs"
152
- end
183
+ template_name = bundler_template_for("esbuild", "js/build.mjs", {
184
+ "deepkit" => "ts/build.deepkit.mjs",
185
+ "typia" => "ts/build.typia.mjs",
186
+ "none" => "ts/build.mjs"
187
+ })
188
+ say "Adding build.mjs for #{@use_typescript ? "TypeScript" : "JavaScript"} compilation"
189
+ copy_file "#{__dir__}/templates/#{template_name}", "build.mjs"
153
190
  when "bun"
154
- config_template = if @use_typescript
155
- @use_deepkit ? "bun/bun.config.deepkit.js" : "bun/bun.config.ts.js"
156
- else
157
- "bun/bun.config.js"
158
- end
191
+ template_name = bundler_template_for("bun", "bun/bun.config.js", {
192
+ "deepkit" => "bun/bun.config.deepkit.js",
193
+ "typia" => "bun/bun.config.typia.js",
194
+ "none" => "bun/bun.config.ts.js"
195
+ })
159
196
  say "Overwriting bun.config.js with Superglue configuration"
160
- copy_file "#{__dir__}/templates/#{config_template}", "bun.config.js"
197
+ copy_file "#{__dir__}/templates/#{template_name}", "bun.config.js"
161
198
  when "webpack"
162
- config_template = if @use_typescript
163
- @use_deepkit ? "webpack/webpack.config.deepkit.js" : "webpack/webpack.config.ts.js"
164
- else
165
- "webpack/webpack.config.js"
166
- end
199
+ template_name = bundler_template_for("webpack", "webpack/webpack.config.js", {
200
+ "deepkit" => "webpack/webpack.config.deepkit.js",
201
+ "typia" => "webpack/webpack.config.typia.js",
202
+ "none" => "webpack/webpack.config.ts.js"
203
+ })
167
204
  say "Overwriting webpack.config.js with Superglue configuration"
168
- copy_file "#{__dir__}/templates/#{config_template}", "webpack.config.js"
205
+ copy_file "#{__dir__}/templates/#{template_name}", "webpack.config.js"
169
206
  when "rollup"
170
- config_template = if @use_typescript
171
- @use_deepkit ? "rollup/rollup.config.deepkit.js" : "rollup/rollup.config.ts.js"
172
- else
173
- "rollup/rollup.config.js"
174
- end
207
+ template_name = bundler_template_for("rollup", "rollup/rollup.config.js", {
208
+ "deepkit" => "rollup/rollup.config.deepkit.js",
209
+ "typia" => "rollup/rollup.config.typia.js",
210
+ "none" => "rollup/rollup.config.ts.js"
211
+ })
175
212
  say "Overwriting rollup.config.js with Superglue configuration"
176
- copy_file "#{__dir__}/templates/#{config_template}", "rollup.config.js"
213
+ copy_file "#{__dir__}/templates/#{template_name}", "rollup.config.js"
177
214
  end
178
215
  end
179
216
 
@@ -197,18 +234,24 @@ module Superglue
197
234
 
198
235
  def install_packages
199
236
  say "Installing Superglue and friends"
200
- run "yarn add react react-dom @thoughtbot/superglue@2.0.0-beta.2"
237
+ run "yarn add react react-dom @thoughtbot/superglue@^2.0.0-beta.11"
201
238
 
202
239
  if @use_typescript
203
240
  run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper@0.0.4 typescript"
204
241
  end
205
242
 
206
- if @use_deepkit
243
+ if @validator == "deepkit"
207
244
  say "Installing Deepkit for runtime type validation"
208
245
  run "yarn add -D @deepkit/type @deepkit/core @deepkit/type-compiler"
246
+ elsif @validator == "typia"
247
+ say "Installing Typia and ttsc for runtime type validation"
248
+ run "yarn add -D typia ttsc @ttsc/unplugin"
209
249
  end
210
250
 
211
251
  case @bundler
252
+ when "esbuild"
253
+ say "Installing esbuild glob plugin"
254
+ run "yarn add -D esbuild-plugin-import-glob"
212
255
  when "bun"
213
256
  say "Installing bun glob plugin"
214
257
  run "yarn add -D bun-plugin-glob-import"
@@ -217,50 +260,14 @@ module Superglue
217
260
  run "yarn add -D esbuild-loader"
218
261
  when "rollup"
219
262
  say "Installing rollup plugins for JSX and glob support"
220
- run "yarn add -D @rollup/plugin-babel @babel/core @babel/preset-react @rollup/plugin-commonjs @rollup/plugin-alias rollup-plugin-import-meta-glob"
263
+ run "yarn add -D @rollup/plugin-babel @babel/core @babel/preset-react @rollup/plugin-commonjs @rollup/plugin-alias @rollup/plugin-replace rollup-plugin-import-meta-glob"
221
264
  if @use_typescript
222
265
  run "yarn add -D @babel/preset-typescript"
223
266
  end
224
267
  end
225
- end
226
-
227
- def insert_jsx_rendering_defaults
228
- inject_into_file "app/controllers/application_controller.rb", after: "class ApplicationController < ActionController::Base\n" do
229
- <<-RUBY
230
- # Enables Superglue rendering defaults for sensible view directories.
231
- #
232
- # without `use_jsx_rendering_defaults`:
233
- #
234
- # ```
235
- # app/views/posts/
236
- # - index.jsx
237
- # - index.json.props
238
- # - index.html.erb
239
- # ```
240
- #
241
- # with `use_jsx_rendering_defaults`:
242
- #
243
- # ```
244
- # app/views/posts/
245
- # - index.jsx
246
- # - index.json.props
247
- # ```
248
- #
249
- # before_action :use_jsx_rendering_defaults
250
- #
251
- #
252
- # The html template used when `use_jsx_rendering_defaults` is enabled.
253
- # Defaults to "application/superglue".
254
- #
255
- # superglue_template "application/superglue"
256
268
 
257
- RUBY
258
- end
259
- end
260
-
261
- def copy_erb_files
262
- say "Copying superglue.html.erb file to app/views/application/"
263
- copy_file "#{__dir__}/templates/erb/superglue.html.erb", "app/views/application/superglue.html.erb"
269
+ say "Installing build dependencies"
270
+ run "yarn add -D npm-run-all"
264
271
  end
265
272
 
266
273
  def copy_ts_files
@@ -281,11 +288,16 @@ module Superglue
281
288
  say "Copying tsconfig.json"
282
289
  copy_file "#{__dir__}/templates/ts/tsconfig.json", "tsconfig.json"
283
290
 
284
- if @use_deepkit
291
+ if @validator == "deepkit"
285
292
  say "Enabling Deepkit reflection in tsconfig.json"
286
293
  inject_into_file "tsconfig.json", before: /\n\}$/ do
287
294
  ",\n \"reflection\": true"
288
295
  end
296
+ elsif @validator == "typia"
297
+ say "Adding Superglue typia plugin to tsconfig.json"
298
+ inject_into_file "tsconfig.json", after: /"compilerOptions": \{/ do
299
+ "\n \"plugins\": [{ \"transform\": \"@thoughtbot/superglue/typia\" }],"
300
+ end
289
301
  end
290
302
  end
291
303
 
@@ -326,6 +338,134 @@ module Superglue
326
338
  end
327
339
  end
328
340
 
341
+ def copy_ssr_files
342
+ say "Adding ssr_context to ApplicationController"
343
+ inject_into_file "app/controllers/application_controller.rb", after: "class ApplicationController < ActionController::Base\n" do
344
+ " ssr_context { Humid.prepare(MINI_RACER_SSR[:context]) if defined?(MINI_RACER_SSR) }\n"
345
+ end
346
+
347
+ say "Copying MiniRacer shim"
348
+ copy_file "#{__dir__}/templates/ssr/shim.js", "shim.js"
349
+
350
+ ssr_ext = @use_typescript ? "tsx" : "jsx"
351
+
352
+ say "Copying SSR build script for #{@bundler}"
353
+ case @bundler
354
+ when "esbuild"
355
+ copy_file "#{__dir__}/templates/ssr/esbuild.build_ssr.mjs", "build_ssr.mjs"
356
+ gsub_file "build_ssr.mjs", "server_rendering.jsx", "server_rendering.#{ssr_ext}"
357
+ run %(npm pkg set scripts.build:ssr="node build_ssr.mjs")
358
+ when "bun"
359
+ copy_file "#{__dir__}/templates/ssr/bun.build_ssr.js", "build_ssr.js"
360
+ gsub_file "build_ssr.js", "server_rendering.jsx", "server_rendering.#{ssr_ext}"
361
+ run %(npm pkg set scripts.build:ssr="bun run build_ssr.js")
362
+ when "webpack"
363
+ copy_file "#{__dir__}/templates/ssr/webpack.build_ssr.js", "webpack.config.ssr.js"
364
+ gsub_file "webpack.config.ssr.js", "server_rendering.jsx", "server_rendering.#{ssr_ext}"
365
+ run %(npm pkg set scripts.build:ssr="webpack --config webpack.config.ssr.js")
366
+ when "rollup"
367
+ copy_file "#{__dir__}/templates/ssr/rollup.build_ssr.config.js", "rollup.config.ssr.js"
368
+ gsub_file "rollup.config.ssr.js", "server_rendering.jsx", "server_rendering.#{ssr_ext}"
369
+ if @use_typescript
370
+ gsub_file "rollup.config.ssr.js",
371
+ 'presets: [["@babel/preset-react", { runtime: "automatic" }]],',
372
+ 'presets: [["@babel/preset-react", { runtime: "automatic" }], "@babel/preset-typescript"],'
373
+ end
374
+ run %(npm pkg set scripts.build:ssr="rollup -c rollup.config.ssr.js")
375
+ end
376
+
377
+ if @use_typescript
378
+ say "Copying server_rendering.tsx"
379
+ copy_file "#{__dir__}/templates/ssr/server_rendering.tsx", "#{app_js_path}/server_rendering.tsx"
380
+ else
381
+ say "Copying server_rendering.jsx"
382
+ copy_file "#{__dir__}/templates/ssr/server_rendering.jsx", "#{app_js_path}/server_rendering.jsx"
383
+ end
384
+
385
+ say "Adding build:web, build:dev, and build:watch scripts"
386
+ web_build = case @bundler
387
+ when "esbuild" then "node build.mjs"
388
+ when "bun" then "bun run bun.config.js"
389
+ when "webpack" then "webpack --config webpack.config.js"
390
+ when "rollup" then "rollup -c rollup.config.js"
391
+ end
392
+
393
+ run %(npm pkg set scripts.build:web="#{web_build}")
394
+ run %(npm pkg set scripts.build="run-p 'build:web -- {@}' 'build:ssr -- {@}' --")
395
+ run %(npm pkg set scripts.build:prod="NODE_ENV=production yarn build")
396
+
397
+ if File.exist?("config/puma.rb")
398
+ say "Adding MiniRacer SSR context to puma.rb for production"
399
+ append_to_file "config/puma.rb" do
400
+ <<~RUBY
401
+
402
+ # Create a MiniRacer context for SSR on each worker boot.
403
+ # MiniRacer is thread safe but not fork safe.
404
+ if ENV["RAILS_ENV"] == "production"
405
+ on_worker_boot do
406
+ MINI_RACER_SSR = { context: MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000) }
407
+ end
408
+
409
+ on_worker_shutdown do
410
+ MINI_RACER_SSR[:context].dispose if defined?(MINI_RACER_SSR)
411
+ end
412
+ end
413
+ RUBY
414
+ end
415
+ end
416
+ end
417
+
418
+ def configure_svgr
419
+ say "Configuring SVGR"
420
+
421
+ case @bundler
422
+ when "esbuild"
423
+ run "yarn add -D esbuild-plugin-svgr"
424
+ inject_svgr_esbuild("build.mjs")
425
+ inject_svgr_esbuild("build_ssr.mjs")
426
+ when "bun"
427
+ run "yarn add -D esbuild-plugin-svgr"
428
+ inject_svgr_bun
429
+ when "webpack"
430
+ run "yarn add -D @svgr/webpack"
431
+ inject_svgr_webpack("webpack.config.js")
432
+ inject_svgr_webpack("webpack.config.ssr.js")
433
+ when "rollup"
434
+ run "yarn add -D @svgr/rollup"
435
+ inject_svgr_rollup("rollup.config.js")
436
+ inject_svgr_rollup("rollup.config.ssr.js")
437
+ end
438
+ end
439
+
440
+ def inject_svgr_esbuild(file)
441
+ prepend_to_file file, "import svgr from 'esbuild-plugin-svgr'\n"
442
+ gsub_file file, "importGlobPlugin()", "importGlobPlugin(), svgr()"
443
+ end
444
+
445
+ def inject_svgr_bun
446
+ # bun uses esbuild-plugin-svgr since its plugin API is compatible
447
+ prepend_to_file "bun.config.js", "import svgr from 'esbuild-plugin-svgr'\n"
448
+ gsub_file "bun.config.js", "globImportPlugin()", "globImportPlugin(), svgr()"
449
+ end
450
+
451
+ def inject_svgr_webpack(file)
452
+ inject_into_file file, after: /rules: \[\n/ do
453
+ <<-JS
454
+ {
455
+ test: /\\.svg$/,
456
+ use: ["@svgr/webpack"]
457
+ },
458
+ JS
459
+ end
460
+ end
461
+
462
+ def inject_svgr_rollup(file)
463
+ inject_into_file file, "import svgr from \"@svgr/rollup\"\n", before: /^export default/
464
+ inject_into_file file, after: /plugins: \[\n/ do
465
+ " svgr(),\n"
466
+ end
467
+ end
468
+
329
469
  def app_js_path
330
470
  "app/javascript/"
331
471
  end
@@ -1,5 +1,6 @@
1
1
  import { globImportPlugin } from 'bun-plugin-glob-import'
2
2
  import { bun as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
3
+ import { watch } from 'fs'
3
4
 
4
5
  const isWatch = process.argv.includes('--watch')
5
6
 
@@ -14,16 +15,13 @@ const config = {
14
15
  }
15
16
 
16
17
  if (isWatch) {
17
- const { watch } = await import('fs')
18
18
  await Bun.build(config)
19
19
  console.log('Watching for changes...')
20
20
 
21
- watch('app/javascript', { recursive: true }, async () => {
22
- await Bun.build(config)
23
- })
24
-
25
- watch('app/views', { recursive: true }, async () => {
26
- await Bun.build(config)
21
+ watch('app/views', { recursive: true }, async (event, filename) => {
22
+ if (event === 'rename' && /\.[jt]sx$/.test(filename)) {
23
+ await Bun.build(config)
24
+ }
27
25
  })
28
26
  } else {
29
27
  const result = await Bun.build(config)
@@ -1,4 +1,5 @@
1
1
  import { globImportPlugin } from 'bun-plugin-glob-import'
2
+ import { watch } from 'fs'
2
3
 
3
4
  const isWatch = process.argv.includes('--watch')
4
5
 
@@ -10,16 +11,13 @@ const config = {
10
11
  }
11
12
 
12
13
  if (isWatch) {
13
- const { watch } = await import('fs')
14
14
  await Bun.build(config)
15
15
  console.log('Watching for changes...')
16
16
 
17
- watch('app/javascript', { recursive: true }, async () => {
18
- await Bun.build(config)
19
- })
20
-
21
- watch('app/views', { recursive: true }, async () => {
22
- await Bun.build(config)
17
+ watch('app/views', { recursive: true }, async (event, filename) => {
18
+ if (event === 'rename' && /\.[jt]sx$/.test(filename)) {
19
+ await Bun.build(config)
20
+ }
23
21
  })
24
22
  } else {
25
23
  const result = await Bun.build(config)
@@ -1,4 +1,5 @@
1
1
  import { globImportPlugin } from 'bun-plugin-glob-import'
2
+ import { watch } from 'fs'
2
3
 
3
4
  const isWatch = process.argv.includes('--watch')
4
5
 
@@ -10,16 +11,13 @@ const config = {
10
11
  }
11
12
 
12
13
  if (isWatch) {
13
- const { watch } = await import('fs')
14
14
  await Bun.build(config)
15
15
  console.log('Watching for changes...')
16
16
 
17
- watch('app/javascript', { recursive: true }, async () => {
18
- await Bun.build(config)
19
- })
20
-
21
- watch('app/views', { recursive: true }, async () => {
22
- await Bun.build(config)
17
+ watch('app/views', { recursive: true }, async (event, filename) => {
18
+ if (event === 'rename' && /\.[jt]sx$/.test(filename)) {
19
+ await Bun.build(config)
20
+ }
23
21
  })
24
22
  } else {
25
23
  const result = await Bun.build(config)
@@ -0,0 +1,37 @@
1
+ import { globImportPlugin } from 'bun-plugin-glob-import'
2
+ import ttsc from '@ttsc/unplugin'
3
+ const ttscPlugin = ttsc.bun
4
+ import { watch } from 'fs'
5
+
6
+ const isWatch = process.argv.includes('--watch')
7
+
8
+ const config = {
9
+ entrypoints: ['app/javascript/application.tsx'],
10
+ outdir: 'app/assets/builds',
11
+ sourcemap: 'external',
12
+ plugins: [
13
+ globImportPlugin(),
14
+ ...(process.env.NODE_ENV === 'production' ? [] : [ttscPlugin()])
15
+ ],
16
+ }
17
+
18
+ if (isWatch) {
19
+ await Bun.build(config)
20
+ console.log('Watching for changes...')
21
+
22
+ watch('app/views', { recursive: true }, async (event, filename) => {
23
+ if (event === 'rename' && /\.[jt]sx$/.test(filename)) {
24
+ await Bun.build(config)
25
+ }
26
+ })
27
+ } else {
28
+ const result = await Bun.build(config)
29
+
30
+ if (!result.success) {
31
+ console.error('Build failed')
32
+ for (const log of result.logs) {
33
+ console.error(log)
34
+ }
35
+ process.exit(1)
36
+ }
37
+ }
@@ -1,4 +1,4 @@
1
- import { asObject as pages } from '../views/**/*.jsx'
1
+ import { asObject as pages } from '../views/**/*.{tsx,jsx}'
2
2
 
3
3
  const pageIdentifierToPageComponent = {}
4
4
 
@@ -1,4 +1,4 @@
1
- import { asObject as pages } from '../views/**/*.tsx'
1
+ import { asObject as pages } from '../views/**/*.{tsx,jsx}'
2
2
 
3
3
  const pageIdentifierToPageComponent: Record<string, React.ComponentType> = {}
4
4
 
@@ -0,0 +1,47 @@
1
+ Humid.configure do |config|
2
+ # Path to a JavaScript file to eval into the MiniRacer context before
3
+ # the SSR bundle. Provides globals that bare V8 doesn't have
4
+ # (TextEncoder, URL, MessageChannel, source-map-support, etc.).
5
+ #
6
+ # Required for SSR
7
+ config.prepend = Rails.root.join("shim.js")
8
+
9
+ # Path to your SSR build file located in `app/assets/builds/`.
10
+ # Use a separate build from your client-side `application.js`.
11
+ #
12
+ # Required
13
+ config.application_path = Rails.root.join("app/assets/builds/server_rendering.js")
14
+
15
+ # Path to your source map file
16
+ #
17
+ # Optional
18
+ config.source_map_path = Rails.root.join("app/assets/builds/server_rendering.js.map")
19
+
20
+ # Raise errors if JS rendering failed. If false, the error will be
21
+ # logged and Humid.render will return an empty string.
22
+ #
23
+ # Defaults to true.
24
+ config.raise_render_errors = Rails.env.local?
25
+
26
+ # The logger instance.
27
+ # `console.log` and friends (`warn`, `error`) are delegated to
28
+ # the respective logger levels on the ruby side.
29
+ #
30
+ # Defaults to nil
31
+ config.logger = Rails.env.local? ? Rails.logger : nil
32
+ end
33
+
34
+ if Rails.env.local?
35
+ MiniRacer::Platform.set_flags! :single_threaded
36
+ MINI_RACER_SSR = { context: MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000) }
37
+
38
+ ssr_checker = ActiveSupport::FileUpdateChecker.new([Humid.config.application_path.to_s]) do
39
+ MINI_RACER_SSR[:context].dispose
40
+ MINI_RACER_SSR[:context] = MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000)
41
+ end
42
+
43
+ Rails.application.reloaders << ssr_checker
44
+ Rails.application.reloader.to_run do
45
+ ssr_checker.execute_if_updated
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  import React from "react"
2
- import { createRoot } from "react-dom/client"
2
+ import { createRoot, hydrateRoot } from "react-dom/client"
3
3
  import { createApp } from "@thoughtbot/superglue"
4
4
  import { buildVisitAndRemote } from "./application_visit"
5
5
  import { pageIdentifierToPageComponent } from "./page_to_page_mapping"
@@ -26,8 +26,7 @@ if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
26
26
  mapping: pageIdentifierToPageComponent,
27
27
  })
28
28
 
29
- const root = createRoot(appEl)
30
- root.render(
29
+ const app = (
31
30
  <div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
32
31
  <Provider>
33
32
  <Layout>
@@ -36,6 +35,12 @@ if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
36
35
  </Provider>
37
36
  </div>
38
37
  )
38
+
39
+ if (appEl.hasChildNodes()) {
40
+ hydrateRoot(appEl, app)
41
+ } else {
42
+ createRoot(appEl).render(app)
43
+ }
39
44
  }
40
45
  })
41
46
  }