svelte-on-rails 5.3.0 → 5.3.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.
- checksums.yaml +4 -4
- data/README.md +38 -55
- data/lib/svelte_on_rails/action_cable.rb +1 -1
- data/lib/svelte_on_rails/active_record_extensions.rb +23 -1
- data/lib/svelte_on_rails/lib/utils.rb +27 -22
- data/lib/svelte_on_rails/lib/view_helper_support.rb +7 -1
- data/lib/svelte_on_rails/renderer/render.js +2 -2
- data/lib/svelte_on_rails/turbo_stream.rb +1 -1
- data/templates/all_features_test/app/frontend/initializers/actionCable.js +2 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66ba05e463ee27dcf6234fd49f46f1879daecd331f52549080d1d9f2f9e0748d
|
4
|
+
data.tar.gz: 1947be68d44b723ed074098728db6a0aaba6e5c5bbbb72dc09604b5fc4dc93f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c4a60a0c0f2d372535af2a7972c4df70ecb2958e0f0f2e9c718f6aeeccbab8f2797c329ec8ea789e5aa9d9e5154bc5b5cc88f70d0a5211416aa1d5d0296d8ad
|
7
|
+
data.tar.gz: afa1cef4cef2787e3da4d0a040b6261f1313b503ae149238faa74f779c46a5d78a569a4ac98c84d0e76276c514d8940f9dd6b6086a58c9c7e54490a2671d18a1
|
data/README.md
CHANGED
@@ -5,24 +5,17 @@
|
|
5
5
|
|
6
6
|
---
|
7
7
|
|
8
|
-
|
9
|
-
with modern front-end requirements:
|
8
|
+
Realizing [DHH's vision](https://rubyonrails.org/2021/12/15/Rails-7-fulfilling-a-vision) with modern front-end technologies.
|
10
9
|
|
11
|
-
Svelte
|
10
|
+
# Why Integrate Svelte?
|
12
11
|
|
13
|
-
|
14
|
-
|
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.
|
12
|
+
Svelte offers the simplest and most elegant soulution to building reactive, high-performance front-end components.
|
19
13
|
|
20
14
|
- **Seamless Integration**
|
21
15
|
- Works flawlessly with Hotwired/Turbo
|
22
|
-
-
|
16
|
+
- Enhances Hotwire’s capabilities
|
23
17
|
- **Developer-Friendly**
|
24
|
-
-
|
25
|
-
- Intuitive and powerful
|
18
|
+
- Simple to learn, intuitive, and powerful
|
26
19
|
- Lightning-fast performance
|
27
20
|
- **Compared to Single Page Apps (SPAs)**
|
28
21
|
- Full-stack development delivers maximum value:
|
@@ -30,20 +23,17 @@ vision while aligning seamlessly with Rails’ full-stack philosophy.
|
|
30
23
|
- Single-source system delivery
|
31
24
|
- For the most HTML Hotwired is enough
|
32
25
|
- **Compared to Hotwired**
|
33
|
-
- Stimulus is not a tool for
|
34
|
-
- Svelte eliminates redundant HTML state logic
|
26
|
+
- Stimulus is not a tool for frontend-apps
|
27
|
+
- Svelte eliminates redundant HTML initial state logic
|
35
28
|
- Consolidates component logic into a single file
|
36
|
-
- Offloads rendering
|
29
|
+
- Offloads rendering to JavaScript by Frontend, Server side Rendering only where necessary, reducing server load
|
37
30
|
- **Compared to React/Vue**
|
38
|
-
-
|
39
|
-
-
|
31
|
+
- No virtual DOM, resulting in leaner packages and faster performance
|
32
|
+
- See Rich Harris’ [Rethinking Reactivity](https://svelte.dev/blog/svelte-3-rethinking-reactivity) (3:50–6:40) for a compelling comparison
|
40
33
|
- Easier to learn
|
41
|
-
- React and Vue
|
42
|
-
- But, for integration, like here, this is not importand
|
43
|
-
- Svelte is sufficiently established
|
44
|
-
- Svelte is younger and growing
|
34
|
+
- While React and Vue have larger communities, Svelte’s ecosystem is robust and growing, ideal for Rails integration
|
45
35
|
|
46
|
-
Svelte empowers Rails’ full-stack vision with modern,
|
36
|
+
Svelte empowers Rails’ full-stack vision with modern, efficient front-end integration.
|
47
37
|
|
48
38
|
# Features
|
49
39
|
|
@@ -389,39 +379,19 @@ on the svelte-on-rails config file or pass the `expires_in` as argument to the v
|
|
389
379
|
|
390
380
|
Pass `debug: true` to the helper and you will see on the logs how your configuration works.
|
391
381
|
|
392
|
-
## ActionCable
|
382
|
+
## ActionCable vs. TurboStream
|
393
383
|
|
394
384
|
There are two ways that the server can talk to the client over Websocket:
|
395
385
|
|
396
|
-
- ActionCable transmits directly to the frontends javascript
|
397
|
-
- TurboStreams is a wrapper around ActionCable
|
398
|
-
- You always need a html part for communication
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
Check the regarding keys and their 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).
|
403
|
-
From there, you just need:
|
404
|
-
|
405
|
-
```yaml
|
406
|
-
turbo_stream:
|
407
|
-
target_html_id: 'svelte-on-rails-stream-actions-box'
|
408
|
-
channel: 'public'
|
409
|
-
```
|
410
|
-
|
411
|
-
## ActionCable vs TurboStream
|
412
|
-
|
413
|
-
- **ActionCable**
|
414
|
-
- Cleaner setup no html needed
|
415
|
-
- Seams to initialize securer, especially for testings (not: production)
|
416
|
-
- **TurboStream**
|
417
|
-
- Secured Streams by html-tag `signed-stream-name` if you want to send confidential data
|
418
|
-
over streams or have different channels for each user privileges
|
419
|
-
- Has [Compatibility issue with UJS](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#compatibility-with-rails-ujs)
|
386
|
+
- **ActionCable** transmits directly to the frontends javascript
|
387
|
+
- **TurboStreams** is a wrapper around ActionCable
|
388
|
+
- You always need a html part for communication by secured channels
|
389
|
+
- Makes sense when you want to transfer confidential data or separate onto privileged user channels
|
390
|
+
- Has [compatibility issues with Rails-UJS](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#compatibility-with-rails-ujs)
|
420
391
|
|
392
|
+
|
421
393
|
## SvelteOnRails::ActionCable
|
422
394
|
|
423
|
-
ActionCable is the more basic library behind `TurboStream` and it is a second Option to call Javascript Actions from the server.
|
424
|
-
|
425
395
|
**Setup**
|
426
396
|
|
427
397
|
Add `app/channels/svelte_on_rails_channel.rb`
|
@@ -438,7 +408,14 @@ class SvelteOnRailsChannel < ApplicationCable::Channel
|
|
438
408
|
end
|
439
409
|
```
|
440
410
|
|
441
|
-
|
411
|
+
config
|
412
|
+
|
413
|
+
```yaml
|
414
|
+
action_cable:
|
415
|
+
channel: "svelte_on_rails_channel"
|
416
|
+
```
|
417
|
+
|
418
|
+
javascript
|
442
419
|
|
443
420
|
```shell
|
444
421
|
npm i @rails/actioncable
|
@@ -511,11 +488,6 @@ on the whole `document` and fires the given event there.
|
|
511
488
|
|
512
489
|
# SvelteOnRails::TurboStream
|
513
490
|
|
514
|
-
Turbo Stream makes more sense when you think of sending confidential data to the components
|
515
|
-
or you want to separate to channels based on user groups, for example.
|
516
|
-
|
517
|
-
Few setup is needed for that:
|
518
|
-
|
519
491
|
**Setup**
|
520
492
|
|
521
493
|
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), which mainly is:
|
@@ -542,6 +514,17 @@ you can test it by:
|
|
542
514
|
|
543
515
|
When this works you are good to go.
|
544
516
|
|
517
|
+
**Configs**
|
518
|
+
|
519
|
+
Check the regarding keys and their 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).
|
520
|
+
From there, you just need:
|
521
|
+
|
522
|
+
```yaml
|
523
|
+
turbo_stream:
|
524
|
+
target_html_id: 'svelte-on-rails-stream-actions-box'
|
525
|
+
channel: 'public'
|
526
|
+
```
|
527
|
+
|
545
528
|
**Minimal Usage Example**
|
546
529
|
|
547
530
|
And call this by:
|
@@ -10,8 +10,30 @@ module SvelteOnRails
|
|
10
10
|
# Returns a hash of attributes, methods, and associations formatted for Svelte components
|
11
11
|
def svelte_attributes(*attributes)
|
12
12
|
@svelte_attributes ||= begin
|
13
|
+
|
14
|
+
# separate offset and limit
|
15
|
+
|
16
|
+
h = attributes.grep(Hash)
|
17
|
+
attr = if h.present?
|
18
|
+
opts = h.first.symbolize_keys
|
19
|
+
offset = opts[:offset]
|
20
|
+
limit = opts[:limit]
|
21
|
+
if offset || limit
|
22
|
+
unless self.respond_to?(:each)
|
23
|
+
raise 'offset and limit are only supported for record sets that respond to :each'
|
24
|
+
end
|
25
|
+
_opts = opts.reject { |key, _| [:offset, :limit].include?(key) }
|
26
|
+
attributes.select { |item| !item.is_a?(Hash) }.push(_opts)
|
27
|
+
else
|
28
|
+
attributes
|
29
|
+
end
|
30
|
+
else
|
31
|
+
attributes
|
32
|
+
end
|
33
|
+
|
13
34
|
utils = SvelteOnRails::Lib::Utils
|
14
|
-
utils.svelte_attributes(self,
|
35
|
+
utils.svelte_attributes(self, attr, offset: offset, limit: limit)
|
36
|
+
|
15
37
|
end
|
16
38
|
end
|
17
39
|
|
@@ -163,21 +163,9 @@ module SvelteOnRails
|
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
|
-
def self.svelte_attributes(record, attributes, labels
|
166
|
+
def self.svelte_attributes(record, attributes, labels: {}, call_stack: 0, offset: nil, limit: nil)
|
167
167
|
|
168
|
-
if record.
|
169
|
-
unless record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Associations::CollectionProxy)
|
170
|
-
raise 'record set must be a Article::ActiveRecord_Associations_CollectionProxy'
|
171
|
-
end
|
172
|
-
|
173
|
-
recs = (limit ? record.limit(limit) : record)
|
174
|
-
recs2 = (offset ? recs.offset(limit) : recs)
|
175
|
-
|
176
|
-
values = recs2.map do |rec|
|
177
|
-
svelte_attributes(rec, attributes, labels, call_stack: call_stack + 1)
|
178
|
-
end
|
179
|
-
|
180
|
-
elsif record.is_a?(Class)
|
168
|
+
if record.is_a?(Class)
|
181
169
|
|
182
170
|
# this is the case if a belongs_to association is empty; In that case we pass the class itself and extract only the labels
|
183
171
|
raise 'limit and offset are supported only for iterable objects' if limit || offset
|
@@ -189,6 +177,19 @@ module SvelteOnRails
|
|
189
177
|
end
|
190
178
|
values = {}
|
191
179
|
|
180
|
+
elsif record.respond_to?(:each)
|
181
|
+
|
182
|
+
unless record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Associations::CollectionProxy)
|
183
|
+
raise 'record set must be a Article::ActiveRecord_Associations_CollectionProxy'
|
184
|
+
end
|
185
|
+
|
186
|
+
recs = (offset ? record.offset(offset) : record)
|
187
|
+
recs2 = (limit ? recs.limit(limit) : recs)
|
188
|
+
|
189
|
+
values = recs2.map do |rec|
|
190
|
+
svelte_attributes(rec, attributes, labels: labels, call_stack: call_stack + 1)
|
191
|
+
end
|
192
|
+
|
192
193
|
else
|
193
194
|
|
194
195
|
# we have a single record
|
@@ -222,20 +223,24 @@ module SvelteOnRails
|
|
222
223
|
|
223
224
|
# values
|
224
225
|
|
225
|
-
content = record.send(_key)
|
226
226
|
reflect = record.class.reflect_on_association(_key)
|
227
227
|
if reflect
|
228
|
+
recs = record.send(_key)
|
229
|
+
content = (recs.present? ? recs : reflect.active_record) # if no record, we extract only the labels
|
228
230
|
if content.respond_to?(:each)
|
229
231
|
values[_key] = svelte_attributes(
|
230
|
-
content,
|
232
|
+
content,
|
233
|
+
value,
|
234
|
+
labels: labels,
|
231
235
|
call_stack: call_stack + 1,
|
232
236
|
offset: offs,
|
233
237
|
limit: lim
|
234
238
|
)
|
235
239
|
else
|
236
240
|
values[_key] = svelte_attributes(
|
237
|
-
content
|
238
|
-
value,
|
241
|
+
content,
|
242
|
+
value,
|
243
|
+
labels: labels,
|
239
244
|
call_stack: call_stack + 1,
|
240
245
|
offset: offs,
|
241
246
|
limit: lim
|
@@ -275,12 +280,12 @@ module SvelteOnRails
|
|
275
280
|
hash_args = attributes.grep(Hash).first.with_indifferent_access # multiple arrays is not possible
|
276
281
|
|
277
282
|
offset = if hash_args["#{key}_offset"] && !record.respond_to?("#{key}_offset")
|
278
|
-
|
279
|
-
|
283
|
+
hash_args["#{key}_offset"]
|
284
|
+
end
|
280
285
|
|
281
286
|
limit = if hash_args["#{key}_limit"] && !record.respond_to?("#{key}_limit")
|
282
|
-
|
283
|
-
|
287
|
+
hash_args["#{key}_limit"]
|
288
|
+
end
|
284
289
|
|
285
290
|
[offset, limit]
|
286
291
|
end
|
@@ -79,7 +79,13 @@ module SvelteOnRails
|
|
79
79
|
|
80
80
|
def render_ssr
|
81
81
|
renderer = SvelteOnRails::Renderer.new(filename)
|
82
|
-
renderer.render(@svelte_props)
|
82
|
+
res = renderer.render(@svelte_props)
|
83
|
+
if res['html'].is_a?(Array)
|
84
|
+
res['html'] = res['html'].join
|
85
|
+
res
|
86
|
+
else
|
87
|
+
res
|
88
|
+
end
|
83
89
|
end
|
84
90
|
|
85
91
|
def custom_cache_key
|
@@ -14,13 +14,13 @@ import {loadComponentModule, readPropsFromStdin} from './utils.js';
|
|
14
14
|
|
15
15
|
try {
|
16
16
|
MyComponent(payload, props); // Writes directly to payload.out
|
17
|
-
console.log(`[svelte-on-rails:debug] written to payload`)
|
17
|
+
console.log(`[svelte-on-rails:debug] written to payload (typeof payload.out => «${typeof payload.out}»)`)
|
18
18
|
} catch (error) {
|
19
19
|
console.error('[svelte-on-rails:debug] Error rendering component:', error);
|
20
20
|
process.exit(1);
|
21
21
|
}
|
22
22
|
|
23
|
-
const res = {status: 'SUCCESS', html: payload.out
|
23
|
+
const res = {status: 'SUCCESS', html: payload.out};
|
24
24
|
console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
|
25
25
|
})();
|
26
26
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { createConsumer } from "@rails/actioncable"
|
2
|
-
import {dispatchSvelteStreamEvent, actionCableDebugLog} from '@csedl/svelte-on-rails'
|
2
|
+
import { SvelteOnRails, dispatchSvelteStreamEvent, actionCableDebugLog } from '@csedl/svelte-on-rails'
|
3
|
+
SvelteOnRails.debug = true
|
3
4
|
|
4
5
|
const consumer = createConsumer()
|
5
6
|
|