Skip to content

Commit f7d5355

Browse files
Enhance Pro license validation for force_load feature (#1781)
Rename force_load to immediate_hydration and enforce Pro license requirement Breaking Changes: - Rename `force_load` option to `immediate_hydration` across entire codebase - Change default value from true to false for safer community version behavior - Make immediate_hydration a React on Rails Pro licensed feature Implementation: - Add centralized Pro license validation via support_pro_features? helper - Implement server-side checks that disable immediate_hydration for non-Pro users - Add client-side validation with console warnings when Pro feature is requested - Display warning badge in development when Pro feature attempted without license - Update all data attributes from data-force-load to data-immediate-hydration Documentation: - Update configuration docs to clarify Pro license requirement - Add immediate_hydration to Pro features documentation - Update changelog for v16.0.0 release (v15.0.0 retracted) - Add proper Prettier formatting commands to CONTRIBUTING.md and CLAUDE.md Testing: - Fix flaky Turbolinks/TurboStream integration tests - Update all test expectations for new data attributes - Configure tests to handle Pro feature warnings appropriately The immediate_hydration option enables components to hydrate as soon as they're rendered without waiting for full page load - critical for streaming HTML and improving time-to-interactive metrics.
1 parent d5873f1 commit f7d5355

File tree

18 files changed

+330
-222
lines changed

18 files changed

+330
-222
lines changed

CHANGELOG.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ After a release, please make sure to run `bundle exec rake update_changelog`. Th
2323

2424
Changes since the last non-beta release.
2525

26-
### [15.0.0] - 2025-08-28
26+
### [16.0.0] - 2025-01-XX
2727

28-
See [Release Notes](docs/release-notes/15.0.0.md) for full details.
28+
See [Release Notes](docs/release-notes/16.0.0.md) for full details.
2929

3030
### Removed (Breaking Changes)
3131

@@ -40,10 +40,14 @@ See [Release Notes](docs/release-notes/15.0.0.md) for full details.
4040
- For TypeScript errors, upgrade to TypeScript 5.8+ and set `module` to `nodenext`.
4141
- `ReactOnRails.reactOnRailsPageLoaded` is now an async function. Migration:
4242
- Add `await` when calling this function: `await ReactOnRails.reactOnRailsPageLoaded()`.
43-
- `force_load` configuration now defaults to `true`. Migration:
44-
- Set `force_load: false` in your config if you want the previous behavior.
43+
- **RENAMED**: `force_load` configuration renamed to `immediate_hydration` for better API clarity.
44+
- `immediate_hydration` now defaults to `false` and requires React on Rails Pro license.
45+
- Migration:
46+
- `config.force_load = true``config.immediate_hydration = true`
47+
- `react_component(force_load: true)``react_component(immediate_hydration: true)`
48+
- `redux_store(force_load: true)``redux_store(immediate_hydration: true)`
4549

46-
For detailed migration instructions, see the [15.0.0 Release Notes](docs/release-notes/15.0.0.md).
50+
For detailed migration instructions, see the [16.0.0 Release Notes](docs/release-notes/16.0.0.md).
4751

4852
#### Fixed
4953

@@ -70,6 +74,12 @@ For detailed migration instructions, see the [15.0.0 Release Notes](docs/release
7074
- React Server Components Support (Pro Feature) [PR 1644](https://github.com/shakacode/react_on_rails/pull/1644) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
7175
- Improved component and store hydration performance [PR 1656](https://github.com/shakacode/react_on_rails/pull/1656) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
7276

77+
### [15.0.0] - 2025-08-28 - RETRACTED
78+
79+
**⚠️ This version has been retracted due to API design issues. Please upgrade directly to v16.0.0.**
80+
81+
The `force_load` feature was incorrectly available without a Pro license and has been renamed to `immediate_hydration` for better clarity. All features from v15 are available in v16 with the corrected API.
82+
7383
### [14.2.0] - 2025-03-03
7484

7585
#### Added

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
1515
- All linters: `rake lint` (runs ESLint and RuboCop)
1616
- ESLint only: `yarn run lint` or `rake lint:eslint`
1717
- RuboCop only: `rake lint:rubocop`
18+
- **Code Formatting**:
19+
- Format code with Prettier: `yarn start format`
20+
- Check formatting without fixing: `yarn start format.listDifferent`
1821
- **Build**: `yarn run build` (compiles TypeScript to JavaScript in node_package/lib)
1922
- **Type checking**: `yarn run type-check`
2023

CONTRIBUTING.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,42 @@ cd react_on_rails/
180180
yarn run check
181181
```
182182

183+
## Development Commands
184+
185+
### Code Formatting
186+
187+
To format JavaScript/TypeScript files with Prettier:
188+
189+
```sh
190+
yarn start format
191+
```
192+
193+
To check formatting without fixing:
194+
195+
```sh
196+
yarn start format.listDifferent
197+
```
198+
199+
### Linting
200+
201+
Run all linters (ESLint and RuboCop):
202+
203+
```sh
204+
rake lint
205+
```
206+
207+
Run only RuboCop:
208+
209+
```sh
210+
rake lint:rubocop
211+
```
212+
213+
Run only ESLint:
214+
215+
```sh
216+
yarn run lint
217+
```
218+
183219
### Starting the Dummy App
184220

185221
To run the dummy app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start` with one of the Procfiles. If you don't do this, then `webpack` will not generate a new bundle, and you will be seriously confused when you change JavaScript and the app does not change. If you change the Webpack configs, then you need to restart Foreman. If you change the JS code for react-on-rails, you need to run `yarn run build` in the project root.

docs/guides/configuration.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,14 @@ ReactOnRails.configure do |config|
223223
# DEPRECATED: Use `generated_component_packs_loading_strategy` instead.
224224
# Migration: `defer_generated_component_packs: true` → `generated_component_packs_loading_strategy: :defer`
225225
# Migration: `defer_generated_component_packs: false` → `generated_component_packs_loading_strategy: :sync`
226-
# See [15.0.0 Release Notes](docs/release-notes/15.0.0.md) for more details.
226+
# See [16.0.0 Release Notes](docs/release-notes/16.0.0.md) for more details.
227227
# config.defer_generated_component_packs = false
228228

229-
# Default is true
230-
# When true, components hydrate immediately as soon as their server-rendered HTML reaches the client,
231-
# without waiting for the full page load. This improves time-to-interactive performance.
232-
config.force_load = true
229+
# Default is false
230+
# React on Rails Pro (licensed) feature: When true, components hydrate immediately as soon as
231+
# their server-rendered HTML reaches the client, without waiting for the full page load.
232+
# This improves time-to-interactive performance.
233+
config.immediate_hydration = false
233234

234235
################################################################################
235236
# I18N OPTIONS

docs/guides/streaming-server-rendering.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ React on Rails Pro supports streaming server rendering using React 18's latest A
66

77
- React on Rails Pro subscription
88
- React 19
9-
- React on Rails v15.0.0-alpha.0 or higher
9+
- React on Rails v16.0.0 or higher
1010
- React on Rails Pro v4.0.0.rc.5 or higher
1111

1212
## Benefits of Streaming Server Rendering

docs/rails/turbolinks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ document.addEventListener('turbolinks:load', function () {
103103
React on Rails 15 fixes both issues, so if you still have the listener it can be removed (and should be as `reactOnRailsPageLoaded()` is now async).
104104

105105
> [!WARNING]
106-
> Do not use `force_load: false` with Turbolinks if you have async scripts.
106+
> Do not use `immediate_hydration: false` (React on Rails Pro licensed feature) with Turbolinks if you have async scripts.
107107
108108
## Troubleshooting
109109

docs/release-notes/15.0.0.md

Lines changed: 2 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,5 @@
11
# React on Rails 15.0.0 Release Notes
22

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.**
44

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-
![Performance comparison showing early hydration improvement](../assets/early-hydration-performance-comparison.jpg)
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

Comments
 (0)