superglue 2.0.0.alpha.10 → 2.0.0.beta.2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/channels/superglue/streams/broadcasts.rb +4 -34
  3. data/app/helpers/superglue/streams_helper.rb +2 -2
  4. data/app/models/concerns/superglue/broadcastable.rb +10 -36
  5. data/lib/generators/superglue/install/install_generator.rb +193 -25
  6. data/lib/generators/superglue/install/templates/application.json.props +1 -3
  7. data/lib/generators/superglue/install/templates/bun/bun.config.deepkit.js +38 -0
  8. data/lib/generators/superglue/install/templates/bun/bun.config.js +34 -0
  9. data/lib/generators/superglue/install/templates/bun/bun.config.ts.js +34 -0
  10. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.js +10 -0
  11. data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.ts +10 -0
  12. data/lib/generators/superglue/install/templates/js/application.jsx +24 -18
  13. data/lib/generators/superglue/install/templates/js/application_visit.js +31 -61
  14. data/lib/generators/superglue/install/templates/js/build.mjs +26 -0
  15. data/lib/generators/superglue/install/templates/js/flash.js +6 -47
  16. data/lib/generators/superglue/install/templates/js/layout.jsx +2 -2
  17. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.js +9 -0
  18. data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.ts +9 -0
  19. data/lib/generators/superglue/install/templates/rollup/rollup.config.deepkit.js +37 -0
  20. data/lib/generators/superglue/install/templates/rollup/rollup.config.js +32 -0
  21. data/lib/generators/superglue/install/templates/rollup/rollup.config.ts.js +35 -0
  22. data/lib/generators/superglue/install/templates/stream.json.props +1 -3
  23. data/lib/generators/superglue/install/templates/ts/application.tsx +24 -18
  24. data/lib/generators/superglue/install/templates/ts/application_visit.ts +35 -64
  25. data/lib/generators/superglue/install/templates/ts/build.deepkit.mjs +27 -0
  26. data/lib/generators/superglue/install/templates/ts/build.mjs +26 -0
  27. data/lib/generators/superglue/install/templates/ts/flash.ts +16 -48
  28. data/lib/generators/superglue/install/templates/ts/layout.tsx +2 -2
  29. data/lib/generators/superglue/install/templates/ts/page_to_page_mapping.ts +3 -1
  30. data/lib/generators/superglue/install/templates/ts/tsconfig.json +2 -2
  31. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.js +9 -0
  32. data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.ts +9 -0
  33. data/lib/generators/superglue/install/templates/webpack/webpack.config.deepkit.js +42 -0
  34. data/lib/generators/superglue/install/templates/webpack/webpack.config.js +40 -0
  35. data/lib/generators/superglue/install/templates/webpack/webpack.config.ts.js +40 -0
  36. data/lib/generators/superglue/view_collection/templates/js/edit.jsx +7 -6
  37. data/lib/generators/superglue/view_collection/templates/js/new.jsx +9 -8
  38. data/lib/generators/superglue/view_collection/templates/ts/edit.tsx +9 -8
  39. data/lib/generators/superglue/view_collection/templates/ts/new.tsx +10 -9
  40. data/lib/superglue/engine.rb +0 -1
  41. data/lib/superglue/rendering.rb +18 -4
  42. data/lib/superglue.rb +0 -10
  43. metadata +21 -8
  44. data/app/controllers/concerns/superglue/request_id_tracking.rb +0 -16
  45. data/app/models/superglue/debouncer.rb +0 -28
  46. data/app/models/superglue/thread_debouncer.rb +0 -30
  47. data/lib/generators/superglue/install/templates/js/store.js +0 -31
  48. data/lib/generators/superglue/install/templates/ts/store.ts +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fa419e7869dd82d8ca911e9d769008878ff2f067c1f0acf04fce9a5634f12ef
4
- data.tar.gz: b9dc1c99d956a04699e96c3a297f5eb21f90621c71c56c2379da1b189ca745bc
3
+ metadata.gz: b145fb67a8de9d06b652077c65ca6193e060a0662d300a8b9123651886e0db7c
4
+ data.tar.gz: bdb3106d98cf8c30f5efb396d21222d8ca5d750f2cbe7f3a682bca4a37259a19
5
5
  SHA512:
