react_on_rails_pro 16.4.0.rc.7 → 16.4.0.rc.9
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/CONTRIBUTING.md +2 -2
- data/Gemfile.lock +3 -3
- data/LICENSE_SETUP.md +10 -5
- data/README.md +16 -16
- data/lib/react_on_rails_pro/compression_middleware_guard.rb +164 -0
- data/lib/react_on_rails_pro/concerns/rsc_payload_renderer.rb +3 -1
- data/lib/react_on_rails_pro/engine.rb +8 -54
- data/lib/react_on_rails_pro/version.rb +1 -1
- data/lib/react_on_rails_pro.rb +1 -0
- metadata +5 -35
- data/docs/bundle-caching.md +0 -219
- data/docs/caching.md +0 -246
- data/docs/code-splitting-loadable-components.md +0 -326
- data/docs/configuration.md +0 -165
- data/docs/home-pro.md +0 -164
- data/docs/installation.md +0 -328
- data/docs/js-memory-leaks.md +0 -21
- data/docs/node-renderer/basics.md +0 -94
- data/docs/node-renderer/debugging.md +0 -42
- data/docs/node-renderer/error-reporting-and-tracing.md +0 -172
- data/docs/node-renderer/heroku.md +0 -101
- data/docs/node-renderer/js-configuration.md +0 -163
- data/docs/node-renderer/troubleshooting.md +0 -5
- data/docs/profiling-server-side-rendering-code.md +0 -180
- data/docs/react-server-components/add-streaming-and-interactivity.md +0 -190
- data/docs/react-server-components/create-without-ssr.md +0 -448
- data/docs/react-server-components/flight-protocol-syntax.md +0 -294
- data/docs/react-server-components/glossary.md +0 -131
- data/docs/react-server-components/how-react-server-components-work.md +0 -250
- data/docs/react-server-components/inside-client-components.md +0 -333
- data/docs/react-server-components/purpose-and-benefits.md +0 -253
- data/docs/react-server-components/rendering-flow.md +0 -90
- data/docs/react-server-components/selective-hydration-in-streamed-components.md +0 -75
- data/docs/react-server-components/server-side-rendering.md +0 -73
- data/docs/react-server-components/tutorial.md +0 -19
- data/docs/release-notes/4.0.md +0 -103
- data/docs/release-notes/v4-react-server-components.md +0 -66
- data/docs/ruby-api.md +0 -9
- data/docs/streaming-server-rendering.md +0 -239
- data/docs/troubleshooting.md +0 -11
- data/docs/updating.md +0 -283
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c63303b689f4adb5d1be96c2415522aeb05fd210258535c2a8fe3421414870a9
|
|
4
|
+
data.tar.gz: d0e63c69ac3c6ca63021ed54fc6f8f1fa6c574f0a261e74d6d6b4b9970a05c8a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 920e935410da89b4bbd5951c70e1b4f528e7525bba8f2d27094fbe1ce0676ac17f1277a100d235d6d74186a3414765e40f471de7dd0b7bb7e4faa68d04c61426
|
|
7
|
+
data.tar.gz: a4d980d3b3bdb5ace4a9d18902dbfabb35c2c2c99a3c354e5cbc39bda05853500d466d34c748e612dea4e0f0886849ed255be92082274befbaabc971af6b327e
|
data/CONTRIBUTING.md
CHANGED
|
@@ -47,12 +47,12 @@ From [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/
|
|
|
47
47
|
## Doc Changes
|
|
48
48
|
|
|
49
49
|
When making doc changes, we want the change to work on both [the ShakaCode docs site](https://www.shakacode.com/react-on-rails-pro/docs/) and when browsing the GitHub repo.
|
|
50
|
-
The issue is that the
|
|
50
|
+
The issue is that the ShakaCode site is generated only from files in [`../docs/pro`](../docs/pro), so any references from them to non-doc files must use the full GitHub URL.
|
|
51
51
|
|
|
52
52
|
### Links to other docs:
|
|
53
53
|
|
|
54
54
|
- When making references to doc files, use a relative URL path like:
|
|
55
|
-
`[Installation
|
|
55
|
+
`[Installation Guide](../docs/pro/installation.md)`
|
|
56
56
|
|
|
57
57
|
- When making references to source code files, use a full url path like:
|
|
58
58
|
`[spec/dummy/config/initializers/react_on_rails.rb](https://github.com/shakacode/react_on_rails/tree/master/react_on_rails_pro/spec/dummy/config/initializers/react_on_rails.rb)`
|
data/Gemfile.lock
CHANGED
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.4.0.rc.
|
|
12
|
+
react_on_rails (16.4.0.rc.9)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,7 +20,7 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: .
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.4.0.rc.
|
|
23
|
+
react_on_rails_pro (16.4.0.rc.9)
|
|
24
24
|
addressable
|
|
25
25
|
async (>= 2.6)
|
|
26
26
|
connection_pool
|
|
@@ -29,7 +29,7 @@ PATH
|
|
|
29
29
|
httpx (~> 1.5)
|
|
30
30
|
jwt (~> 2.7)
|
|
31
31
|
rainbow
|
|
32
|
-
react_on_rails (= 16.4.0.rc.
|
|
32
|
+
react_on_rails (= 16.4.0.rc.9)
|
|
33
33
|
|
|
34
34
|
GEM
|
|
35
35
|
remote: https://rubygems.org/
|
data/LICENSE_SETUP.md
CHANGED
|
@@ -75,13 +75,16 @@ heroku config:set REACT_ON_RAILS_PRO_LICENSE="your_token"
|
|
|
75
75
|
Configure your license token via the `REACT_ON_RAILS_PRO_LICENSE` environment variable.
|
|
76
76
|
Never commit license tokens to version control.
|
|
77
77
|
|
|
78
|
-
## License Validation
|
|
78
|
+
## License Validation and Signals
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
License-related checks and signals occur at multiple points:
|
|
81
81
|
|
|
82
82
|
1. **Ruby Gem**: When Rails application starts
|
|
83
83
|
2. **Node Renderer**: When the Node renderer process starts
|
|
84
|
-
3. **Browser Package**:
|
|
84
|
+
3. **Browser Package**: Receives Pro-installed signal via `railsContext.rorPro` (not license-valid state)
|
|
85
|
+
|
|
86
|
+
The browser package does not perform independent license validation. A valid paid license is still required for
|
|
87
|
+
production deployments.
|
|
85
88
|
|
|
86
89
|
When no license is present, the application runs in **unlicensed mode**. This is fine for development, testing, and CI/CD. Production deployments should always have a valid paid license.
|
|
87
90
|
|
|
@@ -148,7 +151,7 @@ The task exits with code 0 on success and code 1 if the license is missing, inva
|
|
|
148
151
|
| Field | Type | Description |
|
|
149
152
|
| ---------------------- | --------------- | --------------------------------------------------- |
|
|
150
153
|
| `status` | string | `"valid"`, `"expired"`, `"invalid"`, or `"missing"` |
|
|
151
|
-
| `organization` | string or null | Organization name from the
|
|
154
|
+
| `organization` | string or null | Organization name from the JWT `org` claim |
|
|
152
155
|
| `plan` | string or null | License plan (`"paid"`, `"startup"`, etc.) |
|
|
153
156
|
| `expiration` | string or null | ISO 8601 expiration date |
|
|
154
157
|
| `attribution_required` | boolean | Whether attribution is required |
|
|
@@ -302,11 +305,13 @@ The license is a JWT (JSON Web Token) signed with RSA-256, containing:
|
|
|
302
305
|
"iat": 1234567890, // Issued at timestamp (REQUIRED)
|
|
303
306
|
"exp": 1234567890, // Expiration timestamp (REQUIRED)
|
|
304
307
|
"plan": "paid", // License plan (Optional — only "paid" is valid for production)
|
|
305
|
-
"
|
|
308
|
+
"org": "Your Company", // Organization name (Optional)
|
|
306
309
|
"iss": "api" // Issuer identifier (Optional, standard JWT claim)
|
|
307
310
|
}
|
|
308
311
|
```
|
|
309
312
|
|
|
313
|
+
> Note: The JWT claim is `org`. The verify task output uses the field name `organization` for readability.
|
|
314
|
+
|
|
310
315
|
### Security
|
|
311
316
|
|
|
312
317
|
- **Offline validation**: No internet connection required
|
data/README.md
CHANGED
|
@@ -156,7 +156,7 @@ end %>
|
|
|
156
156
|
- Automatic cache invalidation based on props
|
|
157
157
|
- Works with Rails fragment caching infrastructure
|
|
158
158
|
|
|
159
|
-
**📖 Learn more**: [docs/caching.md](
|
|
159
|
+
**📖 Learn more**: [docs/pro/caching.md](../docs/pro/caching.md)
|
|
160
160
|
|
|
161
161
|
### 2. Prerender Caching
|
|
162
162
|
|
|
@@ -175,7 +175,7 @@ end
|
|
|
175
175
|
- Caches across multiple requests
|
|
176
176
|
- Complements fragment caching for maximum performance
|
|
177
177
|
|
|
178
|
-
**📖 Learn more**: [docs/caching.md](
|
|
178
|
+
**📖 Learn more**: [docs/pro/caching.md](../docs/pro/caching.md)
|
|
179
179
|
|
|
180
180
|
### 3. React on Rails Pro Node Renderer
|
|
181
181
|
|
|
@@ -203,7 +203,7 @@ reactOnRailsProNodeRenderer({
|
|
|
203
203
|
});
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
-
**📖 Learn more**: [docs/node-renderer/basics.md](
|
|
206
|
+
**📖 Learn more**: [docs/pro/node-renderer/basics.md](../docs/pro/node-renderer/basics.md)
|
|
207
207
|
|
|
208
208
|
### 4. React Server Components (RSC)
|
|
209
209
|
|
|
@@ -236,7 +236,7 @@ Speed up webpack rebuilds by caching unchanged bundles.
|
|
|
236
236
|
- **Faster development**: Hot reload only what changed
|
|
237
237
|
- **Lower costs**: Reduce build server time
|
|
238
238
|
|
|
239
|
-
**📖 Learn more**: [docs/bundle-caching.md](
|
|
239
|
+
**📖 Learn more**: [docs/pro/bundle-caching.md](../docs/pro/bundle-caching.md)
|
|
240
240
|
|
|
241
241
|
### 6. Global State Management
|
|
242
242
|
|
|
@@ -249,7 +249,7 @@ ReactOnRailsPro.configure do |config|
|
|
|
249
249
|
end
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
**📖 Learn more**: [docs/configuration.md](
|
|
252
|
+
**📖 Learn more**: [docs/pro/configuration.md](../docs/pro/configuration.md)
|
|
253
253
|
|
|
254
254
|
---
|
|
255
255
|
|
|
@@ -326,9 +326,9 @@ rails console
|
|
|
326
326
|
|
|
327
327
|
### Next Steps
|
|
328
328
|
|
|
329
|
-
- **Enable caching**: See [docs/caching.md](
|
|
330
|
-
- **Set up Node Renderer**: See [docs/node-renderer/basics.md](
|
|
331
|
-
- **Optimize performance**: See [docs/configuration.md](
|
|
329
|
+
- **Enable caching**: See [docs/pro/caching.md](../docs/pro/caching.md)
|
|
330
|
+
- **Set up Node Renderer**: See [docs/pro/node-renderer/basics.md](../docs/pro/node-renderer/basics.md)
|
|
331
|
+
- **Optimize performance**: See [docs/pro/configuration.md](../docs/pro/configuration.md)
|
|
332
332
|
- **Set up for your team**: See [LICENSE_SETUP.md](./LICENSE_SETUP.md#team-setup)
|
|
333
333
|
|
|
334
334
|
---
|
|
@@ -337,20 +337,20 @@ rails console
|
|
|
337
337
|
|
|
338
338
|
### Installation & Setup
|
|
339
339
|
|
|
340
|
-
- **[Installation Guide](
|
|
340
|
+
- **[Installation Guide](../docs/pro/installation.md)** - Detailed installation instructions
|
|
341
341
|
- **[License Setup](./LICENSE_SETUP.md)** - Complete license configuration guide
|
|
342
|
-
- **[Configuration Reference](
|
|
342
|
+
- **[Configuration Reference](../docs/pro/configuration.md)** - All configuration options
|
|
343
343
|
|
|
344
344
|
### Features
|
|
345
345
|
|
|
346
|
-
- **[Caching Guide](
|
|
347
|
-
- **[Bundle Caching](
|
|
348
|
-
- **[Node Renderer Basics](
|
|
349
|
-
- **[Node Renderer Configuration](
|
|
346
|
+
- **[Caching Guide](../docs/pro/caching.md)** - Fragment and prerender caching
|
|
347
|
+
- **[Bundle Caching](../docs/pro/bundle-caching.md)** - Speed up webpack builds
|
|
348
|
+
- **[Node Renderer Basics](../docs/pro/node-renderer/basics.md)** - Standalone Node.js server
|
|
349
|
+
- **[Node Renderer Configuration](../docs/pro/node-renderer/js-configuration.md)** - JavaScript config
|
|
350
350
|
|
|
351
351
|
### API Reference
|
|
352
352
|
|
|
353
|
-
- **[Ruby API](
|
|
353
|
+
- **[Ruby API](../docs/pro/ruby-api.md)** - Helper methods and utilities
|
|
354
354
|
- **[CHANGELOG](./CHANGELOG.md)** - Version history and upgrade notes
|
|
355
355
|
|
|
356
356
|
### Upgrading
|
|
@@ -408,7 +408,7 @@ Check out these production applications using React on Rails Pro:
|
|
|
408
408
|
|
|
409
409
|
- **📧 Email Support**: [support@shakacode.com](mailto:support@shakacode.com)
|
|
410
410
|
- **💼 Sales & Licensing**: [justin@shakacode.com](mailto:justin@shakacode.com)
|
|
411
|
-
- **📖 Documentation**: [docs/](
|
|
411
|
+
- **📖 Documentation**: [docs/pro/](../docs/pro/)
|
|
412
412
|
- **🐛 Found a Bug?**: Email [support@shakacode.com](mailto:support@shakacode.com) (for Pro customers)
|
|
413
413
|
|
|
414
414
|
### Professional Services
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
require "timeout"
|
|
5
|
+
|
|
6
|
+
module ReactOnRailsPro
|
|
7
|
+
class CompressionMiddlewareGuard
|
|
8
|
+
COMPATIBILITY_GUIDE_PATH =
|
|
9
|
+
"https://www.shakacode.com/react-on-rails/docs/building-features/" \
|
|
10
|
+
"streaming-server-rendering/#compression-middleware-compatibility"
|
|
11
|
+
PROBLEMATIC_MIDDLEWARES = %w[Rack::Deflater Rack::Brotli].freeze
|
|
12
|
+
PROBE_TIMEOUT_SECONDS = 1
|
|
13
|
+
|
|
14
|
+
Finding = Struct.new(:middleware_name, :source_location, keyword_init: true)
|
|
15
|
+
|
|
16
|
+
def initialize(middlewares:, logger: nil)
|
|
17
|
+
@middlewares = normalize_middlewares(middlewares)
|
|
18
|
+
@logger = logger
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def findings
|
|
22
|
+
@findings ||= @middlewares.filter_map do |middleware|
|
|
23
|
+
next unless problematic_middleware?(middleware)
|
|
24
|
+
|
|
25
|
+
condition = middleware_condition(middleware)
|
|
26
|
+
next unless condition.respond_to?(:call)
|
|
27
|
+
next unless destructively_iterates_stream?(condition)
|
|
28
|
+
|
|
29
|
+
Finding.new(
|
|
30
|
+
middleware_name: middleware_name(middleware),
|
|
31
|
+
source_location: source_location_for(condition)
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def warning_messages(root:)
|
|
37
|
+
findings.map do |finding|
|
|
38
|
+
"[React on Rails Pro] #{finding.middleware_name} has a custom `:if` callback" \
|
|
39
|
+
"#{formatted_source_location(finding, root: root)} that calls `body.each`. " \
|
|
40
|
+
"This is incompatible with streaming SSR/RSC and can deadlock `ActionController::Live` responses. " \
|
|
41
|
+
"Remove the custom `:if`, or guard it with " \
|
|
42
|
+
"`return true unless body.respond_to?(:to_ary)` before iterating. " \
|
|
43
|
+
"See #{COMPATIBILITY_GUIDE_PATH}."
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def normalize_middlewares(middlewares)
|
|
50
|
+
if defined?(ActionDispatch::MiddlewareStack) && middlewares.is_a?(ActionDispatch::MiddlewareStack)
|
|
51
|
+
return middlewares.middlewares
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Array(middlewares)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def problematic_middleware?(middleware)
|
|
58
|
+
PROBLEMATIC_MIDDLEWARES.include?(middleware_name(middleware))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def middleware_name(middleware)
|
|
62
|
+
middleware.klass.respond_to?(:name) ? middleware.klass.name : middleware.klass.to_s
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def middleware_condition(middleware)
|
|
66
|
+
Array(middleware.args).filter_map do |arg|
|
|
67
|
+
next unless arg.is_a?(Hash)
|
|
68
|
+
|
|
69
|
+
arg[:if] || arg["if"]
|
|
70
|
+
end.first
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def destructively_iterates_stream?(condition)
|
|
74
|
+
probe = StreamingBodyProbe.new
|
|
75
|
+
|
|
76
|
+
Timeout.timeout(PROBE_TIMEOUT_SECONDS) do
|
|
77
|
+
condition.call(probe_env, 200, probe_headers, probe)
|
|
78
|
+
end
|
|
79
|
+
probe.iterated?
|
|
80
|
+
rescue StreamingBodyProbe::BodyIteratedError
|
|
81
|
+
true
|
|
82
|
+
rescue Timeout::Error => e
|
|
83
|
+
return true if probe.iterated?
|
|
84
|
+
|
|
85
|
+
log_probe_failure(condition, e, reason: "timed out after #{PROBE_TIMEOUT_SECONDS}s")
|
|
86
|
+
false
|
|
87
|
+
rescue StandardError => e
|
|
88
|
+
return true if probe.iterated?
|
|
89
|
+
|
|
90
|
+
log_probe_failure(condition, e)
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Minimal Rack env used to probe `:if` callbacks.
|
|
95
|
+
# Callbacks that depend on application-specific keys can still raise here;
|
|
96
|
+
# those probe failures are logged at debug level and treated as non-findings.
|
|
97
|
+
# Path-gated callbacks can bypass this probe and yield false negatives.
|
|
98
|
+
def probe_env
|
|
99
|
+
{
|
|
100
|
+
"CONTENT_TYPE" => "text/html; charset=utf-8",
|
|
101
|
+
"HTTP_ACCEPT" => "text/html",
|
|
102
|
+
"REQUEST_METHOD" => "GET",
|
|
103
|
+
"PATH_INFO" => "/__react_on_rails_pro_stream_probe__",
|
|
104
|
+
"HTTP_ACCEPT_ENCODING" => "br, gzip, identity",
|
|
105
|
+
"HTTP_HOST" => "example.test",
|
|
106
|
+
"SERVER_NAME" => "example.test",
|
|
107
|
+
"rack.url_scheme" => "https",
|
|
108
|
+
"rack.errors" => StringIO.new,
|
|
109
|
+
"rack.input" => StringIO.new
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def probe_headers
|
|
114
|
+
{
|
|
115
|
+
"Content-Type" => "text/html; charset=utf-8"
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def formatted_source_location(finding, root:)
|
|
120
|
+
return "" unless finding.source_location
|
|
121
|
+
|
|
122
|
+
path, line = finding.source_location
|
|
123
|
+
root_prefix = "#{root}/"
|
|
124
|
+
display_path = path.start_with?(root_prefix) ? path.delete_prefix(root_prefix) : path
|
|
125
|
+
|
|
126
|
+
" (#{display_path}:#{line})"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def source_location_for(condition)
|
|
130
|
+
condition.respond_to?(:source_location) ? condition.source_location : nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def log_probe_failure(condition, error, reason: nil)
|
|
134
|
+
return unless @logger.respond_to?(:debug)
|
|
135
|
+
|
|
136
|
+
identifier = source_location_for(condition)&.join(":") || condition.class.name || condition.inspect
|
|
137
|
+
backtrace_hint = error.backtrace&.first
|
|
138
|
+
|
|
139
|
+
@logger.debug do
|
|
140
|
+
message = "[React on Rails Pro] CompressionMiddlewareGuard could not probe `:if` callback " \
|
|
141
|
+
"(#{identifier}): "
|
|
142
|
+
message += "#{reason}: " if reason
|
|
143
|
+
message += "#{error.class}: #{error.message}"
|
|
144
|
+
message += " (#{backtrace_hint})" if backtrace_hint
|
|
145
|
+
message
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class StreamingBodyProbe
|
|
150
|
+
include Enumerable
|
|
151
|
+
|
|
152
|
+
class BodyIteratedError < StandardError; end
|
|
153
|
+
|
|
154
|
+
def iterated?
|
|
155
|
+
@iterated == true
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def each
|
|
159
|
+
@iterated = true
|
|
160
|
+
raise BodyIteratedError, "Compression middleware `:if` callback called `body.each` on a streaming body."
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -27,7 +27,9 @@ module ReactOnRailsPro
|
|
|
27
27
|
"[React on Rails Pro] RSC payload templates are now rendered with format :text. " \
|
|
28
28
|
"If you override `custom_rsc_payload_template`, make sure the override resolves to " \
|
|
29
29
|
"a text or format-neutral template (for example `rsc_payload.text.erb`) instead of " \
|
|
30
|
-
"only `.html.erb`. See
|
|
30
|
+
"only `.html.erb`. See\n" \
|
|
31
|
+
"https://github.com/shakacode/react_on_rails/blob/master/docs/pro/updating.md " \
|
|
32
|
+
"for upgrade notes.\n\n" \
|
|
31
33
|
"Original error: #{e.message}"
|
|
32
34
|
)
|
|
33
35
|
end
|
|
@@ -7,10 +7,8 @@ module ReactOnRailsPro
|
|
|
7
7
|
LICENSE_URL = "https://www.shakacode.com/react-on-rails-pro/"
|
|
8
8
|
# TODO: Remove this legacy migration warning path after 16.5.0 stable release (target: 2026-05-31).
|
|
9
9
|
LEGACY_LICENSE_FILE = "config/react_on_rails_pro_license.key"
|
|
10
|
-
RSC_STREAMING_MIDDLEWARE_WARNING_TARGETS = ["Rack::Deflater"].freeze
|
|
11
10
|
private_constant :LICENSE_URL
|
|
12
11
|
private_constant :LEGACY_LICENSE_FILE
|
|
13
|
-
private_constant :RSC_STREAMING_MIDDLEWARE_WARNING_TARGETS
|
|
14
12
|
|
|
15
13
|
initializer "react_on_rails_pro.routes" do
|
|
16
14
|
ActionDispatch::Routing::Mapper.include ReactOnRailsPro::Routes
|
|
@@ -22,8 +20,8 @@ module ReactOnRailsPro
|
|
|
22
20
|
config.after_initialize { ReactOnRailsPro::Engine.log_license_status }
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
initializer "react_on_rails_pro.
|
|
26
|
-
config.after_initialize { ReactOnRailsPro::Engine.
|
|
23
|
+
initializer "react_on_rails_pro.warn_on_problematic_compression_middleware" do
|
|
24
|
+
config.after_initialize { ReactOnRailsPro::Engine.log_problematic_compression_middleware_warnings }
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
class << self
|
|
@@ -46,22 +44,12 @@ module ReactOnRailsPro
|
|
|
46
44
|
end
|
|
47
45
|
end
|
|
48
46
|
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return if problematic.empty?
|
|
56
|
-
|
|
57
|
-
route_path = ReactOnRailsPro.configuration.rsc_payload_generation_url_path
|
|
58
|
-
Rails.logger.warn(
|
|
59
|
-
"[React on Rails Pro] React Server Components support is enabled and the middleware " \
|
|
60
|
-
"stack includes #{problematic.join(', ')}. Compression and other response-transforming " \
|
|
61
|
-
"middleware can interfere with ActionController::Live NDJSON streaming. If your " \
|
|
62
|
-
"`#{route_path}` payload route is not already exempt, consider bypassing " \
|
|
63
|
-
"#{problematic.join(', ')} for that endpoint if you see stalled or corrupted RSC payloads."
|
|
64
|
-
)
|
|
47
|
+
def log_problematic_compression_middleware_warnings(logger: Rails.logger,
|
|
48
|
+
middlewares: Rails.application.middleware,
|
|
49
|
+
root: Rails.root)
|
|
50
|
+
CompressionMiddlewareGuard.new(middlewares: middlewares, logger: logger)
|
|
51
|
+
.warning_messages(root: root)
|
|
52
|
+
.each { |message| logger.warn(message) }
|
|
65
53
|
end
|
|
66
54
|
|
|
67
55
|
private
|
|
@@ -129,40 +117,6 @@ module ReactOnRailsPro
|
|
|
129
117
|
Rails.logger.info message
|
|
130
118
|
end
|
|
131
119
|
end
|
|
132
|
-
|
|
133
|
-
def middleware_stack_names
|
|
134
|
-
middleware_stack = Rails.application&.middleware
|
|
135
|
-
return [] unless middleware_stack
|
|
136
|
-
|
|
137
|
-
entries =
|
|
138
|
-
if middleware_stack.respond_to?(:middlewares)
|
|
139
|
-
middleware_stack.middlewares
|
|
140
|
-
elsif middleware_stack.respond_to?(:to_a)
|
|
141
|
-
middleware_stack.to_a
|
|
142
|
-
else
|
|
143
|
-
Array(middleware_stack)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
entries.filter_map { |entry| middleware_entry_name(entry) }.uniq
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def middleware_entry_name(entry)
|
|
150
|
-
candidate =
|
|
151
|
-
if entry.respond_to?(:klass) && entry.klass
|
|
152
|
-
entry.klass
|
|
153
|
-
elsif entry.is_a?(Array)
|
|
154
|
-
entry.first
|
|
155
|
-
else
|
|
156
|
-
entry
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
case candidate
|
|
160
|
-
when Module
|
|
161
|
-
candidate.name
|
|
162
|
-
else
|
|
163
|
-
candidate.to_s.presence
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
120
|
end
|
|
167
121
|
end
|
|
168
122
|
end
|
data/lib/react_on_rails_pro.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "react_on_rails"
|
|
|
6
6
|
require "react_on_rails_pro/request"
|
|
7
7
|
require "react_on_rails_pro/version"
|
|
8
8
|
require "react_on_rails_pro/constants"
|
|
9
|
+
require "react_on_rails_pro/compression_middleware_guard"
|
|
9
10
|
require "react_on_rails_pro/engine"
|
|
10
11
|
require "react_on_rails_pro/error"
|
|
11
12
|
require "react_on_rails_pro/utils"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: react_on_rails_pro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 16.4.0.rc.
|
|
4
|
+
version: 16.4.0.rc.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Gordon
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -128,14 +128,14 @@ dependencies:
|
|
|
128
128
|
requirements:
|
|
129
129
|
- - '='
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: 16.4.0.rc.
|
|
131
|
+
version: 16.4.0.rc.9
|
|
132
132
|
type: :runtime
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
136
|
- - '='
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: 16.4.0.rc.
|
|
138
|
+
version: 16.4.0.rc.9
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
140
|
name: bundler
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -225,42 +225,12 @@ files:
|
|
|
225
225
|
- app/helpers/react_on_rails_pro_helper.rb
|
|
226
226
|
- app/views/react_on_rails_pro/rsc_payload.text.erb
|
|
227
227
|
- babel.config.js
|
|
228
|
-
- docs/bundle-caching.md
|
|
229
|
-
- docs/caching.md
|
|
230
|
-
- docs/code-splitting-loadable-components.md
|
|
231
|
-
- docs/configuration.md
|
|
232
|
-
- docs/home-pro.md
|
|
233
|
-
- docs/installation.md
|
|
234
|
-
- docs/js-memory-leaks.md
|
|
235
|
-
- docs/node-renderer/basics.md
|
|
236
|
-
- docs/node-renderer/debugging.md
|
|
237
|
-
- docs/node-renderer/error-reporting-and-tracing.md
|
|
238
|
-
- docs/node-renderer/heroku.md
|
|
239
|
-
- docs/node-renderer/js-configuration.md
|
|
240
|
-
- docs/node-renderer/troubleshooting.md
|
|
241
|
-
- docs/profiling-server-side-rendering-code.md
|
|
242
|
-
- docs/react-server-components/add-streaming-and-interactivity.md
|
|
243
|
-
- docs/react-server-components/create-without-ssr.md
|
|
244
|
-
- docs/react-server-components/flight-protocol-syntax.md
|
|
245
|
-
- docs/react-server-components/glossary.md
|
|
246
|
-
- docs/react-server-components/how-react-server-components-work.md
|
|
247
|
-
- docs/react-server-components/inside-client-components.md
|
|
248
|
-
- docs/react-server-components/purpose-and-benefits.md
|
|
249
|
-
- docs/react-server-components/rendering-flow.md
|
|
250
|
-
- docs/react-server-components/selective-hydration-in-streamed-components.md
|
|
251
|
-
- docs/react-server-components/server-side-rendering.md
|
|
252
|
-
- docs/react-server-components/tutorial.md
|
|
253
|
-
- docs/release-notes/4.0.md
|
|
254
|
-
- docs/release-notes/v4-react-server-components.md
|
|
255
|
-
- docs/ruby-api.md
|
|
256
|
-
- docs/streaming-server-rendering.md
|
|
257
|
-
- docs/troubleshooting.md
|
|
258
|
-
- docs/updating.md
|
|
259
228
|
- eslint.config.mjs
|
|
260
229
|
- lib/react_on_rails_pro.rb
|
|
261
230
|
- lib/react_on_rails_pro/assets_precompile.rb
|
|
262
231
|
- lib/react_on_rails_pro/async_value.rb
|
|
263
232
|
- lib/react_on_rails_pro/cache.rb
|
|
233
|
+
- lib/react_on_rails_pro/compression_middleware_guard.rb
|
|
264
234
|
- lib/react_on_rails_pro/concerns/async_rendering.rb
|
|
265
235
|
- lib/react_on_rails_pro/concerns/rsc_payload_renderer.rb
|
|
266
236
|
- lib/react_on_rails_pro/concerns/stream.rb
|