react_on_rails_pro 16.2.0.beta.13 → 16.2.0.beta.16

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ea28d8199e9609b3233cd147a173c48936d4400fe618bd609c972bff2fe22a9
4
- data.tar.gz: ab4e291db072282321c49648c0ea4e247f1c69160e6d3bdade1c650ab221d057
3
+ metadata.gz: 3ebc6173ce60ead470a454c30308e09f0341130ed0af5a2e06e2c403005cffb6
4
+ data.tar.gz: 8482e11aaeb534457939143614cc969a52bb96fe7ac1db7ed435847bbdc6f716
5
5
  SHA512:
6
- metadata.gz: 86872a77f2b473f5e5e4c36aa7b0809e0e6f26907adfbe6e98b5701e0cfea85c826ab84de90d753c18a03c2b9812672ad9999d418a5abb34995ddaefd2c4b97e
7
- data.tar.gz: 5edffa8cafd674020d4e441b10bb90e2098f1074eadeb2555202e64af238babe8c6ca0d6b55e9ae6c9bda797e7106a28b286416c1b97b691ea28c063e9762126
6
+ metadata.gz: 5c1c2519d7d340ce8bb74619d8e11c4df8d546c58c5b8e9787ad77cb3a4ea80c0ff7c02f476427f72fbf1ea4f6d09d5fb7524ff55aae1621be7d6272c40386fd
7
+ data.tar.gz: 68c652b7250fb5a298c3bfaa8f258ab8bc88e9f71f1393311abedc17b1513714a14e02c4249d6176a9f2a25c49dd153c9f6a25913eea8d577ba471fe6aee3039
data/CHANGELOG.md CHANGED
@@ -17,7 +17,9 @@ You can find the **package** version numbers from this repo's tags and below in
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
- _Add changes in master not yet tagged._
20
+ ### [v16.2.0.beta.13] - 2025-12-07
21
+
22
+ Changes since the last non-beta release.
21
23
 
22
24
  ### Improved
23
25
 
@@ -48,8 +50,12 @@ _Add changes in master not yet tagged._
48
50
 
49
51
  ### Fixed
50
52
 
