|
1 | 1 | # React on Rails 15.0.0 Release Notes |
2 | 2 |
|
3 | | -Also see the [Changelog for 15.0.0](https://github.com/shakacode/react_on_rails/blob/master/CHANGELOG.md#1500---2025-08-28). |
| 3 | +**⚠️ Version 15.0.0 has been retracted. Please upgrade directly to v16.0.0.** |
4 | 4 |
|
5 | | -## Major Features |
6 | | - |
7 | | -### 🚀 React Server Components Support |
8 | | - |
9 | | -Experience the future of React with full RSC integration in your Rails apps: |
10 | | - |
11 | | -- Seamlessly use React Server Components |
12 | | -- Reduce client bundle sizes |
13 | | -- Enable powerful new patterns for data fetching |
14 | | -- ⚡️ Requires React on Rails Pro - [See the full tutorial](https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/tutorial/) |
15 | | - |
16 | | -### 🚀 Major Performance Breakthrough: Early Hydration |
17 | | - |
18 | | -**React on Rails now starts hydration even before the full page is loaded!** This revolutionary change delivers significant performance improvements across all pages: |
19 | | - |
20 | | -- **Eliminates Race Conditions**: No more waiting for full page load before hydration begins |
21 | | -- **Faster Time-to-Interactive**: Components hydrate as soon as their server-rendered HTML reaches the client |
22 | | -- **Streaming HTML Optimization**: Perfect for modern streaming responses - components hydrate in parallel with page streaming |
23 | | -- **Async Script Safety**: Can use `async` scripts without fear of race conditions |
24 | | -- **No More Defer Needed**: The previous need for `defer` to prevent race conditions has been eliminated |
25 | | - |
26 | | -This optimization is particularly impactful for: |
27 | | - |
28 | | -- **Streamed pages** where content loads progressively |
29 | | -- **Large pages** with many components |
30 | | -- **Slow network conditions** where every millisecond counts |
31 | | -- **Modern web apps** requiring fast interactivity |
32 | | - |
33 | | -_Performance improvement visualization:_ |
34 | | - |
35 | | - |
36 | | - |
37 | | -_The image above demonstrates the dramatic performance improvement:_ |
38 | | - |
39 | | -- **Left (Before)**: Hydration didn't start until the full page load completed, causing a huge delay before hydration |
40 | | -- **Right (After)**: Hydration starts immediately as soon as components are available, without waiting for full page load |
41 | | -- **Result**: Components now become interactive much faster, eliminating the previous race condition delays |
42 | | - |
43 | | -### Enhanced Script Loading Strategies |
44 | | - |
45 | | -- New configuration option `generated_component_packs_loading_strategy` replaces `defer_generated_component_packs` |
46 | | -- Supports three loading strategies: |
47 | | - - `:async` - Loads scripts asynchronously (default for Shakapacker ≥ 8.2.0) |
48 | | - - `:defer` - Defers script execution until after page load (doesn't work well with Streamed HTML as it will wait for the full page load before hydrating the components) |
49 | | - - `:sync` - Loads scripts synchronously (default for Shakapacker < 8.2.0) (better to upgrade to Shakapacker 8.2.0 and use `:async` strategy) |
50 | | -- Improves page performance by optimizing how component packs are loaded |
51 | | - |
52 | | -## Breaking Changes |
53 | | - |
54 | | -### Component Hydration Changes |
55 | | - |
56 | | -- The `defer_generated_component_packs` configuration has been deprecated. Use `generated_component_packs_loading_strategy` instead. |
57 | | -- The `generated_component_packs_loading_strategy` defaults to `:async` for Shakapacker ≥ 8.2.0 and `:sync` for Shakapacker < 8.2.0. |
58 | | -- The `force_load` configuration now defaults to `true`. |
59 | | -- The new default values of `generated_component_packs_loading_strategy: :async` and `force_load: true` work together to optimize component hydration. Components now hydrate as soon as their code and server-rendered HTML are available, without waiting for the full page to load. This parallel processing significantly improves time-to-interactive by eliminating the traditional waterfall of waiting for page load before beginning hydration (It's critical for streamed HTML). |
60 | | - |
61 | | - - The previous need for deferring scripts to prevent race conditions has been eliminated due to improved hydration handling. Making scripts not defer is critical to execute the hydration scripts early before the page is fully loaded. |
62 | | - - The `force_load` configuration makes `react-on-rails` hydrate components immediately as soon as their server-rendered HTML reaches the client, without waiting for the full page load. |
63 | | - - If you want to keep the previous behavior, you can set `generated_component_packs_loading_strategy: :defer` or `force_load: false` in your `config/initializers/react_on_rails.rb` file. |
64 | | - - You can also keep it for individual components by passing `force_load: false` to `react_component` or `stream_react_component`. |
65 | | - - Redux store now supports `force_load` option, which defaults to `config.force_load` (and so to `true` if that isn't set). If `true`, the Redux store will hydrate immediately as soon as its server-side data reaches the client. |
66 | | - - You can override this behavior for individual Redux stores by calling the `redux_store` helper with `force_load: false`, same as `react_component`. |
67 | | - |
68 | | -- `ReactOnRails.reactOnRailsPageLoaded()` is now an async function: |
69 | | - |
70 | | - - If you manually call this function to ensure components are hydrated (e.g., with async script loading), you must now await the promise it returns: |
71 | | - |
72 | | - ```js |
73 | | - // Before |
74 | | - ReactOnRails.reactOnRailsPageLoaded(); |
75 | | - // Code expecting all components to be hydrated |
76 | | - |
77 | | - // After |
78 | | - await ReactOnRails.reactOnRailsPageLoaded(); |
79 | | - // Code expecting all components to be hydrated |
80 | | - ``` |
81 | | - |
82 | | - - If you call it in a `turbolinks:load` listener to work around the issue documented in [Turbolinks](../rails/turbolinks.md#async-script-loading), the listener can be safely removed. |
83 | | - |
84 | | -### Script Loading Strategy Migration |
85 | | - |
86 | | -- If you were previously using `defer_generated_component_packs: true`, use `generated_component_packs_loading_strategy: :defer` instead |
87 | | -- If you were previously using `defer_generated_component_packs: false`, use `generated_component_packs_loading_strategy: :sync` instead |
88 | | -- For optimal performance with Shakapacker ≥ 8.2.0, consider using `generated_component_packs_loading_strategy: :async` |
89 | | - |
90 | | -### ESM-only package |
91 | | - |
92 | | -The package is now published as ES Modules instead of CommonJS. In most cases it shouldn't affect your code, as bundlers will be able to handle it. However: |
93 | | -
|
94 | | -- If you explicitly use `require('react-on-rails')`, and can't change to `import`, upgrade to Node v20.19.0+ or v22.12.0+. They allow `require` for ESM modules without any flags. Node v20.17.0+ with `--experimental-require-module` should work as well. |
95 | | -- If you run into `TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'.` TypeScript error, you'll need to [upgrade to TypeScript 5.8 and set `module` to `nodenext`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html#support-for-require-of-ecmascript-modules-in---module-nodenext). |
96 | | -
|
97 | | -Finally, if everything else fails, please contact us and we'll help you upgrade or release a dual ESM-CJS version. |
98 | | - |
99 | | -### `globalThis` |
100 | | - |
101 | | -[`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) is now used in code. |
102 | | -It should be available in browsers since 2020 and in Node, but in case your environment doesn't support it, you'll need to shim it using [globalthis](https://www.npmjs.com/package/globalthis) or [core-js](https://www.npmjs.com/package/core-js). |
103 | | - |
104 | | -## Store Dependencies for Components |
105 | | - |
106 | | -When using Redux stores with multiple components, you need to explicitly declare store dependencies to optimize hydration. Here's how: |
107 | | -
|
108 | | -### The Problem |
109 | | -
|
110 | | -If you have deferred Redux stores and components like this: |
111 | | -
|
112 | | -```erb |
113 | | -<% redux_store("SimpleStore", props: @app_props_server_render, defer: true) %> |
114 | | -<%= react_component('ReduxApp', {}, {prerender: true}) %> |
115 | | -<%= react_component('ComponentWithNoStore', {}, {prerender: true}) %> |
116 | | -<%= redux_store_hydration_data %> |
117 | | -``` |
118 | | -
|
119 | | -By default, React on Rails assumes components depend on all previously created stores. This means: |
120 | | -
|
121 | | -- Neither `ReduxApp` nor `ComponentWithNoStore` will hydrate until `SimpleStore` is hydrated |
122 | | -- Since the store is deferred to the end of the page, both components are forced to wait unnecessarily |
123 | | -
|
124 | | -### The Solution |
125 | | -
|
126 | | -Explicitly declare store dependencies for each component: |
127 | | -
|
128 | | -```erb |
129 | | -<% redux_store("SimpleStore", props: @app_props_server_render, defer: true) %> |
130 | | -<%= react_component('ReduxApp', {}, { |
131 | | - prerender: true |
132 | | - # No need to specify store_dependencies: it automatically depends on SimpleStore |
133 | | -}) %> |
134 | | -<%= react_component('ComponentWithNoStore', {}, { |
135 | | - prerender: true, |
136 | | - # Explicitly declare no store dependencies |
137 | | - store_dependencies: [] |
138 | | -}) %> |
139 | | -<%= redux_store_hydration_data %> |
140 | | -``` |
141 | | -
|
142 | | -This allows `ComponentWithNoStore` to hydrate immediately without waiting for `SimpleStore`, improving page performance. |
| 5 | +See [React on Rails 16.0.0 Release Notes](./16.0.0.md) for the latest version. |
0 commit comments