svelte-on-rails 4.1.1 → 5.0.0
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.
- checksums.yaml +4 -4
- data/README.md +123 -32
- data/lib/generators/svelte_on_rails/install/install_generator.rb +25 -0
- data/lib/svelte-on-rails.rb +4 -1
- data/lib/svelte_on_rails/installer/gem_utils.rb +1 -1
- data/lib/svelte_on_rails/installer/hello_world.rb +1 -0
- data/lib/svelte_on_rails/installer/utils.rb +21 -9
- data/lib/svelte_on_rails/renderer/render.js +11 -4
- data/lib/svelte_on_rails/renderer/renderer.rb +12 -3
- data/lib/svelte_on_rails/turbo_stream.rb +43 -0
- data/templates/config_base/config/svelte_on_rails.yml +6 -0
- data/templates/rails_vite_hello_world/app/controllers/svelte_on_rails_hello_world_controller.rb +19 -0
- data/templates/rails_vite_hello_world/app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte +1 -1
- data/templates/rails_vite_hello_world/app/frontend/javascript/components/TurboStreamsChannel.svelte +56 -0
- data/templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/_nav.html.erb +2 -0
- data/templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/_styles.html.erb +10 -0
- data/templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/turbo_streams_channel.html.erb +12 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 702cfaf256c84b2e8f17356ed333b63e14d4d1252f7e1e2dabd1698d350a4461
|
4
|
+
data.tar.gz: d7b63bfce50f3aba78c2bfd5f646bba5e02e0ae351d6cf4cc6129b8ba4ce26f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f86aafc1b3e91cbe2eff633fc40325dc048f00d5d668d52f7ea03c130f9171ecea1101a63c871883ac8ec173dfbaaa5932cb37e1de83a49fea5e3c09993463ef
|
7
|
+
data.tar.gz: 197a951604f5dcdf6c64bf7ccfcfe0fd65cd91e2ae8cb6d55c53de3bcd0b0821292856ba2cfdffb56f72a3b3d6e93b76a4e63ea08c8eb16548a03b4166cdcf10
|
data/README.md
CHANGED
@@ -12,34 +12,35 @@ Svelte.
|
|
12
12
|
|
13
13
|
Vite.
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
- Works
|
22
|
-
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
-
|
26
|
-
-
|
27
|
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
|
31
|
-
-
|
15
|
+
# Why Choose Svelte for Integration?
|
16
|
+
|
17
|
+
Svelte delivers the robust frontend experience missing from DHH’s
|
18
|
+
vision while aligning seamlessly with Rails’ full-stack philosophy.
|
19
|
+
|
20
|
+
- **Seamless Integration**
|
21
|
+
- Works flawlessly with Hotwired/Turbo
|
22
|
+
- Complements Hotwired perfectly
|
23
|
+
- **Developer-Friendly**
|
24
|
+
- Easy to learn
|
25
|
+
- Intuitive and powerful
|
26
|
+
- Lightning-fast performance
|
27
|
+
- **Compared to Single Page Apps (SPAs)**
|
28
|
+
- Full-stack development delivers maximum value:
|
29
|
+
- Unified testing from database to frontend
|
30
|
+
- Single-source system delivery
|
31
|
+
- For the most HTML Hotwired is enough
|
32
|
+
- **Compared to Hotwired**
|
33
|
+
- Stimulus is not a tool for writing frontend-apps
|
34
|
+
- Svelte eliminates redundant HTML state logic
|
35
|
+
- Consolidates component logic into a single file
|
36
|
+
- Offloads rendering of certain HTML components to frontend JavaScript, reducing server load
|
32
37
|
- **Compared to React**
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
38
|
+
- Watch Rich Harris’ [Rethinking Reactivity](https://svelte.dev/blog/svelte-3-rethinking-reactivity) (3:50–6:40) for a compelling comparison
|
39
|
+
- No shadow DOM or performance-heavy packages (e.g., useCallback)
|
40
|
+
- Leaner, slimmer packages
|
41
|
+
- Easier to learn and faster performance
|
37
42
|
|
38
|
-
|
39
|
-
by Rich Harris, especially from 3:50 to 6:40 and his comparison to react.
|
40
|
-
|
41
|
-
This all fits in perfectly with the Rails way of minimalist javascript,
|
42
|
-
but: Where needed, we want full power.
|
43
|
+
Svelte empowers Rails’ full-stack vision with modern, streamlined frontend integration.
|
43
44
|
|
44
45
|
# Features
|
45
46
|
|
@@ -314,13 +315,13 @@ When using the `cached_svelte_component` helper you must have the `redis` gem in
|
|
314
315
|
|
315
316
|
This caches on a key like `svelte-on-rails:development:SvelteOnRailsHelloWorld.svelte-1xq5tnu-User1:fscyhz-18bm76a` which includes:
|
316
317
|
|
317
|
-
- gem
|
318
|
+
- Namespace, if configured, otherwise the default is gem-name and environment
|
318
319
|
- component filename
|
319
|
-
-
|
320
|
+
- checksum of the file-path
|
320
321
|
- `cache_key` if given as argument to the view-helper
|
321
322
|
- can be a array of active-record objects or strings or a single element instead of a array
|
322
|
-
-
|
323
|
-
-
|
323
|
+
- checksum of the last modification timestamp of the component (only when `watch_changes` is set to true)
|
324
|
+
- checksum of the given attributes
|
324
325
|
|
325
326
|
**Configuration**
|
326
327
|
|
@@ -339,12 +340,98 @@ redis_cache_store:
|
|
339
340
|
expires_in: 2.hours
|
340
341
|
```
|
341
342
|
|
342
|
-
on the svelte-on-rails config file.
|
343
|
+
on the svelte-on-rails config file or pass the `expires_in` as argument to the view helper.
|
343
344
|
|
344
345
|
**Check if it works**
|
345
346
|
|
346
347
|
Pass `debug: true` to the helper and you will see on the logs how your configuration works.
|
347
348
|
|
349
|
+
# Turbo::StreamsChannel.send!
|
350
|
+
|
351
|
+
There are some methods that making it easier to let the server speak to the Components on the front.
|
352
|
+
|
353
|
+
Theese are independent class methods that can be executed from every place on the app.
|
354
|
+
|
355
|
+
Few setup is needed for that:
|
356
|
+
|
357
|
+
**Setup**
|
358
|
+
|
359
|
+
Please setup the `turbo-rails` gem and follow the chapter [Come alive with Turbo Streams](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#come-alive-with-turbo-streams)
|
360
|
+
|
361
|
+
If a channel - let's call us it `public` is working and you have a html-tag on the front
|
362
|
+
with a ID - let's call us it `svelte-on-rails-stream-actions-box` (This can be any element,
|
363
|
+
you could just give the body-tag a ID // it is just the way hotwired works)
|
364
|
+
and a code Block like
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
Turbo::StreamsChannel.send(
|
368
|
+
"broadcast_append_to",
|
369
|
+
'public',
|
370
|
+
target: 'svelte-on-rails-stream-actions-box',
|
371
|
+
content: "<div>Hello World</div>"
|
372
|
+
)
|
373
|
+
```
|
374
|
+
|
375
|
+
is exposing a «Hello World» on the front then you are good to go.
|
376
|
+
Please check the regarding keys and theyr commends on the [config file](https://gitlab.com/sedl/svelte-on-rails/-/blob/main/templates/config_base/config/svelte_on_rails.yml?ref_type=heads).
|
377
|
+
|
378
|
+
**Usage Example: Component Event**
|
379
|
+
|
380
|
+
The easiest way on the svelte component is:
|
381
|
+
|
382
|
+
```sveltehtml
|
383
|
+
<script>
|
384
|
+
import {addComponentStreamListener} from '@csedl/svelte-on-rails/src/componentStreamListener'
|
385
|
+
|
386
|
+
function handleCableEvent(event) {
|
387
|
+
console.log(event.detail.message)
|
388
|
+
}
|
389
|
+
</script>
|
390
|
+
<!--on any element:-->
|
391
|
+
<h1 use:addComponentStreamListener={handleCableEvent}>Test TurboStreams Channel</h1>
|
392
|
+
```
|
393
|
+
|
394
|
+
And call this by:
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
SvelteOnRails::TurboStream.new.dispatch_event(
|
398
|
+
event_detail: { message: "Special Chars from the server: äöü🤣🌴🌍漢字" }
|
399
|
+
)
|
400
|
+
```
|
401
|
+
|
402
|
+
**What is this doing?**
|
403
|
+
|
404
|
+
- The `addComponentStreamListener` adds a `eventListener` on the Element, that wraps each
|
405
|
+
component that is rendered by the view helper `svelte_component`, found by `currentElement.closest('.svelte-component')`
|
406
|
+
- A Stimulus controller is pushed to all subscribers of the configured channel.
|
407
|
+
- You can override this by passing `stream_name` to the method.
|
408
|
+
- Without the attribute `component` given,
|
409
|
+
it searches for all elements with the class `svelte-component` and fires the event `channel-action`
|
410
|
+
- When `selector` is given, it searches for all matching elements within each component.
|
411
|
+
- The event can be overriden by the argument `event`
|
412
|
+
|
413
|
+
By setting `debug = true` [node package](https://www.npmjs.com/package/@csedl/svelte-on-rails) you see what it is doing.
|
414
|
+
|
415
|
+
**Usage Example: Event on components element**
|
416
|
+
|
417
|
+
If you want to fire a event on a specific element within the component, you do not need `addComponentStreamListener`.
|
418
|
+
Just do something like
|
419
|
+
|
420
|
+
```sveltehtml
|
421
|
+
<button class="counter-button" onclick="{increaseCounter}">increase {counter}</button>
|
422
|
+
```
|
423
|
+
|
424
|
+
within the svelte component and call it by
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
SvelteOnRails::TurboStream.new.dispatch_event(
|
428
|
+
event: 'click',
|
429
|
+
selector: '.counter-button',
|
430
|
+
component: '/javascript/components/TurboStreamsChannel'
|
431
|
+
)
|
432
|
+
```
|
433
|
+
|
434
|
+
|
348
435
|
## More rake tasks
|
349
436
|
|
350
437
|
This tasks are more for testing/playground purposes
|
@@ -398,10 +485,14 @@ This will cause the installer, to install the npm package from a local path inst
|
|
398
485
|
|
399
486
|
Then run the tests and start contributing.
|
400
487
|
|
488
|
+
**RUN THE FIRST TEST (!)**: Testing is complex here because of the design based on the installer test.
|
489
|
+
On Problems, i always run the `Installer > destroy and create rails app > FIRST TEST > [...] check if javascript works`. When this passes,
|
490
|
+
all the others passing mostly.
|
491
|
+
|
401
492
|
Tests are based on the included templates, like the `hello world template` and on the installer.
|
402
493
|
|
403
494
|
Here I learned how to write tests! Testing installers is heavy, you will read about it in the
|
404
|
-
test_helpers. But I have
|
495
|
+
test_helpers. But I have done my best to give all the code a clear structure.
|
405
496
|
I hope you like it, and improvements are welcome.
|
406
497
|
|
407
498
|
**Installer tests** starting with completely destroy the rails app within the `generated_test_app_path`,
|
@@ -9,6 +9,7 @@ module SvelteOnRails
|
|
9
9
|
class_option :vite, type: :boolean, default: false, desc: "Use Vite"
|
10
10
|
class_option :haml, type: :boolean, default: false, desc: "Use Haml"
|
11
11
|
class_option :turbo, type: :boolean, default: false, desc: "Use @hotwired/turbo-rails"
|
12
|
+
class_option :turbo_streams, type: :boolean, default: false, desc: "Turbo::StreamsChannel"
|
12
13
|
class_option :svelte, type: :boolean, default: false, desc: "Install Svelte"
|
13
14
|
class_option :pug, type: :boolean, default: false, desc: "Install Pug"
|
14
15
|
class_option :hello_world, type: :boolean, default: false, desc: "Create Hello World component"
|
@@ -88,6 +89,20 @@ module SvelteOnRails
|
|
88
89
|
js_i = SvelteOnRails::Installer::Javascript
|
89
90
|
js_i.append_import_statement(application_js_path, tr_pkg, "import '#{tr_pkg}';")
|
90
91
|
|
92
|
+
return unless options[:turbo_streams] || options[:full]
|
93
|
+
|
94
|
+
puts '-' * 80
|
95
|
+
puts ' ▶︎▶︎▶︎ INSTALLING Turbo::StreamsChannel'
|
96
|
+
puts '-' * 80
|
97
|
+
|
98
|
+
gem_uts = SvelteOnRails::GemUtils
|
99
|
+
puts '• installing turbo-rails ...'
|
100
|
+
gem_uts.install_gem('turbo-rails')
|
101
|
+
puts '• installed turbo-rails!'
|
102
|
+
utils_i = SvelteOnRails::Installer::Utils
|
103
|
+
puts '• running turbo:install ...'
|
104
|
+
utils_i.run_command('bundle exec rails turbo:install', success_message: 'You must import')
|
105
|
+
puts '• turbo:install finished!'
|
91
106
|
end
|
92
107
|
|
93
108
|
def svelte
|
@@ -112,6 +127,12 @@ module SvelteOnRails
|
|
112
127
|
puts '-' * 80
|
113
128
|
|
114
129
|
hw_i = SvelteOnRails::Installer::HelloWorld
|
130
|
+
|
131
|
+
utils_i = SvelteOnRails::Installer::Utils
|
132
|
+
utils_i.add_route(" get \"svelte_on_rails_hello_world/turbo_streams_channel\"", app_root: Rails.root)
|
133
|
+
utils_i.add_route(" get \"svelte_on_rails_hello_world/turbo_stream_action\"", app_root: Rails.root)
|
134
|
+
npm_i = SvelteOnRails::Installer::Npm
|
135
|
+
npm_i.install_or_update_package('axios')
|
115
136
|
@hello_world_path = hw_i.install_hello_world(['rails_vite_hello_world'], app_root: nil, force: true, silent: true)
|
116
137
|
end
|
117
138
|
|
@@ -160,6 +181,10 @@ module SvelteOnRails
|
|
160
181
|
valid_display = valid_options.map { |opt| opt.gsub(/^--/, '') }.join(', ')
|
161
182
|
raise Thor::Error, "Unknown options: #{unknown_options.join(', ')}. Valid options are: #{valid_display}\nNothing done."
|
162
183
|
end
|
184
|
+
|
185
|
+
if options[:turbo_streams] && !(options[:full] || options[:turbo])
|
186
|
+
raise Thor::Error, "--turbo-streams option cannot be used without --turbo"
|
187
|
+
end
|
163
188
|
end
|
164
189
|
|
165
190
|
def application_js_path
|
data/lib/svelte-on-rails.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require "svelte_on_rails/configuration"
|
2
2
|
require "svelte_on_rails/view_helpers"
|
3
|
+
require "svelte_on_rails/turbo_stream"
|
4
|
+
require "svelte_on_rails/railtie" if defined?(Rails)
|
5
|
+
|
3
6
|
require "svelte_on_rails/renderer/renderer"
|
7
|
+
|
4
8
|
require "svelte_on_rails/lib/utils"
|
5
9
|
require "svelte_on_rails/lib/view_helper_support"
|
6
|
-
require "svelte_on_rails/railtie" if defined?(Rails)
|
7
10
|
|
8
11
|
# installer
|
9
12
|
require 'svelte_on_rails/installer/utils'
|
@@ -133,15 +133,26 @@ module SvelteOnRails
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
def self.run_command(command)
|
136
|
+
def self.run_command(command, success_message: false)
|
137
137
|
|
138
138
|
Dir.chdir(Rails.root) do
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
139
|
+
Bundler.with_unbundled_env do
|
140
|
+
`pwd`
|
141
|
+
stdout, stderr, status = Open3.capture3(command)
|
142
|
+
err_msg = if stderr.present?
|
143
|
+
stderr.strip
|
144
|
+
elsif success_message && !stdout.match(/#{success_message}/)
|
145
|
+
"missing string «#{success_message}» on result:\n\n+++#{stdout}\n+++"
|
146
|
+
else
|
147
|
+
end
|
148
|
+
|
149
|
+
if err_msg
|
150
|
+
puts "Error running command «#{command}»:"
|
151
|
+
raise err_msg
|
152
|
+
else
|
153
|
+
puts "#{command} => Success"
|
154
|
+
end
|
155
|
+
|
145
156
|
end
|
146
157
|
end
|
147
158
|
|
@@ -179,11 +190,12 @@ module SvelteOnRails
|
|
179
190
|
|
180
191
|
if existing.present? && ask_for_overwrite
|
181
192
|
begin
|
182
|
-
puts "#{'File'.pluralize(existing.length)} already exists:\n#{existing.map { |p| p[1] }.join("\n")}.\nOverwrite? (y/n)
|
193
|
+
puts "#{'File'.pluralize(existing.length)} already exists:\n#{existing.map { |p| p[1] }.join("\n")}.\nOverwrite? (y/n)
|
194
|
+
"
|
183
195
|
continue = STDIN.gets.chomp.downcase[0]
|
184
196
|
end until ['y', 'n'].include?(continue)
|
185
197
|
if continue == 'n'
|
186
|
-
puts "Skipping write #{'template'.pluralize(templates.length)}."
|
198
|
+
puts " Skipping write #{'template'.pluralize(templates.length)}."
|
187
199
|
return
|
188
200
|
end
|
189
201
|
end
|
@@ -2,18 +2,25 @@ import {loadComponentModule, readPropsFromStdin} from './utils.js';
|
|
2
2
|
|
3
3
|
(async () => {
|
4
4
|
|
5
|
+
console.log(`[svelte-on-rails:debug] awaiting load component => «${process.argv[2]}»`)
|
6
|
+
|
5
7
|
const MyComponent = await loadComponentModule(process.argv[2]);
|
8
|
+
console.log(`[svelte-on-rails:debug] component read: «${MyComponent}}»`)
|
9
|
+
|
6
10
|
const props = await readPropsFromStdin();
|
7
|
-
|
11
|
+
console.log(`[svelte-on-rails:debug] props read: «${props}»`)
|
12
|
+
|
13
|
+
const payload = {out: []};
|
8
14
|
|
9
15
|
try {
|
10
16
|
MyComponent(payload, props); // Writes directly to payload.out
|
17
|
+
console.log(`[svelte-on-rails:debug] written to payload`)
|
11
18
|
} catch (error) {
|
12
|
-
console.error('Error rendering component:', error);
|
19
|
+
console.error('[svelte-on-rails:debug] Error rendering component:', error);
|
13
20
|
process.exit(1);
|
14
21
|
}
|
15
22
|
|
16
|
-
const res = {status: 'SUCCESS', html: payload.out};
|
17
|
-
console.log(JSON.stringify(res));
|
23
|
+
const res = {status: 'SUCCESS', html: payload.out.join('')};
|
24
|
+
console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
|
18
25
|
})();
|
19
26
|
|
@@ -32,10 +32,19 @@ module SvelteOnRails
|
|
32
32
|
].join(' ')
|
33
33
|
|
34
34
|
Dir.chdir(cnf.rails_root) do
|
35
|
-
stdout, stderr, status = Open3.capture3(cmd, stdin_data: props.to_json
|
35
|
+
stdout, stderr, status = Open3.capture3(cmd, stdin_data: props.to_json)
|
36
|
+
|
37
|
+
ary = stdout.split('[svelte-on-rails:successful-json-response]')
|
38
|
+
|
39
|
+
unless ary.length == 2
|
40
|
+
raise "[svelte-on-rails] render ERROR for component: #{@component_files[:svelte_filename]}\n\ncommand:\n+++\n#{cmd}\n+++\n\nstdout:\n+++\n#{stdout}+++\n\n\nstderr:\n+++\n#{stderr}+++"
|
41
|
+
end
|
42
|
+
|
36
43
|
|
37
44
|
begin
|
38
|
-
|
45
|
+
|
46
|
+
|
47
|
+
res = JSON.parse(ary[1])
|
39
48
|
css_file = @component_files[:compiled_file] + '.css'
|
40
49
|
if File.exist?(css_file)
|
41
50
|
res['css'] = File.read(css_file)
|
@@ -50,7 +59,7 @@ module SvelteOnRails
|
|
50
59
|
return res
|
51
60
|
rescue JSON::ParserError => e
|
52
61
|
|
53
|
-
raise "[svelte-on-rails] render ERROR Svelte Server-side
|
62
|
+
raise "[svelte-on-rails] render ERROR Svelte Server-side for component: #{@component_files[:svelte_filename]}\n\nError message:\n+++\n#{e.message}\n+++\n\nstdout:\n+++\n#{stdout}+++\n\n\nstderr:\n+++\n#{stderr}+++"
|
54
63
|
end
|
55
64
|
end
|
56
65
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SvelteOnRails
|
2
|
+
class TurboStream
|
3
|
+
def dispatch_event(event: 'stream-action', event_detail: nil, selector: nil, component: nil, stream_name: nil)
|
4
|
+
|
5
|
+
args = {
|
6
|
+
eventDetail: event_detail,
|
7
|
+
component: component,
|
8
|
+
event: event,
|
9
|
+
selector: selector
|
10
|
+
}
|
11
|
+
|
12
|
+
args_enc = Base64.strict_encode64(args.to_json)
|
13
|
+
|
14
|
+
Turbo::StreamsChannel.send(
|
15
|
+
"broadcast_append_to",
|
16
|
+
stream_name || configs['stream_name'],
|
17
|
+
target: configs['target_html_id'],
|
18
|
+
content: "<div style=\"display: none;\" data-controller=\"svelte-on-rails-turbo-stream\" data-args=\"#{args_enc}\"></div>"
|
19
|
+
)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def configs
|
26
|
+
@configs ||= begin
|
27
|
+
|
28
|
+
conf = SvelteOnRails::Configuration.instance
|
29
|
+
unless conf.configs[:turbo_stream]
|
30
|
+
raise '[svelte-on-rails] missing configuration: :turbo_stream'
|
31
|
+
end
|
32
|
+
unless conf.configs[:turbo_stream]['target_html_id']
|
33
|
+
raise '[svelte-on-rails] missing configuration: turbo_stream/target_html_id'
|
34
|
+
end
|
35
|
+
unless conf.configs[:turbo_stream]['stream_name']
|
36
|
+
raise '[svelte-on-rails] missing configuration: turbo_stream/stream_name'
|
37
|
+
end
|
38
|
+
|
39
|
+
conf.configs[:turbo_stream]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -21,6 +21,12 @@ non_ssr_request_header: 'X-Turbo-Request-ID'
|
|
21
21
|
# expires_in: 90.minutes (=> default / fallback: 1 hour)
|
22
22
|
# namespace: 'my-app-svelte-on-rails'
|
23
23
|
|
24
|
+
turbo_stream:
|
25
|
+
# this part you need when you want to be able to trigger javascript actions on svelte-components from the backend
|
26
|
+
target_html_id: 'svelte-on-rails-stream-actions-box'
|
27
|
+
# html-id of any element that must exist for being able to receive actions (turbo streams can only work this way)
|
28
|
+
stream_name: 'public'
|
29
|
+
|
24
30
|
development:
|
25
31
|
watch_changes: true
|
26
32
|
# Check on every request if any file within the svelte components folder have changed, for recompiling
|
data/templates/rails_vite_hello_world/app/controllers/svelte_on_rails_hello_world_controller.rb
CHANGED
@@ -3,4 +3,23 @@ class SvelteOnRailsHelloWorldController < ApplicationController
|
|
3
3
|
def index
|
4
4
|
end
|
5
5
|
|
6
|
+
def turbo_stream_action
|
7
|
+
|
8
|
+
if params['increase']
|
9
|
+
SvelteOnRails::TurboStream.new.dispatch_event(
|
10
|
+
event: 'click',
|
11
|
+
selector: '.counter-button',
|
12
|
+
component: '/javascript/components/TurboStreamsChannel'
|
13
|
+
)
|
14
|
+
render plain: 'increase-action streamed'
|
15
|
+
else
|
16
|
+
SvelteOnRails::TurboStream.new.dispatch_event(
|
17
|
+
event_detail: { message: "Special Chars from the server: äöü🤣🌴🌍漢字", user: "Müller" }
|
18
|
+
)
|
19
|
+
render plain: 'component-action streamed'
|
20
|
+
end
|
21
|
+
|
22
|
+
head :ok
|
23
|
+
end
|
24
|
+
|
6
25
|
end
|
data/templates/rails_vite_hello_world/app/frontend/javascript/components/TurboStreamsChannel.svelte
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import axios from "axios";
|
3
|
+
import {addComponentStreamListener} from '@csedl/svelte-on-rails/src/componentStreamListener'
|
4
|
+
import { onMount } from "svelte";
|
5
|
+
|
6
|
+
let counter = $state(0)
|
7
|
+
let results = $state([])
|
8
|
+
let incrBtn
|
9
|
+
|
10
|
+
|
11
|
+
onMount(() => {
|
12
|
+
incrBtn.addEventListener('click', increaseCounter)
|
13
|
+
});
|
14
|
+
|
15
|
+
function callChannelAction(params) {
|
16
|
+
results = []
|
17
|
+
axios.get(`/svelte_on_rails_hello_world/turbo_stream_action?${params}`)
|
18
|
+
.then(function (response) {
|
19
|
+
results.push(
|
20
|
+
{
|
21
|
+
text: `server action called, status: ${response.status}`,
|
22
|
+
class: 'called-for-action'
|
23
|
+
})
|
24
|
+
})
|
25
|
+
}
|
26
|
+
|
27
|
+
function increaseCounter() {
|
28
|
+
counter += 1
|
29
|
+
}
|
30
|
+
|
31
|
+
const handleCableEvent = (ev) => {
|
32
|
+
results.push(
|
33
|
+
{
|
34
|
+
text: `Message received from TurboStream: ${JSON.stringify(ev.detail.message)}`,
|
35
|
+
class: 'stream-action-received'
|
36
|
+
}
|
37
|
+
)
|
38
|
+
};
|
39
|
+
|
40
|
+
</script>
|
41
|
+
|
42
|
+
<h1 use:addComponentStreamListener={handleCableEvent}>Test TurboStreams Channel</h1>
|
43
|
+
|
44
|
+
<p>Actions that are triggered by SvelteOnRails::TurboStream channel from the server</p>
|
45
|
+
|
46
|
+
<button onstream-action="{() => callChannelAction('increase=true')}">Call increase action over Channel</button>
|
47
|
+
|
48
|
+
<button bind:this={incrBtn} class="counter-button" onclick="{increaseCounter}">increase {counter}</button>
|
49
|
+
|
50
|
+
<button class="call-channel-action" onclick="{callChannelAction}">Action</button>
|
51
|
+
|
52
|
+
<ul class="results">
|
53
|
+
{#each results as result}
|
54
|
+
<li class="{result.class}">{result.text}</li>
|
55
|
+
{/each}
|
56
|
+
</ul>
|
@@ -4,6 +4,8 @@
|
|
4
4
|
<%= link_to 'Backend/Frontend Test', '/svelte_on_rails_hello_world/backend_frontend_rendered' %>
|
5
5
|
|
|
6
6
|
<%= link_to 'SSR-Auto rendered (default)', '/svelte_on_rails_hello_world/ssr_auto_rendered' %>
|
7
|
+
|
|
8
|
+
<%= link_to 'Turbo Streams', '/svelte_on_rails_hello_world/turbo_streams_channel' %>
|
7
9
|
</div>
|
8
10
|
|
9
11
|
<% turbo_id = request.headers['X-Turbo-Request-ID'] %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svelte-on-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Sedlmair
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- lib/svelte_on_rails/renderer/render.js
|
48
48
|
- lib/svelte_on_rails/renderer/renderer.rb
|
49
49
|
- lib/svelte_on_rails/renderer/utils.js
|
50
|
+
- lib/svelte_on_rails/turbo_stream.rb
|
50
51
|
- lib/svelte_on_rails/view_helpers.rb
|
51
52
|
- lib/tasks/svelte_on_rails_tasks.rake
|
52
53
|
- templates/config_base/app/frontend/ssr/ssr.js
|
@@ -62,6 +63,7 @@ files:
|
|
62
63
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/PngImport.svelte
|
63
64
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/SvelteOnRailsHelloWorld.svelte
|
64
65
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/SvgRawImport.svelte
|
66
|
+
- templates/rails_vite_hello_world/app/frontend/javascript/components/TurboStreamsChannel.svelte
|
65
67
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/sub/NestedComponent.svelte
|
66
68
|
- templates/rails_vite_hello_world/app/frontend/javascript/nestedJavascript.js
|
67
69
|
- templates/rails_vite_hello_world/app/frontend/javascript/nestedJavascriptToggled.js
|
@@ -70,6 +72,7 @@ files:
|
|
70
72
|
- templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/backend_frontend_rendered.html.erb
|
71
73
|
- templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/index.html.erb
|
72
74
|
- templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/ssr_auto_rendered.html.erb
|
75
|
+
- templates/rails_vite_hello_world/app/views/svelte_on_rails_hello_world/turbo_streams_channel.html.erb
|
73
76
|
homepage: https://gitlab.com/sedl/svelte-on-rails
|
74
77
|
licenses:
|
75
78
|
- MIT
|