inertia_rails 3.20.0 → 3.21.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/CHANGELOG.md +12 -0
- data/lib/generators/inertia/install/install_generator.rb +10 -7
- data/lib/inertia_rails/cached_prop.rb +11 -0
- data/lib/inertia_rails/configuration.rb +8 -0
- data/lib/inertia_rails/controller.rb +8 -0
- data/lib/inertia_rails/defer_prop.rb +1 -0
- data/lib/inertia_rails/engine.rb +8 -0
- data/lib/inertia_rails/middleware.rb +5 -1
- data/lib/inertia_rails/optional_prop.rb +1 -0
- data/lib/inertia_rails/prop_cacheable.rb +39 -0
- data/lib/inertia_rails/props_resolver.rb +2 -0
- data/lib/inertia_rails/raw_json.rb +23 -0
- data/lib/inertia_rails/renderer.rb +2 -1
- data/lib/inertia_rails/ssr_renderer.rb +1 -1
- data/lib/inertia_rails/version.rb +1 -1
- data/lib/inertia_rails.rb +11 -0
- data/lib/puma/plugin/inertia_ssr.rb +9 -6
- 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: 8e115fc23929dd31823522f220656a19369a8f5532215bf2c36a2f01e038ca20
|
|
4
|
+
data.tar.gz: 81bf7c11c9fb32be96de1d70e212894057bbb16c49ce87c76ea17071fe9635e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80d695972717a9ad929c580bffb339102b19cb0890b1f235d3b2076b0b8094d7d8f5ce67de1d9b18ebe440dc03982be37371d522d7168fb8be447fa3e7b15fe0
|
|
7
|
+
data.tar.gz: dac3f813eecdc130f9b2081f084122c9783cb3d74793847c8f2ca1f9c95d080159594ccf1e015f05c4b1848faccd53fa069c4f97694614fb5ea96ac7b54765b2
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [3.21.0] - 2026-04-14
|
|
10
|
+
|
|
11
|
+
* Skip excluded hash props on partial reloads (@erickreutz)
|
|
12
|
+
* Fix Vite plugin insertion order in install generator (@onk)
|
|
13
|
+
* Fix typo in `inertia()` plugin configuration example in docs (@onk)
|
|
14
|
+
* Better SSR Puma plugin lookup defaults (@skryukov)
|
|
15
|
+
* Add prop-level caching and caching documentation (@skryukov)
|
|
16
|
+
* Skip session cleanup in middleware when session was never loaded (@khamusa)
|
|
17
|
+
* Support `layout` option in `render inertia:` calls (@skryukov)
|
|
18
|
+
|
|
7
19
|
## [3.20.0] - 2026-04-04
|
|
8
20
|
|
|
9
21
|
* Fix partial reload filtering with arrays
|
|
@@ -87,18 +87,21 @@ module Inertia
|
|
|
87
87
|
say 'Installing Inertia npm packages'
|
|
88
88
|
add_dependencies(inertia_package, *FRAMEWORKS[framework]['packages'])
|
|
89
89
|
|
|
90
|
-
unless File.read(vite_config_path).include?(FRAMEWORKS[framework]['vite_plugin_import'])
|
|
91
|
-
say "Adding Vite plugin for #{framework}"
|
|
92
|
-
insert_into_file vite_config_path, "\n #{FRAMEWORKS[framework]['vite_plugin_call']},", after: 'plugins: ['
|
|
93
|
-
prepend_file vite_config_path, "#{FRAMEWORKS[framework]['vite_plugin_import']}\n"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
90
|
unless File.read(vite_config_path).include?('@inertiajs/vite')
|
|
97
91
|
say 'Adding Inertia Vite plugin'
|
|
98
|
-
|
|
92
|
+
# Append to the end of the plugins array.
|
|
93
|
+
gsub_file vite_config_path, /(plugins: \[.*?)(\n\s*\])/m, "\\1\n inertia(),\\2"
|
|
99
94
|
prepend_file vite_config_path, "import inertia from '@inertiajs/vite'\n"
|
|
100
95
|
end
|
|
101
96
|
|
|
97
|
+
unless File.read(vite_config_path).include?(FRAMEWORKS[framework]['vite_plugin_import'])
|
|
98
|
+
say "Adding Vite plugin for #{framework}"
|
|
99
|
+
# Append to the end of the plugins array.
|
|
100
|
+
gsub_file vite_config_path, /(plugins: \[.*?)(\n\s*\])/m,
|
|
101
|
+
"\\1\n #{FRAMEWORKS[framework]['vite_plugin_call']},\\2"
|
|
102
|
+
prepend_file vite_config_path, "#{FRAMEWORKS[framework]['vite_plugin_import']}\n"
|
|
103
|
+
end
|
|
104
|
+
|
|
102
105
|
say "Copying #{inertia_entrypoint} entrypoint"
|
|
103
106
|
copy_file "#{framework}/#{inertia_entrypoint}", js_file_path("entrypoints/#{inertia_entrypoint}")
|
|
104
107
|
|
|
@@ -71,6 +71,10 @@ module InertiaRails
|
|
|
71
71
|
|
|
72
72
|
# Whether to include shared prop keys in the page response metadata.
|
|
73
73
|
expose_shared_prop_keys: true,
|
|
74
|
+
|
|
75
|
+
# Cache store for prop-level caching and SSR response caching.
|
|
76
|
+
# Defaults to Rails.cache when nil.
|
|
77
|
+
cache_store: nil,
|
|
74
78
|
}.freeze
|
|
75
79
|
|
|
76
80
|
OPTION_NAMES = DEFAULTS.keys.freeze
|
|
@@ -141,6 +145,10 @@ module InertiaRails
|
|
|
141
145
|
@options[:on_ssr_error]
|
|
142
146
|
end
|
|
143
147
|
|
|
148
|
+
def cache_store
|
|
149
|
+
@options[:cache_store] || Rails.cache
|
|
150
|
+
end
|
|
151
|
+
|
|
144
152
|
OPTION_NAMES.each do |option|
|
|
145
153
|
unless method_defined?(option)
|
|
146
154
|
define_method(option) do
|
|
@@ -112,6 +112,14 @@ module InertiaRails
|
|
|
112
112
|
view_assigns.except(*@_inertia_skip_props)
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
# Rails < 8: _normalize_options overwrites :layout with a resolved default,
|
|
116
|
+
# making an explicit `layout: false` indistinguishable from "not provided".
|
|
117
|
+
# Stash the original value so the renderer can tell the two apart.
|
|
118
|
+
def _normalize_options(options)
|
|
119
|
+
options[:_inertia_layout] = options[:layout] if options.key?(:inertia) && options.key?(:layout)
|
|
120
|
+
super
|
|
121
|
+
end
|
|
122
|
+
|
|
115
123
|
def inertia_configuration
|
|
116
124
|
self.class._inertia_configuration.bind_controller(self)
|
|
117
125
|
end
|
data/lib/inertia_rails/engine.rb
CHANGED
|
@@ -15,6 +15,14 @@ module InertiaRails
|
|
|
15
15
|
initializer 'inertia_rails.renderer' do
|
|
16
16
|
ActiveSupport.on_load(:action_controller) do
|
|
17
17
|
ActionController::Renderers.add :inertia do |component, options|
|
|
18
|
+
# See Controller#_normalize_options — restore the user's original
|
|
19
|
+
# :layout or discard the Rails-injected default.
|
|
20
|
+
if options.key?(:_inertia_layout)
|
|
21
|
+
options[:layout] = options.delete(:_inertia_layout)
|
|
22
|
+
else
|
|
23
|
+
options.delete(:layout)
|
|
24
|
+
end
|
|
25
|
+
|
|
18
26
|
InertiaRails::Renderer.new(
|
|
19
27
|
component,
|
|
20
28
|
self,
|
|
@@ -26,7 +26,11 @@ module InertiaRails
|
|
|
26
26
|
request = ActionDispatch::Request.new(@env)
|
|
27
27
|
|
|
28
28
|
# Inertia session data is added via redirect_to
|
|
29
|
-
|
|
29
|
+
# Guard with session.loaded? to avoid forcing session I/O (and unnecessary
|
|
30
|
+
# database writes) on requests that never accessed the session, e.g. sessionless
|
|
31
|
+
# controllers. If the session was never loaded the Inertia keys cannot have been
|
|
32
|
+
# set, so the cleanup would be a no-op anyway.
|
|
33
|
+
unless keep_inertia_session_options?(status) || !request.session.loaded?
|
|
30
34
|
request.session.delete(:inertia_errors)
|
|
31
35
|
request.session.delete(:inertia_clear_history)
|
|
32
36
|
request.session.delete(:inertia_preserve_fragment)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
module PropCacheable
|
|
5
|
+
def initialize(**props, &block)
|
|
6
|
+
cache_arg = props.delete(:cache)
|
|
7
|
+
|
|
8
|
+
if cache_arg.is_a?(Hash)
|
|
9
|
+
raise ArgumentError, 'cache: hash requires a :key' unless cache_arg.key?(:key)
|
|
10
|
+
|
|
11
|
+
@cache_key = derive_cache_key(cache_arg.delete(:key))
|
|
12
|
+
@cache_options = cache_arg.freeze
|
|
13
|
+
elsif cache_arg
|
|
14
|
+
@cache_key = derive_cache_key(cache_arg)
|
|
15
|
+
@cache_options = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cached?
|
|
22
|
+
!@cache_key.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(controller, **context)
|
|
26
|
+
return super unless cached?
|
|
27
|
+
|
|
28
|
+
json = InertiaRails.cache_store.fetch(@cache_key, **(@cache_options || {})) { super.to_json }
|
|
29
|
+
RawJson.new(json)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def derive_cache_key(raw_key)
|
|
35
|
+
expanded = ActiveSupport::Cache.expand_cache_key(raw_key)
|
|
36
|
+
"inertia_rails/#{expanded}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -82,6 +82,8 @@ module InertiaRails
|
|
|
82
82
|
prop = prop.to_inertia if prop.respond_to?(:to_inertia)
|
|
83
83
|
|
|
84
84
|
if prop.is_a?(Hash) && prop.any?
|
|
85
|
+
next if !parent_was_resolved && excluded_by_partial_request?(path)
|
|
86
|
+
|
|
85
87
|
nested = deep_transform_props(prop, path, parent_was_resolved: parent_was_resolved)
|
|
86
88
|
transformed_props[key] = nested unless nested.empty?
|
|
87
89
|
next
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
# Wraps a pre-serialized JSON string so it embeds directly
|
|
5
|
+
# into a larger JSON structure without re-serialization.
|
|
6
|
+
#
|
|
7
|
+
# - JSON.generate calls #to_json, embedding the raw string.
|
|
8
|
+
# - ActiveSupport::JSON.encode calls #as_json first, which
|
|
9
|
+
# returns parsed Ruby data that the encoder re-serializes.
|
|
10
|
+
class RawJson
|
|
11
|
+
def initialize(json_string)
|
|
12
|
+
@json_string = json_string
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_json(*)
|
|
16
|
+
@json_string
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def as_json(*)
|
|
20
|
+
JSON.parse(@json_string)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -27,6 +27,7 @@ module InertiaRails
|
|
|
27
27
|
@encrypt_history = options.fetch(:encrypt_history, @configuration.encrypt_history)
|
|
28
28
|
@clear_history = options.fetch(:clear_history, controller.session[:inertia_clear_history] || false)
|
|
29
29
|
@preserve_fragment = options.fetch(:preserve_fragment, controller.session[:inertia_preserve_fragment] || false)
|
|
30
|
+
@layout_override = options.fetch(:layout) { @configuration.layout }
|
|
30
31
|
@ssr_cache = options[:ssr_cache]
|
|
31
32
|
|
|
32
33
|
deep_merge = options.fetch(:deep_merge, @configuration.deep_merge_shared_data)
|
|
@@ -70,7 +71,7 @@ module InertiaRails
|
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
def layout
|
|
73
|
-
layout = @
|
|
74
|
+
layout = @layout_override
|
|
74
75
|
layout.nil? || layout
|
|
75
76
|
end
|
|
76
77
|
|
data/lib/inertia_rails.rb
CHANGED
|
@@ -12,6 +12,8 @@ require_relative 'inertia_rails/current'
|
|
|
12
12
|
require_relative 'inertia_rails/errors'
|
|
13
13
|
|
|
14
14
|
# props
|
|
15
|
+
require_relative 'inertia_rails/raw_json'
|
|
16
|
+
require_relative 'inertia_rails/prop_cacheable'
|
|
15
17
|
require_relative 'inertia_rails/prop_onceable'
|
|
16
18
|
require_relative 'inertia_rails/prop_mergeable'
|
|
17
19
|
require_relative 'inertia_rails/base_prop'
|
|
@@ -19,6 +21,7 @@ require_relative 'inertia_rails/ignore_on_first_load_prop'
|
|
|
19
21
|
require_relative 'inertia_rails/always_prop'
|
|
20
22
|
require_relative 'inertia_rails/lazy_prop'
|
|
21
23
|
require_relative 'inertia_rails/optional_prop'
|
|
24
|
+
require_relative 'inertia_rails/cached_prop'
|
|
22
25
|
require_relative 'inertia_rails/defer_prop'
|
|
23
26
|
require_relative 'inertia_rails/merge_prop'
|
|
24
27
|
require_relative 'inertia_rails/once_prop'
|
|
@@ -54,6 +57,10 @@ module InertiaRails
|
|
|
54
57
|
@configuration ||= Configuration.default
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
def cache_store
|
|
61
|
+
configuration.cache_store
|
|
62
|
+
end
|
|
63
|
+
|
|
57
64
|
def deprecator # :nodoc:
|
|
58
65
|
@deprecator ||= ActiveSupport::Deprecation.new
|
|
59
66
|
end
|
|
@@ -82,6 +89,10 @@ module InertiaRails
|
|
|
82
89
|
MergeProp.new(deep_merge: true, match_on: match_on, &block)
|
|
83
90
|
end
|
|
84
91
|
|
|
92
|
+
def cache(...)
|
|
93
|
+
CachedProp.new(...)
|
|
94
|
+
end
|
|
95
|
+
|
|
85
96
|
def defer(...)
|
|
86
97
|
DeferProp.new(...)
|
|
87
98
|
end
|
|
@@ -138,14 +138,17 @@ Puma::Plugin.create do
|
|
|
138
138
|
|
|
139
139
|
return Array(config.ssr_bundle).find { |path| File.exist?(path) } if config.ssr_bundle
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return candidates.first if candidates&.any?
|
|
141
|
+
patterns = %w[ssr/*.js public/assets-ssr/*.js]
|
|
142
|
+
if defined?(ViteRuby) && (ssr_dir = ViteRuby.config.ssr_output_dir)
|
|
143
|
+
patterns.prepend(File.join(ssr_dir, '*.js'))
|
|
145
144
|
end
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
patterns.each do |pattern|
|
|
147
|
+
candidates = Dir.glob(pattern)
|
|
148
|
+
return candidates.first if candidates.any?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
nil
|
|
149
152
|
end
|
|
150
153
|
|
|
151
154
|
def resolve_base_url
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inertia_rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.21.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Knoles
|
|
@@ -184,6 +184,7 @@ files:
|
|
|
184
184
|
- lib/inertia_rails.rb
|
|
185
185
|
- lib/inertia_rails/always_prop.rb
|
|
186
186
|
- lib/inertia_rails/base_prop.rb
|
|
187
|
+
- lib/inertia_rails/cached_prop.rb
|
|
187
188
|
- lib/inertia_rails/configuration.rb
|
|
188
189
|
- lib/inertia_rails/controller.rb
|
|
189
190
|
- lib/inertia_rails/current.rb
|
|
@@ -209,10 +210,12 @@ files:
|
|
|
209
210
|
- lib/inertia_rails/once_prop.rb
|
|
210
211
|
- lib/inertia_rails/optional_prop.rb
|
|
211
212
|
- lib/inertia_rails/precognition.rb
|
|
213
|
+
- lib/inertia_rails/prop_cacheable.rb
|
|
212
214
|
- lib/inertia_rails/prop_evaluator.rb
|
|
213
215
|
- lib/inertia_rails/prop_mergeable.rb
|
|
214
216
|
- lib/inertia_rails/prop_onceable.rb
|
|
215
217
|
- lib/inertia_rails/props_resolver.rb
|
|
218
|
+
- lib/inertia_rails/raw_json.rb
|
|
216
219
|
- lib/inertia_rails/renderer.rb
|
|
217
220
|
- lib/inertia_rails/rspec.rb
|
|
218
221
|
- lib/inertia_rails/rspec/deprecated.rb
|