svelte-on-rails 5.1.0 → 5.2.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 +52 -55
- data/lib/generators/svelte_on_rails/install/install_generator.rb +4 -0
- data/lib/svelte_on_rails/action_cable.rb +13 -19
- data/lib/svelte_on_rails/turbo_stream.rb +2 -2
- data/templates/config_base/config/svelte_on_rails.yml +4 -0
- data/templates/rails_vite_hello_world/app/controllers/svelte_on_rails_hello_world_controller.rb +29 -19
- data/templates/rails_vite_hello_world/app/frontend/initializers/actionCable.js +17 -0
- data/templates/rails_vite_hello_world/app/frontend/javascript/components/ReceiveFromChannel.svelte +28 -32
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f7ba72715095d212a289e5fba57a8ddd78b358474e4219a5b3c47f3b7d66c88
|
4
|
+
data.tar.gz: e690deefa5507a42cf31176efc368c3ff2f304ce1ff057dc79f431e33b5c4232
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1b2150fa517ce388feaf13c9816b8d71cb339c9ac9670d7552096430a8cddff8688629ca96c58dbcde715e4f9e9b3953e6760ab6e67c37f3a0ad10797b8fcc9
|
7
|
+
data.tar.gz: 275691b15976c8dbcd551b3c07ec7495da686c7fa23192b5aca471527b4fe63c20fa8048851a3d9b0085756de52bc7ae1d1e4e5a663114a9fbed9608873ba68e
|
data/README.md
CHANGED
@@ -365,7 +365,17 @@ turbo_stream:
|
|
365
365
|
channel: 'public'
|
366
366
|
```
|
367
367
|
|
368
|
-
## ActionCable
|
368
|
+
## ActionCable vs TurboStream
|
369
|
+
|
370
|
+
- **ActionCable**
|
371
|
+
- Cleaner setup no html needed
|
372
|
+
- Seams to initialize securer, especially for testings (not: production)
|
373
|
+
- **TurboStream**
|
374
|
+
- Secured Streams by html-tag `signed-stream-name` if you want to send confidential data
|
375
|
+
over streams or have different channels for each user privileges
|
376
|
+
- Has [Compatibility issue with UJS](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#compatibility-with-rails-ujs)
|
377
|
+
|
378
|
+
## SvelteOnRails::ActionCable.send
|
369
379
|
|
370
380
|
ActionCable is the more basic library behind `TurboStream` and it is a second Option to call Javascript Actions from the server.
|
371
381
|
|
@@ -395,7 +405,8 @@ Add to `application.js`
|
|
395
405
|
|
396
406
|
```javascript
|
397
407
|
import { createConsumer } from "@rails/actioncable"
|
398
|
-
import {dispatchSvelteStreamEvent, actionCableDebugLog} from '@csedl/svelte-on-rails'
|
408
|
+
import { SvelteOnRails, dispatchSvelteStreamEvent, actionCableDebugLog } from '@csedl/svelte-on-rails'
|
409
|
+
SvelteOnRails.debug = true
|
399
410
|
|
400
411
|
const consumer = createConsumer()
|
401
412
|
|
@@ -413,9 +424,7 @@ consumer.subscriptions.create("SvelteOnRailsChannel", {
|
|
413
424
|
})
|
414
425
|
```
|
415
426
|
|
416
|
-
|
417
|
-
|
418
|
-
**WhatdispatchSvelteStreamEvent does**
|
427
|
+
**What dispatchSvelteStreamEvent does**
|
419
428
|
|
420
429
|
- Without the attribute `component` given,
|
421
430
|
it searches for all elements with the class `svelte-component` and fires the event `channel-action`
|
@@ -424,18 +433,40 @@ By setting `debug = true` [node package](https://www.npmjs.com/package/@csedl/sv
|
|
424
433
|
|
425
434
|
**Usage**
|
426
435
|
|
436
|
+
`app/frontend/javascript/components/folder/MyComponent.svelte`
|
437
|
+
|
438
|
+
```sveltehtml
|
439
|
+
<script>
|
440
|
+
import {addComponentStreamListener} from '@csedl/svelte-on-rails/src/componentStreamListener'
|
441
|
+
|
442
|
+
function handleCableEvent(event) {
|
443
|
+
console.log('Event received by Turbo Stream', event.detail)
|
444
|
+
}
|
445
|
+
</script>
|
446
|
+
<!--on ANY element:-->
|
447
|
+
<h1 use:addComponentStreamListener={handleCableEvent}>Test TurboStreams Channel</h1>
|
448
|
+
```
|
449
|
+
|
450
|
+
The `addComponentStreamListener` adds the eventListener `stream-action` on the wrapping Element.
|
451
|
+
The «wrapping Element» is the Element from the view helper `svelte_component` with the class `svelte-component`.
|
452
|
+
|
427
453
|
Now you can dispatch events on the component by:
|
428
454
|
|
429
455
|
```ruby
|
430
|
-
ActionCable.
|
431
|
-
|
432
|
-
|
433
|
-
component: '/javascript/components/ReceiveFromChannel',
|
434
|
-
}
|
456
|
+
SvelteOnRails::ActionCable.send(
|
457
|
+
'folder/MyComponent',
|
458
|
+
{ message: "greetings from Server: äöü🤣🌴🌍漢字" }
|
435
459
|
)
|
436
460
|
```
|
437
461
|
|
438
|
-
|
462
|
+
And you will find the object, with the message key on the browser logs.
|
463
|
+
|
464
|
+
Without any arguments, just by `SvelteOnRails::ActionCable.send` it would fire the `stream-action` event on all components.
|
465
|
+
|
466
|
+
# SvelteOnRails::TurboStream.send
|
467
|
+
|
468
|
+
Turbo Stream makes more sense when you think of sending confidential data to the components
|
469
|
+
or you want to separate to channels based on user groups, for example.
|
439
470
|
|
440
471
|
Few setup is needed for that:
|
441
472
|
|
@@ -449,15 +480,15 @@ rails turbo:install
|
|
449
480
|
```
|
450
481
|
|
451
482
|
make sure that `import "@hotwired/turbo-rails"` is on your application.js and set the view helper
|
452
|
-
`<%= turbo_stream_from '
|
483
|
+
`<%= turbo_stream_from 'authenticated' if current_user %>` to your view.
|
453
484
|
|
454
|
-
If a channel (e.g.: `
|
485
|
+
If a channel (e.g.: `authenticated`) is active and you have an HTML element with a HTML-ID (e.g.: `svelte-on-rails-stream-actions-box`),
|
455
486
|
you can test it by:
|
456
487
|
|
457
488
|
```ruby
|
458
489
|
Turbo::StreamsChannel.send(
|
459
490
|
"broadcast_append_to",
|
460
|
-
'
|
491
|
+
'authenticated',
|
461
492
|
target: 'svelte-on-rails-stream-actions-box',
|
462
493
|
content: "<div>Turbo-Streams are working!</div>"
|
463
494
|
)
|
@@ -467,27 +498,13 @@ When this works you are good to go.
|
|
467
498
|
|
468
499
|
**Minimal Usage Example**
|
469
500
|
|
470
|
-
```sveltehtml
|
471
|
-
<script>
|
472
|
-
import {addComponentStreamListener} from '@csedl/svelte-on-rails/src/componentStreamListener'
|
473
|
-
|
474
|
-
function handleCableEvent() {
|
475
|
-
console.log('Event received by Turbo Stream')
|
476
|
-
}
|
477
|
-
</script>
|
478
|
-
<!--on any element:-->
|
479
|
-
<h1 use:addComponentStreamListener={handleCableEvent}>Test TurboStreams Channel</h1>
|
480
|
-
```
|
481
|
-
|
482
501
|
And call this by:
|
483
502
|
|
484
503
|
```ruby
|
485
|
-
SvelteOnRails::TurboStream.
|
504
|
+
SvelteOnRails::TurboStream.send
|
486
505
|
```
|
487
506
|
**What it does**
|
488
507
|
|
489
|
-
- The `addComponentStreamListener` adds the eventListener `stream-action` on the wrapping Element
|
490
|
-
- The «wrapping Element» is the Element from the view helper `svelte_component` with the class `svelte-component`.
|
491
508
|
- A Stimulus controller is pushed to all subscribers of the configured channel.
|
492
509
|
- You can override the channel name by passing `channel` to the method.
|
493
510
|
|
@@ -519,8 +536,6 @@ Then, call it by:
|
|
519
536
|
)
|
520
537
|
```
|
521
538
|
|
522
|
-
|
523
|
-
|
524
539
|
## More rake tasks
|
525
540
|
|
526
541
|
This tasks are more for testing/playground purposes
|
@@ -575,30 +590,12 @@ This will cause the installer, to install the npm package from a local path inst
|
|
575
590
|
Then run the tests and start contributing.
|
576
591
|
|
577
592
|
**RUN THE FIRST TEST (!)**: Testing is complex here because of the design based on the installer test.
|
578
|
-
On Problems, i always run the `Installer > destroy and create rails app > FIRST TEST > [...] check if javascript works`.
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
test_helpers. But I have done my best to give all the code a clear structure.
|
585
|
-
I hope you like it, and improvements are welcome.
|
586
|
-
|
587
|
-
**Installer tests** starting with completely destroy the rails app within the `generated_test_app_path`,
|
588
|
-
generating a new rails app and running the installer and test by `playwright` if the components are working.
|
589
|
-
|
590
|
-
**component tests** only checking if a rails server is alive, and if not, install and run a rails app.
|
591
|
-
For this is the testing helper `start_rails_server_unless_ping`. This step may only be slow on the
|
592
|
-
first run, then it is fast. And on every repeating the test it always overwrites the components
|
593
|
-
with the components from the template by the testing helper `install_hello_world(
|
594
|
-
['rails_vite_hello_world'],
|
595
|
-
app_root: generated_rails_app_root,
|
596
|
-
force: true,
|
597
|
-
silent: true
|
598
|
-
)`. At the end of the test it leaves the rails server running.
|
599
|
-
|
600
|
-
On that way a developer can just edit the templates and run a test and see always the refreshed
|
601
|
-
content on the browser and on the app within the `generated_test_app_path`.
|
593
|
+
On Problems, i always run the `Installer > destroy and create rails app > FIRST TEST > [...] check if javascript works`.
|
594
|
+
If there are problems, open the generated app on a IDE and check errors there.
|
595
|
+
|
596
|
+
When this passes, all the others passing mostly.
|
597
|
+
|
598
|
+
At the end of the most tests it leaves the rails server running, so that you can see the result on `localhost:3000`.
|
602
599
|
|
603
600
|
NOTE: Theese tests are dependend on your environment, including the running ruby version!
|
604
601
|
I am working on rvm. If you work on a different environment, some (not many) changes may be necessary.
|
@@ -133,6 +133,10 @@ module SvelteOnRails
|
|
133
133
|
utils_i.add_route(" get \"svelte_on_rails_hello_world/turbo_stream_action\"", app_root: Rails.root)
|
134
134
|
npm_i = SvelteOnRails::Installer::Npm
|
135
135
|
npm_i.install_or_update_package('axios')
|
136
|
+
npm_i.install_or_update_package('@rails/actioncable')
|
137
|
+
js_i = SvelteOnRails::Installer::Javascript
|
138
|
+
init_stat = '../initializers/actionCable.js'
|
139
|
+
js_i.append_import_statement(application_js_path, init_stat, "import '#{init_stat}';")
|
136
140
|
@hello_world_path = hw_i.install_hello_world(['rails_vite_hello_world'], app_root: nil, force: true, silent: true)
|
137
141
|
end
|
138
142
|
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module SvelteOnRails
|
2
2
|
class ActionCable
|
3
|
-
def
|
3
|
+
def self.send(component = nil, event_detail = nil, event: 'stream-action', selector: nil, channel: nil)
|
4
|
+
|
5
|
+
_channel = configs['channel'] || channel
|
6
|
+
unless _channel.present?
|
7
|
+
raise 'Missing attribute or configuration: action_cable/channel'
|
8
|
+
end
|
4
9
|
|
5
10
|
if event != 'stream-action' && !selector
|
6
11
|
raise "Another event name than the default one is only possible together with a selector"
|
@@ -13,30 +18,19 @@ module SvelteOnRails
|
|
13
18
|
selector: selector
|
14
19
|
}
|
15
20
|
|
16
|
-
|
21
|
+
::ActionCable.server.broadcast(
|
22
|
+
_channel,
|
23
|
+
args
|
24
|
+
)
|
17
25
|
|
18
|
-
ActionCable.server.broadcast(channel, args)
|
19
26
|
|
20
27
|
end
|
21
28
|
|
22
29
|
private
|
23
30
|
|
24
|
-
def configs
|
25
|
-
|
26
|
-
|
27
|
-
conf = SvelteOnRails::Configuration.instance
|
28
|
-
unless conf.configs[:turbo_stream]
|
29
|
-
raise '[svelte-on-rails] missing configuration: :turbo_stream'
|
30
|
-
end
|
31
|
-
unless conf.configs[:turbo_stream]['target_html_id']
|
32
|
-
raise '[svelte-on-rails] missing configuration: turbo_stream/target_html_id'
|
33
|
-
end
|
34
|
-
unless conf.configs[:turbo_stream]['channel']
|
35
|
-
raise '[svelte-on-rails] missing configuration: turbo_stream/channel'
|
36
|
-
end
|
37
|
-
|
38
|
-
conf.configs[:turbo_stream]
|
39
|
-
end
|
31
|
+
def self.configs
|
32
|
+
SvelteOnRails::Configuration.instance.configs[:action_cable]
|
40
33
|
end
|
34
|
+
|
41
35
|
end
|
42
36
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SvelteOnRails
|
2
2
|
class TurboStream
|
3
|
-
def
|
3
|
+
def self.send(component = nil, event_detail = nil, event: 'stream-action', selector: nil, channel: nil)
|
4
4
|
|
5
5
|
if event != 'stream-action' && !selector
|
6
6
|
raise "Another event name than the default one is only possible together with a selector"
|
@@ -26,7 +26,7 @@ module SvelteOnRails
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
def configs
|
29
|
+
def self.configs
|
30
30
|
@configs ||= begin
|
31
31
|
|
32
32
|
conf = SvelteOnRails::Configuration.instance
|
@@ -27,6 +27,10 @@ turbo_stream:
|
|
27
27
|
# html-id of any element that must exist for being able to receive actions (turbo streams can only work this way)
|
28
28
|
channel: 'public'
|
29
29
|
|
30
|
+
action_cable:
|
31
|
+
# if you want to use it
|
32
|
+
channel: "svelte_on_rails_channel"
|
33
|
+
|
30
34
|
development:
|
31
35
|
watch_changes: true
|
32
36
|
# 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
@@ -5,29 +5,39 @@ class SvelteOnRailsHelloWorldController < ApplicationController
|
|
5
5
|
|
6
6
|
def turbo_stream_action
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
comp = '/javascript/components/ReceiveFromChannel'
|
9
|
+
|
10
|
+
case params['stream']
|
11
|
+
|
12
|
+
when 'action-cable-to-component'
|
13
|
+
SvelteOnRails::ActionCable.send(
|
14
|
+
comp,
|
15
|
+
{ message: "#{SecureRandom.hex(2)} Sent by <span class='transfer'>ActionCable</span>: äöü🤣🌴🌍漢字", class: 'action-cable-to-component' },
|
16
|
+
event: 'stream-action'
|
13
17
|
)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
}
|
18
|
+
|
19
|
+
when 'action-cable-to-element'
|
20
|
+
SvelteOnRails::ActionCable.send(
|
21
|
+
comp,
|
22
|
+
{ message: "#{SecureRandom.hex(2)} <span class='transfer'>ActionCable to .my-custom-class / my-custom-event</span>", class: 'action-cable-to-element' },
|
23
|
+
selector: '.my-custom-class',
|
24
|
+
event: 'my-custom-event'
|
22
25
|
)
|
23
|
-
#SvelteOnRails::ActionCable.new.dispatch_event(channel: "svelte_on_rails_channel", event_detail: { message: "Hello from SvelteChannel!" })
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
when 'turbo-stream-to-all-components'
|
28
|
+
SvelteOnRails::TurboStream.send(
|
29
|
+
nil,
|
30
|
+
{ message: "Sent by TurboStream: äöü🤣🌴🌍漢字", class: 'turbo-stream-to-all-components' },
|
31
|
+
)
|
32
|
+
|
33
|
+
when 'turbo-stream-to-element'
|
34
|
+
SvelteOnRails::TurboStream.send(
|
35
|
+
nil,
|
36
|
+
{ message: "Sent by TurboStream: äöü🤣🌴🌍漢字", class: 'turbo-stream-to-element' },
|
37
|
+
selector: '.my-custom-class',
|
38
|
+
event: 'my-custom-event'
|
29
39
|
)
|
30
|
-
|
40
|
+
|
31
41
|
end
|
32
42
|
|
33
43
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { createConsumer } from "@rails/actioncable"
|
2
|
+
import {dispatchSvelteStreamEvent, actionCableDebugLog} from '@csedl/svelte-on-rails'
|
3
|
+
|
4
|
+
const consumer = createConsumer()
|
5
|
+
|
6
|
+
consumer.subscriptions.create("SvelteOnRailsChannel", {
|
7
|
+
connected() {
|
8
|
+
actionCableDebugLog("Connected to SvelteOnRailsChannel")
|
9
|
+
},
|
10
|
+
disconnected() {
|
11
|
+
actionCableDebugLog("Disconnected from SvelteOnRailsChannel")
|
12
|
+
},
|
13
|
+
received(data) {
|
14
|
+
actionCableDebugLog("Received:", data)
|
15
|
+
dispatchSvelteStreamEvent(data)
|
16
|
+
}
|
17
|
+
})
|
data/templates/rails_vite_hello_world/app/frontend/javascript/components/ReceiveFromChannel.svelte
CHANGED
@@ -1,37 +1,31 @@
|
|
1
1
|
<script lang="ts">
|
2
2
|
import axios from "axios";
|
3
3
|
import {addComponentStreamListener} from '@csedl/svelte-on-rails/src/componentStreamListener'
|
4
|
-
import { onMount } from "svelte";
|
5
4
|
|
6
|
-
let counter = $state(0)
|
7
5
|
let results = $state([])
|
8
|
-
let incrBtn
|
9
6
|
|
10
|
-
|
11
|
-
incrBtn.addEventListener('click', increaseCounter)
|
12
|
-
});
|
13
|
-
|
14
|
-
function callChannelAction(params) {
|
7
|
+
function callChannelAction(action) {
|
15
8
|
results = []
|
16
|
-
axios.get(`/svelte_on_rails_hello_world/turbo_stream_action
|
9
|
+
axios.get(`/svelte_on_rails_hello_world/turbo_stream_action?stream=${action}`)
|
17
10
|
.then(function (response) {
|
18
|
-
|
19
|
-
{
|
20
|
-
text: `server action called, status: ${response.status}`,
|
21
|
-
class: 'called-for-action'
|
22
|
-
})
|
11
|
+
console.log(`server action called, status: ${response.status}`)
|
23
12
|
})
|
24
13
|
}
|
25
14
|
|
26
|
-
function increaseCounter() {
|
27
|
-
counter += 1
|
28
|
-
}
|
29
|
-
|
30
15
|
const handleCableEvent = (ev) => {
|
31
16
|
results.push(
|
32
17
|
{
|
33
18
|
text: `Message received from Server: ${JSON.stringify(ev.detail.message)}`,
|
34
|
-
class:
|
19
|
+
class: ev.detail.class
|
20
|
+
}
|
21
|
+
)
|
22
|
+
};
|
23
|
+
|
24
|
+
function handleElementEvent(ev) {
|
25
|
+
results.push(
|
26
|
+
{
|
27
|
+
text: `Element triggered from Server: ${JSON.stringify(ev.detail.message)}`,
|
28
|
+
class: ev.detail.class
|
35
29
|
}
|
36
30
|
)
|
37
31
|
};
|
@@ -42,16 +36,18 @@
|
|
42
36
|
|
43
37
|
<p>Actions that are triggered by SvelteOnRails::TurboStream channel from the server</p>
|
44
38
|
|
45
|
-
<button
|
46
|
-
|
47
|
-
<button
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
<
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
39
|
+
<button class="action-cable-to-component" onclick="{() => callChannelAction('action-cable-to-component')}">ActionCable to component</button>
|
40
|
+
<button class="action-cable-to-element" onclick="{() => callChannelAction('action-cable-to-element')}">ActionCable to element</button>
|
41
|
+
<button class="turbo-stream-to-all-components" onclick="{() => callChannelAction('turbo-stream-to-all-components')}">TurboStream to all components</button>
|
42
|
+
<button class="turbo-stream-to-element" onclick="{() => callChannelAction('turbo-stream-to-element')}">TurboStream to element</button>
|
43
|
+
|
44
|
+
<span class="my-custom-class" onmy-custom-event="{handleElementEvent}"></span>
|
45
|
+
|
46
|
+
<div class="results-box">
|
47
|
+
<p>Result:</p>
|
48
|
+
<ul class="results">
|
49
|
+
{#each results as result}
|
50
|
+
<li class="{result.class}">{@html result.text}</li>
|
51
|
+
{/each}
|
52
|
+
</ul>
|
53
|
+
</div>
|
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: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Sedlmair
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- templates/rails_vite_hello_world/app/frontend/images/svelte-on-rails-hello-world-england.png
|
60
60
|
- templates/rails_vite_hello_world/app/frontend/images/svelte-on-rails-hello-world-face-smile-wink.svg
|
61
61
|
- templates/rails_vite_hello_world/app/frontend/images/svelte-on-rails-hello-world-switzerland.jpg
|
62
|
+
- templates/rails_vite_hello_world/app/frontend/initializers/actionCable.js
|
62
63
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/JavascriptImport.svelte
|
63
64
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/JpgImport.svelte
|
64
65
|
- templates/rails_vite_hello_world/app/frontend/javascript/components/ParentWithChild.svelte
|