6
- metadata.gz: 7653b40c3ba33e5c29b1f081d25ae4c18add19a8556411cff8d43f4787895baf368d99f193e7e9cc9137bf56de85d1e6918dded3abf2e0c0d9bba4e668c9f6fd
7
- data.tar.gz: bad535629a057d095e6da5b394c32fcfe46c1068cc9e5f89879e351fde17d9467c88fc85c2b9f832f50f6714ecdd28ec0d8f13706df5c7425d86db7111f7561c
6
+ metadata.gz: 38c182b8c9123751aba72d726c5d6f53152fc79de03947d8c8c1f58968436ba3c97d37fd5a22fd6ebee786ef7a5fc86f950b8ae376594fed9cd969a37a43ea41
7
+ data.tar.gz: 11c8690fac03c74a48b78189ebff274bf4e6470cc6e3b7892ea9f0eaec34c3e138129af3b36cc0f87871222db7fc527a6f8fc9a375400b82b4f3b4b47a93ec4a
@@ -2,8 +2,8 @@
2
2
  # You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
3
3
 
4
4
  module Superglue::Streams::Broadcasts
5
- def broadcast_save_to(*streamables, **opts)
6
- broadcast_action_to(*streamables, action: :save, **opts)
5
+ def broadcast_update_to(*streamables, **opts)
6
+ broadcast_action_to(*streamables, action: :update, **opts)
7
7
  end
8
8
 
9
9
  def broadcast_append_to(*streamables, **opts)
@@ -14,17 +14,6 @@ module Superglue::Streams::Broadcasts
14
14
  broadcast_action_to(*streamables, action: :prepend, **opts)
15
15
  end
16
16
 
17
- def broadcast_refresh_to(*streamables, **opts)
18
- request_id = Superglue.current_request_id
19
- content = JSON.generate({
20
- type: "message",
21
- action: "refresh",
22
- requestId: request_id,
23
- options: opts
24
- })
25
- broadcast_stream_to(*streamables, content: content)
26
- end
27
-
28
17
  def broadcast_action_to(*streamables, action:, target: nil, targets: nil, save_target: nil, options: {}, **rendering)
29
18
  locals = rendering[:locals] || {}
30
19
  targets = (target ? [target] : targets)
@@ -45,8 +34,8 @@ module Superglue::Streams::Broadcasts
45
34
  broadcast_stream_to(*streamables, content: render_broadcast_action(rendering))
46
35
  end
47
36
 
48
- def broadcast_save_later_to(*streamables, **opts)
49
- broadcast_action_later_to(*streamables, action: :save, **opts)
37
+ def broadcast_update_later_to(*streamables, **opts)
38
+ broadcast_action_later_to(*streamables, action: :update, **opts)
50
39
  end
51
40
 
52
41
  def broadcast_append_later_to(*streamables, **opts)
@@ -57,21 +46,6 @@ module Superglue::Streams::Broadcasts
57
46
  broadcast_action_later_to(*streamables, action: :prepend, **opts)
58
47
  end
59
48
 
60
- def broadcast_refresh_later_to(*streamables, request_id: Superglue.current_request_id, **opts)
61
- stream_name = stream_name_from(streamables)
62
-
63
- refresh_debouncer_for(*streamables, request_id: request_id).debounce do
64
- content = JSON.generate({
65
- type: "message",
66
- action: "refresh",
67
- requestId: request_id,
68
- options: opts
69
- })
70
-
71
- Superglue::Streams::BroadcastStreamJob.perform_later stream_name, content: content
72
- end
73
- end
74
-
75
49
  def broadcast_action_later_to(*streamables, action:, target: nil, targets: nil, save_target: nil, options: {}, **rendering)
76
50
  streamables.flatten!
77
51
  streamables.compact_blank!