53
+ - **SECURITY: CVE-2025-55182 - React Server Components RCE Vulnerability**: by updating `react-on-rails-rsc` peer dependency to `v19.0.3` which mitigates that vulnerability. Also, users should update `react` and `react-dom` package versions to `v19.0.1` to ensure complete mitigation. [PR 2175](https://github.com/shakacode/react_on_rails/pull/2175) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
54
+
51
55
  - Fixed compatibility issue with httpx 1.6.x by explicitly requiring http-2 >= 1.1.1. [PR 2141](https://github.com/shakacode/react_on_rails/pull/2141) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
52
56
 
57
+ - **Client Disconnect Handling for Streaming**: Added error handling for client disconnects during streaming. When a client disconnects mid-stream (browser closed, network drop), the system now catches `IOError`/`Errno::EPIPE`, sets a `client_disconnected` flag, stops the barrier to cancel producer tasks, and logs the disconnect for debugging. Prevents wasted CPU from producers continuing after the writer fails. [PR 2137](https://github.com/shakacode/react_on_rails/pull/2137) by [justin808](https://github.com/justin808).
58
+
53
59
  - **Node Renderer Worker Restart**: Fixed "descriptor closed" error that occurred when the node renderer restarts while handling an in-progress request (especially streaming requests). Workers now perform graceful shutdowns: they disconnect from the cluster to stop receiving new requests, wait for active requests to complete, then shut down cleanly. A configurable `gracefulWorkerRestartTimeout` ensures workers are forcibly killed if they don't shut down in time. [PR 1970](https://github.com/shakacode/react_on_rails/pull/1970) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
54
60
 
55
61
  - **Body Duplication Bug On Streaming**: Fixed a bug that happens while streaming if the node renderer connection closed after streaming some chunks to the client. [PR 1995](https://github.com/shakacode/react_on_rails/pull/1995) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
@@ -536,7 +542,8 @@ Above changes in [PR 52](https://github.com/shakacode/react_on_rails_pro/pull/52
536
542
  - advanced error handling
537
543
 
538
544
  [HEAD compared to 3.2.1]: https://github.com/shakacode/react_on_rails_pro/compare/3.3.1...HEAD
539
- [Unreleased]: https://github.com/shakacode/react_on_rails_pro/compare/4.0.0-rc-15...HEAD
545
+ [Unreleased]: https://github.com/shakacode/react_on_rails/compare/v16.2.0.beta.13...master
546
+ [v16.2.0.beta.13]: https://github.com/shakacode/react_on_rails/compare/16.1.1...v16.2.0.beta.13
540
547
  [4.0.0-rc.15]: https://github.com/shakacode/react_on_rails_pro/compare/4.0.0-rc.14...4.0.0-rc.15
541
548
  [4.0.0.rc.11]: https://github.com/shakacode/react_on_rails_pro/compare/4.0.0-rc.9...4.0.0-rc.11
542
549
  [4.0.0.rc.9]: https://github.com/shakacode/react_on_rails_pro/compare/4.0.0-rc.6...4.0.0-rc.9
@@ -7,7 +7,7 @@ ruby '3.3.7'
7
7
 
8
8
  gem "react_on_rails", path: "../"
9
9
 
10
- gem "shakapacker", "9.3.0"
10
+ gem "shakapacker", "9.4.0"
11
11
  gem "bootsnap", require: false
12
12
  gem "rails", "~> 7.1"
13
13
  gem "puma", "~> 6"
data/Gemfile.lock CHANGED
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: ..
11
11
  specs:
12
- react_on_rails (16.2.0.beta.13)
12
+ react_on_rails (16.2.0.beta.16)
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.2.0.beta.13)
23
+ react_on_rails_pro (16.2.0.beta.16)
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.2.0.beta.13)
32
+ react_on_rails (= 16.2.0.beta.16)
33
33
 
34
34
  GEM
35
35
  remote: https://rubygems.org/
@@ -402,7 +402,7 @@ GEM
402
402
  websocket (~> 1.0)
403
403
  semantic_range (3.1.0)
404
404
  sexp_processor (4.17.1)
405
- shakapacker (9.3.0)
405
+ shakapacker (9.4.0)
406
406
  activesupport (>= 5.2)
407
407
  package_json
408
408
  rack-proxy (>= 0.6.1)
@@ -519,7 +519,7 @@ DEPENDENCIES
519
519
  sass-rails
520
520
  scss_lint
521
521
  selenium-webdriver (= 4.9.0)
522
- shakapacker (= 9.3.0)
522
+ shakapacker (= 9.4.0)
523
523
  spring
524
524
  spring-watcher-listen
525
525
  sprockets
@@ -1,12 +1,14 @@
1
1
  # Server-side rendering with code-splitting using Loadable/Components
2
+
2
3
  by ShakaCode
3
4
 
4
- *Last updated September 19, 2022*
5
+ _Last updated September 19, 2022_
5
6
 
6
7
  ## Introduction
8
+
7
9
  The [React library recommends](https://loadable-components.com/docs/getting-started/) the use of React.lazy for code splitting with dynamic imports except
8
10
  when using server-side rendering. In that case, as of February 2020, they recommend [Loadable Components](https://loadable-components.com)
9
- for server-side rendering with dynamic imports.
11
+ for server-side rendering with dynamic imports.
10
12
 
11
13
  Note, in 2019 and prior, the code-splitting feature was implemented using `react-loadable`. The React
12
14
  team no longer recommends that library. The new way is far preferable.
@@ -18,7 +20,8 @@ yarn add @loadable/babel-plugin @loadable/component @loadable/server @loadable/
18
20
  ```
19
21
 
20
22
  ### Summary
21
- - [`@loadable/babel-plugin`](https://loadable-components.com/docs/getting-started/) - The plugin transforms your code to be ready for Server Side Rendering.
23
+
24
+ - [`@loadable/babel-plugin`](https://loadable-components.com/docs/getting-started/) - The plugin transforms your code to be ready for Server Side Rendering.
22
25
  - `@loadable/component` - Main library for creating loadable components.
23
26
  - `@loadable/server` - Has functions for collecting chunks and provide style, script, link tags for the server.
24
27
  - `@loadable/webpack-plugin` - The plugin to create a stats file with all chunks, assets information.
@@ -35,15 +38,16 @@ See example of server configuration differences in the loadable-components [exam
35
38
  for server-side rendering](https://github.com/gregberge/loadable-components/blob/master/examples/server-side-rendering/webpack.config.babel.js)
36
39
 
37
40
  You need to configure 3 things:
38
- 1. `target`
39
- a. client-side: `web`
40
- b. server-side: `node`
41
+
42
+ 1. `target`
43
+ a. client-side: `web`
44
+ b. server-side: `node`
41
45
  2. `output.libraryTarget`
42
- a. client-side: `undefined`
43
- b. server-side: `commonjs2`
44
- 3. babel-loader options.caller = 'node' or 'web'
45
- 3. `plugins`
46
- a. server-side: `new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })`
46
+ a. client-side: `undefined`
47
+ b. server-side: `commonjs2`
48
+ 3. babel-loader options.caller = 'node' or 'web'
49
+ 4. `plugins`
50
+ a. server-side: `new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })`
47
51
 
48
52
  ```js
49
53
  {
@@ -58,14 +62,15 @@ You need to configure 3 things:
58
62
  Explanation:
59
63
 
60
64
  - `target: 'node'` is required to be able to run the server bundle with the dynamic import logic on nodejs.
61
- If that is not done, webpack will add and invoke browser-specific functions to fetch the chunks into the bundle, which throws an error on server-rendering.
65
+ If that is not done, webpack will add and invoke browser-specific functions to fetch the chunks into the bundle, which throws an error on server-rendering.
62
66
 
63
67
  - `new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })`
64
- The react_on_rails_pro node-renderer expects only one single server-bundle. In other words, we cannot and do not want to split the server bundle.
68
+ The react_on_rails_pro node-renderer expects only one single server-bundle. In other words, we cannot and do not want to split the server bundle.
65
69
 
66
70
  #### Client config
67
71
 
68
72
  For the client config we only need to add the plugin:
73
+
69
74
  ```js
70
75
  {
71
76
  plugins: [
@@ -74,30 +79,33 @@ For the client config we only need to add the plugin:
74
79
  ]
75
80
  }
76
81
  ```
82
+
77
83
  This plugin collects all the information about entrypoints, chunks, and files, that have these chunks and creates a stats file during client bundle build.
78
84
  This stats file is used later to map rendered components to file assets. While you can use any filename, our documentation will use the default name.
79
85
 
80
86
  ### Babel
81
87
 
82
88
  Per [the docs](https://loadable-components.com/docs/babel-plugin/#transformation):
89
+
83
90
  > The plugin transforms your code to be ready for Server Side Rendering
84
91
 
85
92
  Add this to `babel.config.js`:
93
+
86
94
  ```js
87
95
  {
88
96
  "plugins": ["@loadable/babel-plugin"]
89
97
  }
90
98
  ```
91
- https://loadable-components.com/docs/babel-plugin/
92
99
 
100
+ https://loadable-components.com/docs/babel-plugin/
93
101
 
94
102
  ### Convert components into loadable components
95
103
 
96
104
  Instead of importing the component directly, use a dynamic import:
97
105
 
98
106
  ```js
99
- import load from '@loadable/component'
100
- const MyComponent = load(() => import('./MyComponent'))
107
+ import load from '@loadable/component';
108
+ const MyComponent = load(() => import('./MyComponent'));
101
109
  ```
102
110
 
103
111
  ### Resolving issue with ChunkLoadError
@@ -118,22 +126,25 @@ const consoleDebug = (fn) => {
118
126
  console.debug(fn());
119
127
  }
120
128
  };
121
- const retry = (fn, retryMessage = '', retriesLeft = 3, interval = 500) => new Promise((resolve, reject) => {
122
- fn()
123
- .then(resolve)
124
- .catch(() => {
125
- setTimeout(() => {
126
- if (retriesLeft === 1) {
127
- console.warn(`Maximum retries exceeded, retryMessage: ${retryMessage}. Reloading page...`);
128
- window.location.reload();
129
- return;
130
- }
131
- // Passing on "reject" is the important part
132
- consoleDebug(() => `Trying request, retryMessage: ${retryMessage}, retriesLeft: ${retriesLeft - 1}`);
133
- retry(fn, retryMessage, retriesLeft - 1, interval).then(resolve, reject);
134
- }, interval);
135
- });
136
- });
129
+ const retry = (fn, retryMessage = '', retriesLeft = 3, interval = 500) =>
130
+ new Promise((resolve, reject) => {
131
+ fn()
132
+ .then(resolve)
133
+ .catch(() => {
134
+ setTimeout(() => {
135
+ if (retriesLeft === 1) {
136
+ console.warn(`Maximum retries exceeded, retryMessage: ${retryMessage}. Reloading page...`);
137
+ window.location.reload();
138
+ return;
139
+ }
140
+ // Passing on "reject" is the important part
141
+ consoleDebug(
142
+ () => `Trying request, retryMessage: ${retryMessage}, retriesLeft: ${retriesLeft - 1}`,
143
+ );
144
+ retry(fn, retryMessage, retriesLeft - 1, interval).then(resolve, reject);
145
+ }, interval);
146
+ });
147
+ });
137
148
  export default retry;
138
149
  ```
139
150
 
@@ -152,21 +163,21 @@ const HomePage = loadable(() => retry(() => import('./HomePage')));
152
163
 
153
164
  In the client bundle, we need to wrap the `hydrateRoot` call into a `loadableReady` function.
154
165
  So, hydration will be fired only after all necessary chunks preloads. In this example below,
155
- `ClientApp` is registering as `App`.
166
+ `ClientApp` is registering as `App`.
156
167
 
157
168
  ```js
158
169
  import React from 'react';
159
170
  import ReactOnRails from 'react-on-rails';
160
- import { hydrateRoot } from 'react-dom/client'
161
- import { loadableReady } from '@loadable/component'
171
+ import { hydrateRoot } from 'react-dom/client';
172
+ import { loadableReady } from '@loadable/component';
162
173
  import App from './App';
163
174
 
164
175
  const ClientApp = (props, railsContext, domId) => {
165
176
  loadableReady(() => {
166
- const root = document.getElementById(domId)
177
+ const root = document.getElementById(domId);
167
178
  hydrateRoot(root, <App {...props} />);
168
- })
169
- }
179
+ });
180
+ };
170
181
 
