svelte-on-rails 22.3.0 → 22.4.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/lib/svelte-on-rails.rb +1 -0
- data/lib/svelte_on_rails/configuration.rb +25 -8
- data/lib/svelte_on_rails/lib/boot_context.rb +98 -0
- data/lib/svelte_on_rails/lib/view_helper_support.rb +23 -16
- data/lib/svelte_on_rails/railtie.rb +5 -4
- data/lib/svelte_on_rails/view_helpers.rb +12 -9
- data/templates/config_base/config/svelte_on_rails.yml +4 -1
- 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: e4e1180e9510fa0b8592b0b17be5ae1f75348124861184022648f2ec6b96865d
|
|
4
|
+
data.tar.gz: 737ff843db6d9fe9ae04d34fd24b214089368d2b34357ac0e64a14ff90c13d52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 769b3c284cdddd35fb86895a29a6ae3a7bce52f501cb689856c1d166892fd360a264eafe274f2cc41944ec57d1a044d25c2c3a1934149ce9e0d1afb972f4501a
|
|
7
|
+
data.tar.gz: 2d067a4983fb063fc1e38a1a68e235050d405dad829bea0727ceed9a6d0a35752909d2ae2aba99177e73af21ef01e0cd848d51c30612838ea48fda5163c95c90
|
data/lib/svelte-on-rails.rb
CHANGED
|
@@ -18,6 +18,7 @@ require "svelte_on_rails/lib/to_svelte_values"
|
|
|
18
18
|
require "svelte_on_rails/lib/to_svelte_support"
|
|
19
19
|
require "svelte_on_rails/lib/to_svelte_translations"
|
|
20
20
|
require "svelte_on_rails/lib/cache_warmer"
|
|
21
|
+
require "svelte_on_rails/lib/boot_context"
|
|
21
22
|
|
|
22
23
|
# installer
|
|
23
24
|
require 'svelte_on_rails/installer/utils'
|
|
@@ -44,14 +44,9 @@ module SvelteOnRails
|
|
|
44
44
|
|
|
45
45
|
if @configs[:redis_cache_store]
|
|
46
46
|
store = @configs[:redis_cache_store]
|
|
47
|
-
if store['expires_in'].is_a?(String)
|
|
48
|
-
@configs[:redis_cache_store]['expires_in'] = parse_duration(
|
|
49
|
-
store['expires_in']
|
|
50
|
-
)
|
|
51
|
-
end
|
|
52
47
|
@redis_namespace = store[:namespace]
|
|
53
48
|
end
|
|
54
|
-
@redis_namespace ||= "svelte-on-rails:#{Rails.env rescue 'no-env'}"
|
|
49
|
+
@redis_namespace ||= "#{app_name}:svelte-on-rails:#{Rails.env rescue 'no-env'}"
|
|
55
50
|
@configs[:skip_ssr_header] ||= 'X-Turbo-Request-ID'
|
|
56
51
|
if defined? Redis
|
|
57
52
|
@redis_instance = Redis.new(url: redis_cache_store[:url])
|
|
@@ -60,6 +55,7 @@ module SvelteOnRails
|
|
|
60
55
|
validate_serialized_configs
|
|
61
56
|
custom_config_validations
|
|
62
57
|
validate_npm_packages
|
|
58
|
+
process_configs
|
|
63
59
|
end
|
|
64
60
|
|
|
65
61
|
def set_config_defaults
|
|
@@ -175,11 +171,18 @@ module SvelteOnRails
|
|
|
175
171
|
nil
|
|
176
172
|
end
|
|
177
173
|
|
|
174
|
+
def process_configs
|
|
175
|
+
ex = @configs[:cache_expires_in]
|
|
176
|
+
if ex
|
|
177
|
+
@configs[:cache_expires_in] = ex.split('.').first.to_i.send(ex.split('.').last)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
178
181
|
private
|
|
179
182
|
|
|
180
183
|
def redis_cache_store_configs
|
|
181
184
|
if defined?(Rails.application) && Rails.application.config.cache_store.is_a?(Array) && Rails.application.config.cache_store.first == :redis_cache_store
|
|
182
|
-
{ redis_cache_store: Rails.application.config.cache_store.second.
|
|
185
|
+
{ redis_cache_store: Rails.application.config.cache_store.second.deep_symbolize_keys }
|
|
183
186
|
else
|
|
184
187
|
{}
|
|
185
188
|
end
|
|
@@ -228,7 +231,7 @@ module SvelteOnRails
|
|
|
228
231
|
ssr: { options_required: [:auto, true, false] },
|
|
229
232
|
watch_changes: { options_optional: [true, false] },
|
|
230
233
|
|
|
231
|
-
redis_cache_store: { hash_of_strings_optional: [:url, :namespace
|
|
234
|
+
redis_cache_store: { hash_of_strings_optional: [:url, :namespace] },
|
|
232
235
|
turbo_stream: { hash_of_strings_optional: [:target_html_id, :channel] },
|
|
233
236
|
action_cable: { hash_of_strings_optional: [:channel] },
|
|
234
237
|
|
|
@@ -245,6 +248,11 @@ module SvelteOnRails
|
|
|
245
248
|
elsif k == :default_components_root
|
|
246
249
|
available_keys = ['components_subdir'] + @configs[:extra_component_paths].to_a
|
|
247
250
|
raise "[SOR] Invalid configuration: #{k} must be one of: [«#{available_keys.join('», «')}»]" unless available_keys.include?(v)
|
|
251
|
+
elsif k == :cache_expires_in
|
|
252
|
+
reg = /^[0-9]+\.(minutes|hours|days)$/
|
|
253
|
+
unless v.match(reg)
|
|
254
|
+
raise "#{k} must match #{reg}"
|
|
255
|
+
end
|
|
248
256
|
elsif validation[:required]
|
|
249
257
|
if validation[:required] == :string
|
|
250
258
|
raise "[SOR] Missing configuration: #{k} must contain a string" if !v.present? || !v.is_a?(String)
|
|
@@ -262,6 +270,8 @@ module SvelteOnRails
|
|
|
262
270
|
raise "[SOR] Invalid configuration: #{k} must be one of #{validation[:options_optional]}" unless validation[:options_optional].include?(v)
|
|
263
271
|
elsif validation[:hash_of_strings_optional]
|
|
264
272
|
|
|
273
|
+
raise "[SOR] #{k} is empty. Either remove this key or provide a hash" unless v.present?
|
|
274
|
+
|
|
265
275
|
_available_keys = validation[:hash_of_strings_optional]
|
|
266
276
|
v.each do |_k, _v|
|
|
267
277
|
raise "[SOR] Invalid configuration: #{k}/#{_k} («#{_v}» / #{_v.class}) must be a string" unless _v.is_a?(String)
|
|
@@ -367,5 +377,12 @@ module SvelteOnRails
|
|
|
367
377
|
end
|
|
368
378
|
end
|
|
369
379
|
|
|
380
|
+
def app_name
|
|
381
|
+
# Same logic Rails uses internally for e.g. cache_store default namespace
|
|
382
|
+
Rails.application.class&.module_parent_name.to_s[0..30].underscore.presence || 'app'
|
|
383
|
+
rescue StandardError
|
|
384
|
+
'app'
|
|
385
|
+
end
|
|
386
|
+
|
|
370
387
|
end
|
|
371
388
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module SvelteOnRails
|
|
2
|
+
module BootContext
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
# We deliberately use a BLACKLIST + program-name check, not a whitelist of
|
|
6
|
+
# loaded constants. Reason: `puma` is typically in the app's Gemfile default
|
|
7
|
+
# group, so `defined?(::Puma::Launcher)` is truthy even inside `rails console`
|
|
8
|
+
# or `rails assets:precompile`.
|
|
9
|
+
def serving_http?
|
|
10
|
+
# Explicit overrides for tests / edge cases:
|
|
11
|
+
return true if ENV["SVELTE_ON_RAILS_FORCE_SSR"] == "1"
|
|
12
|
+
return false if ENV["SVELTE_ON_RAILS_DISABLE_SSR"] == "1"
|
|
13
|
+
|
|
14
|
+
return false if rake_task?
|
|
15
|
+
return false if rails_console?
|
|
16
|
+
return false if rails_runner?
|
|
17
|
+
return false if rails_dbconsole?
|
|
18
|
+
return false if rails_generator?
|
|
19
|
+
return false if test_runner?
|
|
20
|
+
|
|
21
|
+
# Positive signal: `rails server` sets this constant during command dispatch.
|
|
22
|
+
return true if defined?(Rails::Server)
|
|
23
|
+
|
|
24
|
+
# Positive signal: launched directly via a server binary (bundle exec puma,
|
|
25
|
+
# rackup, unicorn, falcon, passenger). $PROGRAM_NAME is set by the launcher
|
|
26
|
+
# before it requires the app, so this is reliable.
|
|
27
|
+
return true if server_program_name?
|
|
28
|
+
|
|
29
|
+
# Default: assume this is NOT an HTTP-serving context. Better to be silent
|
|
30
|
+
# than to spawn an unwanted Node process; users can force with the ENV var.
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def description
|
|
35
|
+
return "rake tasks: #{Rake.application.top_level_tasks.join(', ')}" if rake_task?
|
|
36
|
+
return "rails console" if rails_console?
|
|
37
|
+
return "rails runner" if rails_runner?
|
|
38
|
+
return "rails dbconsole" if rails_dbconsole?
|
|
39
|
+
return "rails generator" if rails_generator?
|
|
40
|
+
return "test runner (#{test_runner_name})" if test_runner?
|
|
41
|
+
return "rails server" if defined?(Rails::Server)
|
|
42
|
+
"program=#{File.basename($PROGRAM_NAME)}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# --- detectors -----------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
def rake_task?
|
|
48
|
+
defined?(Rake) && Rake.respond_to?(:application) && Rake.application.top_level_tasks.any?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def rails_console?
|
|
52
|
+
defined?(Rails::Console) ||
|
|
53
|
+
program_basename == "irb" ||
|
|
54
|
+
(defined?(IRB) && $PROGRAM_NAME.to_s.include?("irb"))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rails_runner?
|
|
58
|
+
defined?(Rails::Command::RunnerCommand) &&
|
|
59
|
+
Rails::Command.const_defined?(:RunnerCommand) &&
|
|
60
|
+
current_rails_command?("runner")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def rails_dbconsole?
|
|
64
|
+
defined?(Rails::DBConsole) || current_rails_command?("dbconsole")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def rails_generator?
|
|
68
|
+
defined?(Rails::Generators) && current_rails_command?("generate", "destroy", "new")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_runner?
|
|
72
|
+
!test_runner_name.nil?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_runner_name
|
|
76
|
+
return "rspec" if $PROGRAM_NAME.to_s.include?("rspec")
|
|
77
|
+
return "minitest" if defined?(Minitest) && Minitest.respond_to?(:run) && !defined?(Rails::Server)
|
|
78
|
+
return "cucumber" if $PROGRAM_NAME.to_s.include?("cucumber")
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def server_program_name?
|
|
83
|
+
%w[puma rackup unicorn unicorn_rails falcon passenger].include?(program_basename)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def program_basename
|
|
87
|
+
File.basename($PROGRAM_NAME.to_s)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# `rails <command>` sets ARGV[0] to the command name before Rails::Command
|
|
91
|
+
# dispatches. This is stable across Rails 6/7/8.
|
|
92
|
+
def current_rails_command?(*names)
|
|
93
|
+
argv0 = (defined?(ARGV) && ARGV.first) || nil
|
|
94
|
+
return false unless argv0
|
|
95
|
+
names.include?(argv0.to_s)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -5,7 +5,14 @@ module SvelteOnRails
|
|
|
5
5
|
class ViewHelperSupport
|
|
6
6
|
|
|
7
7
|
UNCACHED_PROPS_PLACEHOLDER = "**Uncached Props are available only after hydration**"
|
|
8
|
-
RENDER_OPTIONS = {
|
|
8
|
+
RENDER_OPTIONS = {
|
|
9
|
+
ssr: [:oneof, [true, false, :auto]],
|
|
10
|
+
hydrate: [:oneof, [true, false]],
|
|
11
|
+
debug: [:oneof, [true, false]],
|
|
12
|
+
cache_key: [:typeof, [String, Array]],
|
|
13
|
+
cache_expires_in: [:typeof, [Integer, ActiveSupport::Duration]],
|
|
14
|
+
cached: [:oneof, [true, false]]
|
|
15
|
+
}
|
|
9
16
|
attr_reader :conf
|
|
10
17
|
|
|
11
18
|
def initialize(
|
|
@@ -191,7 +198,7 @@ module SvelteOnRails
|
|
|
191
198
|
@conf.debug_log(debug?, component_paths[:name], "rendered and stored to cache (key: «#{cache_key}»)") do
|
|
192
199
|
r = view_context.instance_eval(&block)
|
|
193
200
|
unless @skip_caching
|
|
194
|
-
@conf.redis_instance.set(cache_key, r)
|
|
201
|
+
@conf.redis_instance.set(cache_key, r, ex: redis_expiration_seconds)
|
|
195
202
|
end
|
|
196
203
|
r
|
|
197
204
|
end
|
|
@@ -289,18 +296,17 @@ module SvelteOnRails
|
|
|
289
296
|
raise "Unknown options: #{@options.keys - RENDER_OPTIONS.keys}. Valid options are: :#{RENDER_OPTIONS.keys.join(', :')}"
|
|
290
297
|
end
|
|
291
298
|
@options.each do |k, v|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
raise "[SOR] Invalid option: :#{k} must be a string or Array (list of strings)."
|
|
299
|
+
validation = RENDER_OPTIONS[k]
|
|
300
|
+
_v_type = validation.first
|
|
301
|
+
_v_opts = validation.second
|
|
302
|
+
|
|
303
|
+
if validation.first == :oneof
|
|
304
|
+
unless validation.second.include? v
|
|
305
|
+
raise "[SOR] Invalid option: :#{k} must be one of #{validation.second.join(', ')}"
|
|
300
306
|
end
|
|
301
|
-
elsif
|
|
302
|
-
unless
|
|
303
|
-
raise "[SOR] Invalid option: :#{k} must be one of #{
|
|
307
|
+
elsif validation.first == :typeof
|
|
308
|
+
unless validation.second.include? v.class
|
|
309
|
+
raise "[SOR] Invalid option: :#{k} must be one of #{validation.second.join(', ')}"
|
|
304
310
|
end
|
|
305
311
|
else
|
|
306
312
|
raise "[SOR] Unknown validation for option"
|
|
@@ -337,16 +343,17 @@ module SvelteOnRails
|
|
|
337
343
|
@cache_key = begin
|
|
338
344
|
fingerprint = (@conf.watch_changes? ? @conf.fingerprint(component_paths[:path], debug?, component_paths[:name]) : '')
|
|
339
345
|
|
|
340
|
-
cache_key_raw = @
|
|
346
|
+
cache_key_raw = @options.to_s +
|
|
341
347
|
@cached_props.to_s + fingerprint + @options[:cache_key].to_s +
|
|
342
348
|
(@cached_props.key?(:_uncached) ? "" : @html_options.to_s)
|
|
343
349
|
|
|
344
|
-
"#{@conf.redis_namespace}:#{Digest::XXH64.hexdigest(cache_key_raw)}"
|
|
350
|
+
"#{@conf.redis_namespace}:#{@component_name.gsub('/','-')}:#{Digest::XXH64.hexdigest(cache_key_raw)}"
|
|
345
351
|
end
|
|
346
352
|
end
|
|
347
353
|
|
|
348
354
|
def redis_expiration_seconds
|
|
349
|
-
|
|
355
|
+
ex = @options[:cache_expires_in] || conf.configs[:cache_expires_in] || 3.days
|
|
356
|
+
ex.to_i
|
|
350
357
|
end
|
|
351
358
|
|
|
352
359
|
end
|
|
@@ -13,12 +13,14 @@ module SvelteOnRails
|
|
|
13
13
|
|
|
14
14
|
# Spawn the Node SSR child process only when we're really about to serve
|
|
15
15
|
# HTTP. `after_initialize` runs at the end of boot, so Puma/Unicorn/etc.
|
|
16
|
-
# are already loaded and the detection in `
|
|
16
|
+
# are already loaded and the detection in `serving_http?` is reliable.
|
|
17
17
|
initializer "svelte-on-rails.initialize_ssr_client" do |app|
|
|
18
18
|
app.config.after_initialize do
|
|
19
19
|
|
|
20
|
-
if
|
|
21
|
-
SvelteOnRails::Lib::Utils.ssr_server_log(
|
|
20
|
+
if !SvelteOnRails::BootContext.serving_http?
|
|
21
|
+
SvelteOnRails::Lib::Utils.ssr_server_log(
|
|
22
|
+
"Skipping svelte-on-rails SSR-Server (#{SvelteOnRails::BootContext.description})"
|
|
23
|
+
)
|
|
22
24
|
$stdout.flush
|
|
23
25
|
elsif SvelteOnRails::Configuration.instance.configs[:ssr]
|
|
24
26
|
SvelteOnRails::SsrClient.instance
|
|
@@ -53,6 +55,5 @@ module SvelteOnRails
|
|
|
53
55
|
load File.expand_path("../../tasks/svelte_on_rails_tasks.rake", __FILE__)
|
|
54
56
|
load File.expand_path("../../tasks/cache_tasks.rake", __FILE__)
|
|
55
57
|
end
|
|
56
|
-
|
|
57
58
|
end
|
|
58
59
|
end
|
|
@@ -143,15 +143,18 @@ module SvelteOnRails
|
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
def calling_view_dir
|
|
146
|
-
rails_views_path =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
rails_views_path = SvelteOnRails::ViewHelpers.rails_views_path
|
|
147
|
+
prefix_len = rails_views_path.length + 1
|
|
148
|
+
|
|
149
|
+
# Walk only a bounded slice of the stack; use loc.path (no string formatting).
|
|
150
|
+
loc = caller_locations(1, 60)&.find { |l| l.path&.start_with?(rails_views_path) }
|
|
151
|
+
return ''.freeze unless loc
|
|
152
|
+
|
|
153
|
+
File.dirname(loc.path[prefix_len..-1])
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.rails_views_path
|
|
157
|
+
@rails_views_path ||= Rails.root.join('app', 'views').to_s
|
|
155
158
|
end
|
|
156
159
|
|
|
157
160
|
end
|
|
@@ -48,7 +48,6 @@ ssr_error_tag: true
|
|
|
48
48
|
|
|
49
49
|
# redis_cache_store:
|
|
50
50
|
# url: 'redis://localhost:6379/2'
|
|
51
|
-
# expires_in: 90.minutes (=> default / fallback: 1 hour)
|
|
52
51
|
# namespace: 'my-app-svelte-on-rails'
|
|
53
52
|
|
|
54
53
|
|
|
@@ -56,6 +55,10 @@ use_caching: false
|
|
|
56
55
|
# this is the default for the #svelte view-helper.
|
|
57
56
|
# When set to true, the redis gem is required.
|
|
58
57
|
|
|
58
|
+
cache_expires_in: 3.days
|
|
59
|
+
# ttl for cache keys
|
|
60
|
+
# default: 3.days
|
|
61
|
+
|
|
59
62
|
debug: true
|
|
60
63
|
# provides deeper logging with timestamps for performance improvements
|
|
61
64
|
|
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: 22.
|
|
4
|
+
version: 22.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christian Sedlmair
|
|
@@ -84,6 +84,7 @@ files:
|
|
|
84
84
|
- lib/svelte_on_rails/installer/npm_sandbox.rb
|
|
85
85
|
- lib/svelte_on_rails/installer/svelte.rb
|
|
86
86
|
- lib/svelte_on_rails/installer/utils.rb
|
|
87
|
+
- lib/svelte_on_rails/lib/boot_context.rb
|
|
87
88
|
- lib/svelte_on_rails/lib/cache_warmer.rb
|
|
88
89
|
- lib/svelte_on_rails/lib/development_utils.rb
|
|
89
90
|
- lib/svelte_on_rails/lib/fallback_renderer.rb
|