@@ -99,10 +73,6 @@ module Superglue::Streams::Broadcasts
99
73
  ActionCable.server.broadcast stream_name_from(streamables), content
100
74
  end
101
75
 
102
- def refresh_debouncer_for(*streamables, request_id: nil) # :nodoc:
103
- Superglue::ThreadDebouncer.for("superglue-refresh-debouncer-#{stream_name_from(streamables.including(request_id))}")
104
- end
105
-
106
76
  private
107
77
 
108
78
  def convert_to_superglue_fragment_id(target)
@@ -36,12 +36,12 @@ module Superglue::StreamsHelper
36
36
  broadcast_action_props(action: "append", model:, target:, options:, **rendering)
37
37
  end
38
38
 
39
- def broadcast_save_props(model: nil, target: nil, options: {}, **rendering)
39
+ def broadcast_update_props(model: nil, target: nil, options: {}, **rendering)
40
40
  if model && !target
41
41
  target = fragment_id(model)
42
42
  end
43
43
 
44
- broadcast_action_props(action: "save", model:, target:, options:, **rendering)
44
+ broadcast_action_props(action: "update", model:, target:, options:, **rendering)
45
45
  end
46
46
 
47
47
  def broadcast_action_props(action:, partial: nil, model: nil, target: nil, options: {}, **rendering)
@@ -12,22 +12,12 @@ module Superglue::Broadcastable
12
12
  module ClassMethods
13
13
  def broadcasts_to(stream, inserts_by: :append, target: broadcast_target_default, save_target: nil, **rendering)
14
14
  after_create_commit -> { broadcast_action_later_to(stream.try(:call, self) || send(stream), action: inserts_by, target: target.try(:call, self) || target, save_target: save_target&.try(:call, self), **rendering) }
15
- after_update_commit -> { broadcast_save_later_to(stream.try(:call, self) || send(stream), **rendering) }
15
+ after_update_commit -> { broadcast_update_later_to(stream.try(:call, self) || send(stream), **rendering) }
16
16
  end
17
17
 
18
18
  def broadcasts(stream = model_name.plural, inserts_by: :append, target: broadcast_target_default, save_target: nil, **rendering)
19
19
  after_create_commit -> { broadcast_action_later_to(stream, action: inserts_by, target: target.try(:call, self) || target, save_target: save_target&.try(:call, self), **rendering) }
20
- after_update_commit -> { broadcast_save_later(**rendering) }
21
- end
22
-
23
- def broadcasts_refreshes_to(stream)
24
- after_commit -> { broadcast_refresh_later_to(stream.try(:call, self) || send(stream)) }
25
- end
26
-
27
- def broadcasts_refreshes(stream = model_name.plural)
28
- after_create_commit -> { broadcast_refresh_later_to(stream) }
29
- after_update_commit -> { broadcast_refresh_later }
30
- after_destroy_commit -> { broadcast_refresh }
20
+ after_update_commit -> { broadcast_update_later(**rendering) }
31
21
  end
32
22
 
33
23
  def broadcast_target_default
@@ -47,12 +37,12 @@ module Superglue::Broadcastable
47
37
  end
48
38
 
49
39
  # add target?
50
- def broadcast_save_to(*streamables, **rendering)
51
- Superglue::StreamsChannel.broadcast_save_to(*streamables, **extract_options_and_add_target(rendering, target: self)) unless suppressed_superglue_broadcasts?
40
+ def broadcast_update_to(*streamables, **rendering)
41
+ Superglue::StreamsChannel.broadcast_update_to(*streamables, **extract_options_and_add_target(rendering, target: self)) unless suppressed_superglue_broadcasts?
52
42
  end
53
43
 
54
- def broadcast_save(**rendering)
55
- broadcast_save_to self, **rendering
44
+ def broadcast_update(**rendering)
45
+ broadcast_update_to self, **rendering
56
46
  end
57
47
 
58
48
  # todo save_target: true
@@ -72,14 +62,6 @@ module Superglue::Broadcastable
72
62
  broadcast_prepend_to self, target: target, save_target: save_target, **rendering
73
63
  end
74
64
 