171
182
  ReactOnRails.register({
172
183
  App: ClientApp,
@@ -175,20 +186,20 @@ ReactOnRails.register({
175
186
 
176
187
  #### Server
177
188
 
178
- The purpose of the server function is to collect all rendered chunks and pass them as script, link,
179
- style tags to the Rails view. In this example below, `ServerApp` is registering as `App`.
189
+ The purpose of the server function is to collect all rendered chunks and pass them as script, link,
190
+ style tags to the Rails view. In this example below, `ServerApp` is registering as `App`.
180
191
 
181
192
  ```js
182
193
  import React from 'react';
183
194
  import ReactOnRails from 'react-on-rails';
184
- import { ChunkExtractor } from '@loadable/server'
185
- import App from './App'
186
- import path from 'path'
195
+ import { ChunkExtractor } from '@loadable/server';
196
+ import App from './App';
197
+ import path from 'path';
187
198
 
188
199
  const ServerApp = (props, railsContext) => {
189
200
  // This loadable-stats file was generated by `LoadablePlugin` in client webpack config.
190
201
  // You must configure the path to resolve per your setup. If you are copying the file to
191
- // a remote server, the file should be a sibling of this file.
202
+ // a remote server, the file should be a sibling of this file.
192
203
  // __dirname is going to be the directory where the server-bundle.js exists
193
204
  // Note, React on Rails Pro automatically copies the loadable-stats.json to the same place as the
194
205
  // server-bundle.js. Thus, the __dirname of this code is where we can find loadable-stats.json.
@@ -198,10 +209,10 @@ const ServerApp = (props, railsContext) => {
198
209
  // This object is used to search filenames by corresponding chunk names.
199
210
  // See https://loadable-components.com/docs/api-loadable-server/#chunkextractor
200
211
  // for the entryPoints, pass an array of all your entryPoints using dynamic imports
201
- const extractor = new ChunkExtractor({ statsFile, entrypoints: ['client-bundle'] })
212
+ const extractor = new ChunkExtractor({ statsFile, entrypoints: ['client-bundle'] });
202
213
 
203
214
  // It creates the wrapper `ChunkExtractorManager` around `App` to collect chunk names of rendered components.
204
- const jsx = extractor.collectChunks(<App {...props} railsContext={railsContext} />)
215
+ const jsx = extractor.collectChunks(<App {...props} railsContext={railsContext} />);
205
216
 
206
217
  const componentHtml = renderToString(jsx);
207
218
 
@@ -211,8 +222,8 @@ const ServerApp = (props, railsContext) => {
211
222
  // Returns all the files with rendered chunks for furture insert into rails view.
212
223
  linkTags: extractor.getLinkTags(),
213
224
  styleTags: extractor.getStyleTags(),
214
- scriptTags: extractor.getScriptTags()
215
- }
225
+ scriptTags: extractor.getScriptTags(),
226
+ },
216
227
  };
217
228
  };
218
229
 
@@ -224,6 +235,7 @@ ReactOnRails.register({
224
235
  ## Configure react_on_rails_pro
225
236
 
226
237
  ### React on Rails Pro
238
+
227
239
  You must set `config.assets_top_copy` so that the node-renderer will have access to the loadable-stats.json.
228
240
 
229
241
  ```ruby
@@ -233,15 +245,16 @@ You must set `config.assets_top_copy` so that the node-renderer will have access
233
245
  Your server rendering code, per the above, will find this file like this:
234
246
 
235
247
  ```js
236
- const statsFile = path.resolve(__dirname, 'loadable-stats.json');
237
- ```
248
+ const statsFile = path.resolve(__dirname, 'loadable-stats.json');
249
+ ```
238
250
 
239
251
  Note, if `__dirname` is not working in your webpack build, that's because you didn't set `node: false`
240
252
  in your webpack configuration. That turns off the polyfills for things like `__dirname`.
241
253
 
242
-
243
254
  ### Node Renderer
255
+
244
256
  In your `node-renderer.js` file which runs node renderer, you need to specify `supportModules` options as follows:
257
+
245
258
  ```js
246
259
  const path = require('path');
247
260
  const env = process.env;
@@ -261,7 +274,7 @@ reactOnRailsProNodeRenderer(config);
261
274
  ```erb
262
275
  <% res = react_component_hash("App", props: {}, prerender: true) %>
263
276
  <%= content_for :link_tags, res['linkTags'] %>
264
- <%= content_for :style_tags, res['styleTags'] %>
277
+ <%= content_for :style_tags, res['styleTags'] %>
265
278
 
266
279
  <%= res['componentHtml'].html_safe %>
267
280
 
@@ -269,6 +282,7 @@ reactOnRailsProNodeRenderer(config);
269
282
  ```
270
283
 
271
284
  ## Making HMR Work
285
+
272
286
  To make HMR work, it's best to disable loadable-components when using the Dev Server.
273
287
  Note: you will need access to our **private** React on Rails Pro repository to open the following links.
274
288
 
@@ -277,9 +291,11 @@ Take a look at the code searches for ['imports-loadable'](https://github.com/sha
277
291
  The general concept is that we have a non-loadable, HMR-ready, file that substitutes for the loadable-enabled one, with the suffixes `imports-hmr.js` instead of `imports-loadable.js`
278
292
 
279
293
  ### Webpack configuration
294
+
280
295
  Use the [NormalModuleReplacement plugin](https://webpack.js.org/plugins/normal-module-replacement-plugin/):
281
296
 
282
297
  [code](https://github.com/shakacode/react_on_rails_pro/blob/a361f4e163b9170f180ae07ee312fb9b4c719fc3/spec/dummy/config/webpack/environment.js#L81-L91)
298
+
283
299
  ```js
284
300
  if (isWebpackDevServer) {
285
301
  environment.plugins.append(
@@ -305,7 +321,7 @@ Note: you will need access to our **private** React on Rails Pro repository to o
305
321
  ### Client-Side Startup
306
322
 
307
323
  - [spec/dummy/client/app/loadable/loadable-client.imports-hmr.js](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-client.imports-hmr.js)
308
- - [spec/dummy/client/app/loadable/loadable-client.imports-loadable.js](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-client.imports-loadable.js)
324
+ - [spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx)
309
325
 
310
326
  ### Server-Side Startup
311
327
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRailsPro
4
- VERSION = "16.2.0.beta.13"
4
+ VERSION = "16.2.0.beta.16"
5
5
  PROTOCOL_VERSION = "2.0.0"
6
6
  end
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.2.0.beta.13
4
+ version: 16.2.0.beta.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-07 00:00:00.000000000 Z
11
+ date: 2025-12-10 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.2.0.beta.13
131
+ version: 16.2.0.beta.16
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.2.0.beta.13
138
+ version: 16.2.0.beta.16
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: bundler
141
141
  requirement: !ruby/object:Gem::Requirement