75
- def broadcast_refresh_to(*streamables)
76
- Superglue::StreamsChannel.broadcast_refresh_to(*streamables) unless suppressed_superglue_broadcasts?
77
- end
78
-
79
- def broadcast_refresh
80
- broadcast_refresh_to self
81
- end
82
-
83
65
  # todo rename options to js_options
84
66
  def broadcast_action_to(*streamables, action:, target: broadcast_target_default, options: {}, **rendering)
85
67
  Superglue::StreamsChannel.broadcast_action_to(*streamables, action: action, options: options, **extract_options_and_add_target(rendering, target: target)) unless suppressed_superglue_broadcasts?
@@ -89,12 +71,12 @@ module Superglue::Broadcastable
89
71
  broadcast_action_to self, action: action, target: target, options: options, **rest
90
72
  end
91
73
 
92
- def broadcast_save_later_to(*streamables, **rendering)
93
- Superglue::StreamsChannel.broadcast_save_later_to(*streamables, **extract_options_and_add_target(rendering, target: self)) unless suppressed_superglue_broadcasts?
74
+ def broadcast_update_later_to(*streamables, **rendering)
75
+ Superglue::StreamsChannel.broadcast_update_later_to(*streamables, **extract_options_and_add_target(rendering, target: self)) unless suppressed_superglue_broadcasts?
94
76
  end
95
77
 
96
- def broadcast_save_later(**rendering)
97
- broadcast_save_later_to self, **rendering
78
+ def broadcast_update_later(**rendering)
79
+ broadcast_update_later_to self, **rendering
98
80
  end
99
81
 
100
82
  def broadcast_append_later_to(*streamables, target: broadcast_target_default, save_target: nil, **rendering)
@@ -113,14 +95,6 @@ module Superglue::Broadcastable
113
95
  broadcast_prepend_later_to self, target: target, save_target: save_target, **rendering
114
96
  end
115
97
 
116
- def broadcast_refresh_later_to(*streamables)
117
- Superglue::StreamsChannel.broadcast_refresh_later_to(*streamables, request_id: Superglue.current_request_id) unless suppressed_superglue_broadcasts?
118
- end
119
-
120
- def broadcast_refresh_later
121
- broadcast_refresh_later_to self
122
- end
123
-
124
98
  def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, options: {}, **rendering)
125
99
  Superglue::StreamsChannel.broadcast_action_later_to(*streamables, action: action, options: options, **extract_options_and_add_target(rendering, target: target)) unless suppressed_superglue_broadcasts?
126
100
  end
@@ -1,3 +1,4 @@
1
+ require "json"
1
2
  require "rails/generators/named_base"
2
3
  require "rails/generators/resource_helpers"
3
4
 
@@ -12,18 +13,35 @@ module Superglue
12
13
  default: false,
13
14
  desc: "Use typescript"
14
15
 
16
+ class_option :bundler,
17
+ type: :string,
18
+ required: false,
19
+ desc: "JavaScript bundler to use (esbuild, bun, rollup, webpack). Skips interactive prompt."
20
+
21
+ class_option :deepkit,
22
+ type: :boolean,
23
+ required: false,
24
+ desc: "Enable Deepkit runtime type validation (experimental). Skips interactive prompt."
25
+
15
26
  def create_files
16
27
  remove_file "#{app_js_path}/application.js"
17
28
 
18
- use_typescript = options["typescript"]
29
+ @use_typescript = options["typescript"]
30
+ @bundler = ask_bundler
31
+ @use_deepkit = @use_typescript && ask_deepkit
32
+
19
33
  copy_erb_files
20
34
 
21
- if use_typescript
35
+ if @use_typescript
22
36
  copy_ts_files
23
37
  else
24
38
  copy_js_files
25
39
  end
26
40
 
41
+ copy_bundler_config
42
+ update_build_script
43
+ copy_page_to_page_mapping
44
+
27
45
  say "Copying Superglue initializer"
28
46
  copy_file "#{__dir__}/templates/initializer.rb", "config/initializers/superglue.rb"
29
47
 
@@ -39,18 +57,173 @@ module Superglue
39
57
  say "Enabling jsx rendering defaults"
40
58
  insert_jsx_rendering_defaults
41
59
 
42
- say "Installing Superglue and friends"
43
- run "yarn add react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue@2.0.0-alpha.8"
44
-
45
- if use_typescript
46
- run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper@0.0.4"
47
- end
60
+ install_packages
48
61
 
49
62
  say "Superglue is Installed! 🎉", :green
50
63
  end
51
64
 
52
65
  private
53
66
 
67
+ BUNDLERS = %w[esbuild bun rollup webpack].freeze
68
+
69
+ def detect_bundler
70
+ if File.exist?("webpack.config.js")
71
+ "webpack"
72
+ elsif File.exist?("rollup.config.js") || File.exist?("rollup.config.mjs")
73
+ "rollup"
74
+ elsif File.exist?("bun.config.js") || File.exist?("bun.config.mjs")
75
+ "bun"
76
+ elsif esbuild_detected?
77
+ "esbuild"
78
+ end
79
+ end
80
+
81
+ def esbuild_detected?
82
+ return true if File.exist?("build.mjs")
83
+ return false unless File.exist?("package.json")
84
+
85
+ package_json = JSON.parse(File.read("package.json"))
86
+ build_script = package_json.dig("scripts", "build") || ""
87
+ dev_deps = package_json["devDependencies"] || {}
88
+
89
+ build_script.include?("esbuild") || dev_deps.key?("esbuild")
90
+ rescue JSON::ParserError
91
+ false
92
+ end
93
+
94
+ def ask_bundler
95
+ if options["bundler"]
96
+ bundler = options["bundler"]
97
+ unless BUNDLERS.include?(bundler)
98
+ raise Thor::Error, "Unknown bundler '#{bundler}'. Must be one of: #{BUNDLERS.join(", ")}"
99
+ end
100
+ say "Using bundler: #{bundler}", :green
101
+ return bundler
102
+ end
103
+
104
+ detected = detect_bundler
105
+
106
+ if detected
107
+ say "Detected #{detected} in your project.", :green
108
+ else
109
+ say "No JavaScript bundler detected.", :red
110
+ say "Install one first via jsbundling-rails:"
111
+ say " rails javascript:install:[esbuild|bun|rollup|webpack]"
112
+ say "See: https://github.com/rails/jsbundling-rails"
113
+ raise Thor::Error, "No bundler found. Install one via jsbundling-rails and re-run this generator."
114
+ end
115
+
116
+ ask("Which bundler are you using?", limited_to: BUNDLERS, default: detected)
117
+ end
118
+
119
+ def ask_deepkit
120
+ unless options["deepkit"].nil?
121
+ say "Deepkit runtime type validation: #{options["deepkit"] ? "enabled" : "disabled"}", :green
122
+ return options["deepkit"]
123
+ end
124
+
125
+ 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]")
129
+ end
130
+
131
+ def update_build_script
132
+ case @bundler
133
+ when "esbuild"
134
+ say "Updating build script for esbuild"
135
+ run %(npm pkg set scripts.build="node build.mjs")
136
+ when "rollup"
137
+ say "Updating build script for rollup"
138
+ run %(npm pkg set scripts.build="rollup -c rollup.config.js")
139
+ end
140
+ end
141
+
142
+ def copy_bundler_config
143
+ case @bundler
144
+ 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
153
+ 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
159
+ say "Overwriting bun.config.js with Superglue configuration"
160
+ copy_file "#{__dir__}/templates/#{config_template}", "bun.config.js"
161
+ 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
167
+ say "Overwriting webpack.config.js with Superglue configuration"
168
+ copy_file "#{__dir__}/templates/#{config_template}", "webpack.config.js"
169
+ 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
175
+ say "Overwriting rollup.config.js with Superglue configuration"
176
+ copy_file "#{__dir__}/templates/#{config_template}", "rollup.config.js"
177
+ end
178
+ end
179
+
180
+ def copy_page_to_page_mapping
181
+ ext = @use_typescript ? "ts" : "js"
182
+
183
+ mapping_source = case @bundler
184
+ when "esbuild"
185
+ "#{ext}/page_to_page_mapping.#{ext}"
186
+ when "bun"
187
+ "bun/page_to_page_mapping.#{ext}"
188
+ when "webpack"
189
+ "webpack/page_to_page_mapping.#{ext}"
190
+ when "rollup"
191
+ "rollup/page_to_page_mapping.#{ext}"
192
+ end
193
+
194
+ say "Copying page_to_page_mapping.#{ext} for #{@bundler}"
195
+ copy_file "#{__dir__}/templates/#{mapping_source}", "#{app_js_path}/page_to_page_mapping.#{ext}"
196
+ end
197
+
198
+ def install_packages
199
+ say "Installing Superglue and friends"
200
+ run "yarn add react react-dom @thoughtbot/superglue@2.0.0-beta.2"
201
+
202
+ if @use_typescript
203
+ run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper@0.0.4 typescript"
204
+ end
205
+
206
+ if @use_deepkit
207
+ say "Installing Deepkit for runtime type validation"
208
+ run "yarn add -D @deepkit/type @deepkit/core @deepkit/type-compiler"
209
+ end
210
+
211
+ case @bundler
212
+ when "bun"
213
+ say "Installing bun glob plugin"
214
+ run "yarn add -D bun-plugin-glob-import"
215
+ when "webpack"
216
+ say "Installing esbuild-loader for JSX support"
217
+ run "yarn add -D esbuild-loader"
218
+ when "rollup"
219
+ 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"
221
+ if @use_typescript
222
+ run "yarn add -D @babel/preset-typescript"
223
+ end
224
+ end
225
+ end
226
+
54
227
  def insert_jsx_rendering_defaults
55
228
  inject_into_file "app/controllers/application_controller.rb", after: "class ApplicationController < ActionController::Base\n" do
56
229
  <<-RUBY
@@ -94,14 +267,8 @@ module Superglue
94
267
  say "Copying application.tsx file to #{app_js_path}"
95
268
  copy_file "#{__dir__}/templates/ts/application.tsx", "#{app_js_path}/application.tsx"
96
269
 
97
- say "Copying page_to_page_mapping.ts file to #{app_js_path}"
98
- copy_file "#{__dir__}/templates/ts/page_to_page_mapping.ts", "#{app_js_path}/page_to_page_mapping.ts"
99
-
100
270
  say "Copying flash.ts file to #{app_js_path}"
101
- copy_file "#{__dir__}/templates/ts/flash.ts", "#{app_js_path}/slices/flash.ts"
102
-
103
- say "Copying store.ts file to #{app_js_path}"
104
- copy_file "#{__dir__}/templates/ts/store.ts", "#{app_js_path}/store.ts"
271
+ copy_file "#{__dir__}/templates/ts/flash.ts", "#{app_js_path}/flash.ts"
105
272
 
106
273
  say "Copying application_visit.ts file to #{app_js_path}"
107
274
  copy_file "#{__dir__}/templates/ts/application_visit.ts", "#{app_js_path}/application_visit.ts"
@@ -111,22 +278,23 @@ module Superglue
111
278
  copy_file "#{__dir__}/templates/ts/layout.tsx", "#{app_js_path}/components/Layout.tsx"
112
279
  copy_file "#{__dir__}/templates/ts/components.ts", "#{app_js_path}/components/index.ts"
113
280
 
114
- say "Copying tsconfig.json file to #{app_js_path}"
281
+ say "Copying tsconfig.json"
115
282
  copy_file "#{__dir__}/templates/ts/tsconfig.json", "tsconfig.json"
283
+
284
+ if @use_deepkit
285
+ say "Enabling Deepkit reflection in tsconfig.json"
286
+ inject_into_file "tsconfig.json", before: /\n\}$/ do
287
+ ",\n \"reflection\": true"
288
+ end
289
+ end
116
290
  end
117
291
 
118
292
  def copy_js_files
119
- say "Copying application.js file to #{app_js_path}"
293
+ say "Copying application.jsx file to #{app_js_path}"
120
294
  copy_file "#{__dir__}/templates/js/application.jsx", "#{app_js_path}/application.jsx"
121
295
 
122
- say "Copying page_to_page_mapping.js file to #{app_js_path}"
123
- copy_file "#{__dir__}/templates/js/page_to_page_mapping.js", "#{app_js_path}/page_to_page_mapping.js"
124
-
125
296
  say "Copying flash.js file to #{app_js_path}"
126
- copy_file "#{__dir__}/templates/js/flash.js", "#{app_js_path}/slices/flash.js"
127
-
128
- say "Copying store.js file to #{app_js_path}"
129
- copy_file "#{__dir__}/templates/js/store.js", "#{app_js_path}/store.js"
297
+ copy_file "#{__dir__}/templates/js/flash.js", "#{app_js_path}/flash.js"
130
298
 
131
299
  say "Copying application_visit.js file to #{app_js_path}"
132
300
  copy_file "#{__dir__}/templates/js/application_visit.js", "#{app_js_path}/application_visit.js"
@@ -136,7 +304,7 @@ module Superglue
136
304
  copy_file "#{__dir__}/templates/js/layout.jsx", "#{app_js_path}/components/Layout.jsx"
137
305
  copy_file "#{__dir__}/templates/js/components.js", "#{app_js_path}/components/index.js"
138
306
 
139
- say "Copying jsconfig.json file to #{app_js_path}"
307
+ say "Copying jsconfig.json"
140
308
  copy_file "#{__dir__}/templates/js/jsconfig.json", "jsconfig.json"
141
309
  end
142
310
 
@@ -25,6 +25,4 @@ json.restoreStrategy 'fromCacheAndRevisitInBackground'
25
25
 
26
26
  json.renderedAt Time.now.to_i
27
27
 
28
- json.slices do
29
- json.flash flash.to_h
30
- end
28
+ json.flash flash.to_h
@@ -0,0 +1,38 @@
1
+ import { globImportPlugin } from 'bun-plugin-glob-import'
2
+ import { bun as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
3
+
4
+ const isWatch = process.argv.includes('--watch')
5
+
6
+ const config = {
7
+ entrypoints: ['app/javascript/application.tsx'],
8
+ outdir: 'app/assets/builds',
9
+ sourcemap: 'external',
10
+ plugins: [
11
+ globImportPlugin(),
12
+ ...(process.env.NODE_ENV === 'production' ? [] : [deepkitPlugin()])
13
+ ],
14
+ }
15
+
16
+ if (isWatch) {
17
+ const { watch } = await import('fs')
18
+ await Bun.build(config)
19
+ console.log('Watching for changes...')
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)
27
+ })
28
+ } else {
29
+ const result = await Bun.build(config)
30
+
31
+ if (!result.success) {
32
+ console.error('Build failed')
33
+ for (const log of result.logs) {
34
+ console.error(log)
35
+ }
36
+ process.exit(1)
37
+ }
38
+ }
@@ -0,0 +1,34 @@
1
+ import { globImportPlugin } from 'bun-plugin-glob-import'
2
+
3
+ const isWatch = process.argv.includes('--watch')
4
+
5
+ const config = {
6
+ entrypoints: ['app/javascript/application.jsx'],
7
+ outdir: 'app/assets/builds',
8
+ sourcemap: 'external',
9
+ plugins: [globImportPlugin()],
10
+ }
11
+
12
+ if (isWatch) {
13
+ const { watch } = await import('fs')
14
+ await Bun.build(config)
15
+ console.log('Watching for changes...')
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)
23
+ })
24
+ } else {
25
+ const result = await Bun.build(config)
26
+
27
+ if (!result.success) {
28
+ console.error('Build failed')
29
+ for (const log of result.logs) {
30
+ console.error(log)
31
+ }
32
+ process.exit(1)
33
+ }
34
+ }
@@ -0,0 +1,34 @@
1
+ import { globImportPlugin } from 'bun-plugin-glob-import'
2
+
3
+ const isWatch = process.argv.includes('--watch')
4
+
5
+ const config = {
6
+ entrypoints: ['app/javascript/application.tsx'],
7
+ outdir: 'app/assets/builds',
8
+ sourcemap: 'external',
9
+ plugins: [globImportPlugin()],
10
+ }
11
+
12
+ if (isWatch) {
13
+ const { watch } = await import('fs')
14
+ await Bun.build(config)
15
+ console.log('Watching for changes...')
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)
23
+ })
24
+ } else {
25
+ const result = await Bun.build(config)
26
+
27
+ if (!result.success) {
28
+ console.error('Build failed')
29
+ for (const log of result.logs) {
30
+ console.error(log)
31
+ }
32
+ process.exit(1)
33
+ }
34
+ }
@@ -0,0 +1,10 @@
1
+ import { asObject as pages } from '../views/**/*.jsx'
2
+
3
+ const pageIdentifierToPageComponent = {}
4
+
5
+ for (const key in pages) {
6
+ const identifier = key.split('.')[0]
7
+ pageIdentifierToPageComponent[identifier] = pages[key].default
8
+ }
9
+
10
+ export { pageIdentifierToPageComponent }
@@ -0,0 +1,10 @@
1
+ import { asObject as pages } from '../views/**/*.tsx'
2
+
3
+ const pageIdentifierToPageComponent: Record<string, React.ComponentType> = {}
4
+
5
+ for (const key in pages) {
6
+ const identifier = key.split('.')[0]
7
+ pageIdentifierToPageComponent[identifier] = (pages[key] as { default: React.ComponentType }).default
8
+ }
9
+
10
+ export { pageIdentifierToPageComponent }
@@ -1,9 +1,9 @@
1
1
  import React from "react"
2
2
  import { createRoot } from "react-dom/client"
3
- import { Application } from "@thoughtbot/superglue"
3
+ import { createApp } from "@thoughtbot/superglue"
4
4
  import { buildVisitAndRemote } from "./application_visit"
5
5
  import { pageIdentifierToPageComponent } from "./page_to_page_mapping"
6
- import { store } from "./store"
6
+ import { Layout } from "./components"
7
7
 
8
8
  if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
9
9
  document.addEventListener("DOMContentLoaded", function() {
@@ -11,24 +11,30 @@ if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
11
11
  const location = window.location
12
12
 
13
13
  if (appEl) {
14
+ const { Provider, Outlet, ujs } = createApp({
15
+ // The base url prefixed to all calls made by the `visit`
16
+ // and `remote` thunks.
17
+ baseUrl: location.origin,
18
+ // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
19
+ // template, e.g., index.html.erb
20
+ initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
21
+ // The initial path of the page, e.g., /foobar
22
+ path: location.pathname + location.search + location.hash,
23
+ // Callback used to setup visit and remote
24
+ buildVisitAndRemote,
25
+ // Mapping between the page identifier to page component
26
+ mapping: pageIdentifierToPageComponent,
27
+ })
28
+
14
29
  const root = createRoot(appEl)
15
30
  root.render(
16
- <Application
17
- // The base url prefixed to all calls made by the `visit`
18
- // and `remote` thunks.
19
- baseUrl={location.origin}
20
- // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
21
- // template, e.g., index.html.erb
22
- initialPage={window.SUPERGLUE_INITIAL_PAGE_STATE}
23
- // The initial path of the page, e.g., /foobar
24
- path={location.pathname + location.search + location.hash}
25
- // Callback used to setup visit and remote
26
- buildVisitAndRemote={buildVisitAndRemote}
27
- // Callback used to setup the store
28
- store={store}
29
- // Mapping between the page identifier to page component
30
- mapping={pageIdentifierToPageComponent}
31
- />
31
+ <div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
32
+ <Provider>
33
+ <Layout>
34
+ <Outlet />
35
+ </Layout>
36
+ </Provider>
37
+ </div>
32
38
  )
33
39
  }
34
40
  })