react_on_rails_pro 16.2.0.beta.8
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 +7 -0
- data/.controlplane/Dockerfile +49 -0
- data/.controlplane/controlplane.yml +22 -0
- data/.controlplane/gvc.yml +25 -0
- data/.controlplane/postgres.yml +33 -0
- data/.controlplane/rails.yml +49 -0
- data/.controlplane/redis.yml +18 -0
- data/.gitignore +77 -0
- data/.prettierignore +12 -0
- data/.prettierrc +19 -0
- data/.rspec +2 -0
- data/.rubocop.yml +120 -0
- data/.scss-lint.yml +205 -0
- data/CHANGELOG.md +570 -0
- data/CI_SETUP.md +502 -0
- data/CONTRIBUTING.md +376 -0
- data/Dockerfile +63 -0
- data/Gemfile +8 -0
- data/Gemfile.development_dependencies +74 -0
- data/Gemfile.loader +32 -0
- data/Gemfile.lock +527 -0
- data/LICENSE +98 -0
- data/LICENSE_SETUP.md +272 -0
- data/README.md +577 -0
- data/Rakefile +13 -0
- data/app/controllers/react_on_rails_pro/rsc_payload_controller.rb +7 -0
- data/app/helpers/react_on_rails_pro_helper.rb +360 -0
- data/app/views/react_on_rails_pro/rsc_payload.html.erb +1 -0
- data/babel.config.js +4 -0
- data/docs/bundle-caching.md +205 -0
- data/docs/caching.md +234 -0
- data/docs/code-splitting-loadable-components.md +313 -0
- data/docs/code-splitting.md +349 -0
- data/docs/configuration.md +165 -0
- data/docs/contributors-info/onboarding-customers.md +6 -0
- data/docs/contributors-info/releasing.md +40 -0
- data/docs/contributors-info/style.md +33 -0
- data/docs/home-pro.md +146 -0
- data/docs/installation.md +203 -0
- data/docs/js-memory-leaks.md +22 -0
- data/docs/node-renderer/basics.md +92 -0
- data/docs/node-renderer/debugging.md +38 -0
- data/docs/node-renderer/error-reporting-and-tracing.md +160 -0
- data/docs/node-renderer/heroku.md +102 -0
- data/docs/node-renderer/js-configuration.md +91 -0
- data/docs/node-renderer/troubleshooting.md +5 -0
- data/docs/profiling-server-side-rendering-code.md +179 -0
- data/docs/react-server-components/add-streaming-and-interactivity.md +190 -0
- data/docs/react-server-components/create-without-ssr.md +448 -0
- data/docs/react-server-components/glossary.md +102 -0
- data/docs/react-server-components/how-react-server-components-work.md +243 -0
- data/docs/react-server-components/inside-client-components.md +332 -0
- data/docs/react-server-components/purpose-and-benefits.md +243 -0
- data/docs/react-server-components/rendering-flow.md +86 -0
- data/docs/react-server-components/selective-hydration-in-streamed-components.md +75 -0
- data/docs/react-server-components/server-side-rendering.md +72 -0
- data/docs/react-server-components/tutorial.md +19 -0
- data/docs/release-notes/4.0.md +94 -0
- data/docs/release-notes/v4-react-server-components.md +66 -0
- data/docs/ruby-api.md +11 -0
- data/docs/streaming-server-rendering.md +210 -0
- data/docs/troubleshooting.md +24 -0
- data/docs/updating.md +219 -0
- data/eslint.config.mjs +220 -0
- data/lib/react_on_rails_pro/assets_precompile.rb +230 -0
- data/lib/react_on_rails_pro/cache.rb +88 -0
- data/lib/react_on_rails_pro/concerns/rsc_payload_renderer.rb +38 -0
- data/lib/react_on_rails_pro/concerns/stream.rb +103 -0
- data/lib/react_on_rails_pro/configuration.rb +228 -0
- data/lib/react_on_rails_pro/constants.rb +8 -0
- data/lib/react_on_rails_pro/engine.rb +24 -0
- data/lib/react_on_rails_pro/error.rb +14 -0
- data/lib/react_on_rails_pro/license_public_key.rb +30 -0
- data/lib/react_on_rails_pro/license_validator.rb +188 -0
- data/lib/react_on_rails_pro/prepare_node_renderer_bundles.rb +40 -0
- data/lib/react_on_rails_pro/rendering_error.rb +5 -0
- data/lib/react_on_rails_pro/request.rb +318 -0
- data/lib/react_on_rails_pro/routes.rb +13 -0
- data/lib/react_on_rails_pro/server_rendering_js_code.rb +102 -0
- data/lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb +133 -0
- data/lib/react_on_rails_pro/server_rendering_pool/pro_rendering.rb +117 -0
- data/lib/react_on_rails_pro/stream_cache.rb +61 -0
- data/lib/react_on_rails_pro/stream_request.rb +170 -0
- data/lib/react_on_rails_pro/utils.rb +222 -0
- data/lib/react_on_rails_pro/v8_log_processor.rb +50 -0
- data/lib/react_on_rails_pro/version.rb +6 -0
- data/lib/react_on_rails_pro.rb +23 -0
- data/package-scripts.yml +109 -0
- data/package.json +159 -0
- data/rakelib/dummy_apps.rake +22 -0
- data/rakelib/lint.rake +32 -0
- data/rakelib/public_key_management.rake +155 -0
- data/rakelib/rbs.rake +47 -0
- data/rakelib/run_rspec.rake +81 -0
- data/rakelib/task_helpers.rb +45 -0
- data/rakelib/yard.rake +20 -0
- data/react_on_rails_pro.gemspec +47 -0
- data/readme-gen-docs.md +1 -0
- data/script/bootstrap +33 -0
- data/script/preinstall.js +31 -0
- data/script/setup +23 -0
- data/script/test +38 -0
- data/sig/react_on_rails_pro/cache.rbs +13 -0
- data/sig/react_on_rails_pro/configuration.rbs +100 -0
- data/sig/react_on_rails_pro/error.rbs +4 -0
- data/sig/react_on_rails_pro/utils.rbs +7 -0
- data/sig/react_on_rails_pro.rbs +5 -0
- data/yarn.lock +7599 -0
- metadata +319 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# 🚀 Streaming Server Rendering with React 18
|
|
2
|
+
|
|
3
|
+
React on Rails Pro supports streaming server rendering using React 18's latest APIs, including `renderToPipeableStream` and Suspense. This guide explains how to implement and optimize streaming server rendering in your React on Rails application.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- React on Rails Pro subscription
|
|
8
|
+
- React 19
|
|
9
|
+
- React on Rails v15.0.0-alpha.0 or higher
|
|
10
|
+
- React on Rails Pro v4.0.0 or higher
|
|
11
|
+
|
|
12
|
+
## Benefits of Streaming Server Rendering
|
|
13
|
+
|
|
14
|
+
- Faster Time to First Byte (TTFB)
|
|
15
|
+
- Progressive page loading
|
|
16
|
+
- Improved user experience
|
|
17
|
+
- Better SEO performance
|
|
18
|
+
- Optimal handling of data fetching
|
|
19
|
+
|
|
20
|
+
## Implementation Steps
|
|
21
|
+
|
|
22
|
+
1. **Use React 19 Version**
|
|
23
|
+
|
|
24
|
+
First, ensure you're using React 19 in your package.json:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"react": "19.0.0",
|
|
29
|
+
"react-dom": "19.0.0"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> Note: Check the React documentation for the latest release that supports streaming.
|
|
34
|
+
|
|
35
|
+
2. **Prepare Your React Components**
|
|
36
|
+
|
|
37
|
+
You can create async React components that return a promise. Then, you can use the `Suspense` component to render a fallback UI while the component is loading.
|
|
38
|
+
|
|
39
|
+
```jsx
|
|
40
|
+
// app/javascript/components/MyStreamingComponent.jsx
|
|
41
|
+
import React, { Suspense } from 'react';
|
|
42
|
+
|
|
43
|
+
const fetchData = async () => {
|
|
44
|
+
// Simulate API call
|
|
45
|
+
const response = await fetch('api/endpoint');
|
|
46
|
+
return response.json();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const MyStreamingComponent = () => {
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<header>
|
|
53
|
+
<h1>Streaming Server Rendering</h1>
|
|
54
|
+
</header>
|
|
55
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
56
|
+
<SlowDataComponent />
|
|
57
|
+
</Suspense>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const SlowDataComponent = async () => {
|
|
63
|
+
const data = await fetchData();
|
|
64
|
+
return <div>{data}</div>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default MyStreamingComponent;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```jsx
|
|
71
|
+
// app/javascript/packs/registration.jsx
|
|
72
|
+
import MyStreamingComponent from '../components/MyStreamingComponent';
|
|
73
|
+
|
|
74
|
+
ReactOnRails.register({ MyStreamingComponent });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
3. **Add The Component To Your Rails View**
|
|
78
|
+
|
|
79
|
+
```erb
|
|
80
|
+
<!-- app/views/example/show.html.erb -->
|
|
81
|
+
|
|
82
|
+
<%=
|
|
83
|
+
stream_react_component(
|
|
84
|
+
'MyStreamingComponent',
|
|
85
|
+
props: { greeting: 'Hello, Streaming World!' },
|
|
86
|
+
prerender: true
|
|
87
|
+
)
|
|
88
|
+
%>
|
|
89
|
+
|
|
90
|
+
<footer>
|
|
91
|
+
<p>Footer content</p>
|
|
92
|
+
</footer>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
4. **Render The View Using The `stream_view_containing_react_components` Helper**
|
|
96
|
+
|
|
97
|
+
Ensure you have a controller that renders the view containing the React components. The controller must include the `ReactOnRails::Controller`, `ReactOnRailsPro::Stream` and `ActionController::Live` modules.
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
# app/controllers/example_controller.rb
|
|
101
|
+
|
|
102
|
+
class ExampleController < ApplicationController
|
|
103
|
+
include ReactOnRailsPro::Stream
|
|
104
|
+
|
|
105
|
+
def show
|
|
106
|
+
stream_view_containing_react_components(template: 'example/show')
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
5. **Test Your Application**
|
|
112
|
+
|
|
113
|
+
You can test your application by running `rails server` and navigating to the appropriate route.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
6. **What Happens During Streaming**
|
|
117
|
+
|
|
118
|
+
When a user visits the page, they'll experience the following sequence:
|
|
119
|
+
|
|
120
|
+
1. The initial HTML shell is sent immediately, including:
|
|
121
|
+
- The page layout
|
|
122
|
+
- Any static content (like the `<h1>` and footer)
|
|
123
|
+
- Placeholder content for the React component (typically a loading state)
|
|
124
|
+
|
|
125
|
+
2. As the React component processes and suspense boundaries resolve:
|
|
126
|
+
- HTML chunks are streamed to the browser progressively
|
|
127
|
+
- Each chunk updates a specific part of the page
|
|
128
|
+
- The browser renders these updates without a full page reload
|
|
129
|
+
|
|
130
|
+
For example, with our `MyStreamingComponent`, the sequence might be:
|
|
131
|
+
|
|
132
|
+
1. The initial HTML includes the header, footer, and loading state.
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<header>
|
|
136
|
+
<h1>Streaming Server Rendering</h1>
|
|
137
|
+
</header>
|
|
138
|
+
<template id="s0">
|
|
139
|
+
<div>Loading...</div>
|
|
140
|
+
</template>
|
|
141
|
+
<footer>
|
|
142
|
+
<p>Footer content</p>
|
|
143
|
+
</footer>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
2. As the component resolves, HTML chunks are streamed to the browser:
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<template hidden id="b0">
|
|
150
|
+
<div>[Fetched data]</div>
|
|
151
|
+
</template>
|
|
152
|
+
|
|
153
|
+
<script>
|
|
154
|
+
// This implementation is slightly simplified
|
|
155
|
+
document.getElementById('s0').replaceChildren(
|
|
156
|
+
document.getElementById('b0')
|
|
157
|
+
);
|
|
158
|
+
</script>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## When to Use Streaming
|
|
162
|
+
|
|
163
|
+
Streaming SSR is particularly valuable in specific scenarios. Here's when to consider it:
|
|
164
|
+
|
|
165
|
+
### Ideal Use Cases
|
|
166
|
+
|
|
167
|
+
1. **Data-Heavy Pages**
|
|
168
|
+
- Pages that fetch data from multiple sources
|
|
169
|
+
- Dashboard-style layouts where different sections can load independently
|
|
170
|
+
- Content that requires heavy processing or computation
|
|
171
|
+
|
|
172
|
+
2. **Progressive Enhancement**
|
|
173
|
+
- When you want users to see and interact with parts of the page while others load
|
|
174
|
+
- For improving perceived performance on slower connections
|
|
175
|
+
- When different parts of your page have different priority levels
|
|
176
|
+
|
|
177
|
+
3. **Large, Complex Applications**
|
|
178
|
+
- Applications with multiple independent widgets or components
|
|
179
|
+
- Pages where some content is critical and other content is supplementary
|
|
180
|
+
- When you need to optimize Time to First Byte (TTFB)
|
|
181
|
+
|
|
182
|
+
### Best Practices for Streaming
|
|
183
|
+
|
|
184
|
+
1. **Component Structure**
|
|
185
|
+
```jsx
|
|
186
|
+
// Good: Independent sections that can stream separately
|
|
187
|
+
<Layout>
|
|
188
|
+
<Suspense fallback={<HeaderSkeleton />}>
|
|
189
|
+
<Header />
|
|
190
|
+
</Suspense>
|
|
191
|
+
<Suspense fallback={<MainContentSkeleton />}>
|
|
192
|
+
<MainContent />
|
|
193
|
+
</Suspense>
|
|
194
|
+
<Suspense fallback={<SidebarSkeleton />}>
|
|
195
|
+
<Sidebar />
|
|
196
|
+
</Suspense>
|
|
197
|
+
</Layout>
|
|
198
|
+
|
|
199
|
+
// Bad: Everything wrapped in a single Suspense boundary
|
|
200
|
+
<Suspense fallback={<FullPageSkeleton />}>
|
|
201
|
+
<Header />
|
|
202
|
+
<MainContent />
|
|
203
|
+
<Sidebar />
|
|
204
|
+
</Suspense>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
2. **Data Loading Strategy**
|
|
208
|
+
- Prioritize critical data that should be included in the initial HTML
|
|
209
|
+
- Use streaming for supplementary data that can load progressively
|
|
210
|
+
- Consider implementing a waterfall strategy for dependent data
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Invalid Token Workaround
|
|
4
|
+
On June 27, 2024, tokens mysteriously did not work for a few hours. The problem resolved itself within a few hours.
|
|
5
|
+
|
|
6
|
+
If you do see this problem, get in touch with the package maintainers via Slack. You can also message
|
|
7
|
+
Justin Gordon at +1-808-281-7272.
|
|
8
|
+
|
|
9
|
+
As an alternative to the token issue, if you have an account with access to the docs and this file, you can
|
|
10
|
+
create a new token and follow these steps.
|
|
11
|
+
|
|
12
|
+
To create a new token, visit https://github.com/settings/apps:
|
|
13
|
+
1. Developer Settings
|
|
14
|
+
2. Personal access tokens
|
|
15
|
+
3. Tokens (classic)
|
|
16
|
+
4. Generate a new token, classic
|
|
17
|
+
5. 30-day expiration (to be safer)
|
|
18
|
+
6. Repo privileges (not ideal) but shouldn't last long
|
|
19
|
+
|
|
20
|
+
Then follow these steps to use your token:
|
|
21
|
+
* [Ruby Gem](https://github.com/shakacode/react_on_rails_pro/blob/master/docs/installation.md#using-a-branch-in-your-gemfile)
|
|
22
|
+
* [Node Package](https://github.com/shakacode/react_on_rails_pro/blob/master/docs/installation.md#instructions-for-using-a-branch)
|
|
23
|
+
|
|
24
|
+
Note that this token gives `repo` access, so you want to revoke this token ASAP.
|
data/docs/updating.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Upgrading React on Rails Pro
|
|
2
|
+
|
|
3
|
+
## Upgrading from GitHub Packages to Public Distribution
|
|
4
|
+
|
|
5
|
+
### Who This Guide is For
|
|
6
|
+
|
|
7
|
+
This guide is for existing React on Rails Pro customers who are:
|
|
8
|
+
|
|
9
|
+
- Currently using GitHub Packages authentication (private distribution)
|
|
10
|
+
- On version 16.2.0-beta.x or earlier
|
|
11
|
+
- Upgrading to version 16.2.0 or higher
|
|
12
|
+
|
|
13
|
+
If you're a new customer, see [Installation](./installation.md) instead.
|
|
14
|
+
|
|
15
|
+
### What's Changing
|
|
16
|
+
|
|
17
|
+
React on Rails Pro packages are now **publicly distributed** via npmjs.org and RubyGems.org:
|
|
18
|
+
|
|
19
|
+
- ✅ No more GitHub Personal Access Tokens (PATs)
|
|
20
|
+
- ✅ No more `.npmrc` configuration
|
|
21
|
+
- ✅ Simplified installation with standard `gem install` and `npm install`
|
|
22
|
+
- ✅ License validation now happens at **runtime** using JWT tokens
|
|
23
|
+
|
|
24
|
+
Package names have changed:
|
|
25
|
+
|
|
26
|
+
- **Scoped** (old): `@shakacode-tools/react-on-rails-pro-node-renderer`
|
|
27
|
+
- **Unscoped** (new): `react-on-rails-pro-node-renderer`
|
|
28
|
+
|
|
29
|
+
### Your Current Setup (GitHub Packages)
|
|
30
|
+
|
|
31
|
+
If you're upgrading, you currently have:
|
|
32
|
+
|
|
33
|
+
**1. Gemfile with GitHub Packages source:**
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
source "https://rubygems.pkg.github.com/shakacode-tools" do
|
|
37
|
+
gem "react_on_rails_pro", "16.1.1"
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**2. `.npmrc` file with GitHub authentication:**
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
always-auth=true
|
|
45
|
+
//npm.pkg.github.com/:_authToken=YOUR_TOKEN
|
|
46
|
+
@shakacode-tools:registry=https://npm.pkg.github.com
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**3. Scoped package name in package.json:**
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"private": true,
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@shakacode-tools/react-on-rails-pro-node-renderer": "16.1.1"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**4. Scoped require statements:**
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
const { reactOnRailsProNodeRenderer } = require('@shakacode-tools/react-on-rails-pro-node-renderer');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Migration Steps
|
|
67
|
+
|
|
68
|
+
#### Step 1: Update Gemfile
|
|
69
|
+
|
|
70
|
+
**Remove** the GitHub Packages source and use standard gem installation:
|
|
71
|
+
|
|
72
|
+
```diff
|
|
73
|
+
- source "https://rubygems.pkg.github.com/shakacode-tools" do
|
|
74
|
+
- gem "react_on_rails_pro", "16.1.1"
|
|
75
|
+
- end
|
|
76
|
+
+ gem "react_on_rails_pro", "~> 16.2"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then run:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
bundle install
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### Step 2: Remove .npmrc Configuration
|
|
86
|
+
|
|
87
|
+
If you have a `.npmrc` file with GitHub Packages authentication, **delete it** or remove the GitHub-specific lines:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Remove the entire file if it only contained GitHub Packages config
|
|
91
|
+
rm .npmrc
|
|
92
|
+
|
|
93
|
+
# Or edit it to remove these lines:
|
|
94
|
+
# always-auth=true
|
|
95
|
+
# //npm.pkg.github.com/:_authToken=YOUR_TOKEN
|
|
96
|
+
# @shakacode-tools:registry=https://npm.pkg.github.com
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Step 3: Update package.json
|
|
100
|
+
|
|
101
|
+
Change the package name from **scoped** to **unscoped**:
|
|
102
|
+
|
|
103
|
+
```diff
|
|
104
|
+
{
|
|
105
|
+
"dependencies": {
|
|
106
|
+
- "@shakacode-tools/react-on-rails-pro-node-renderer": "16.1.1"
|
|
107
|
+
+ "react-on-rails-pro-node-renderer": "^16.2.0"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Then reinstall:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm install
|
|
116
|
+
# or
|
|
117
|
+
yarn install
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Step 4: Update Require Statements
|
|
121
|
+
|
|
122
|
+
Update all require/import statements to use the **unscoped** package name:
|
|
123
|
+
|
|
124
|
+
**In your node renderer configuration file:**
|
|
125
|
+
|
|
126
|
+
```diff
|
|
127
|
+
- const { reactOnRailsProNodeRenderer } = require('@shakacode-tools/react-on-rails-pro-node-renderer');
|
|
128
|
+
+ const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**If using integrations (Sentry, Honeybadger):**
|
|
132
|
+
|
|
133
|
+
```diff
|
|
134
|
+
- require('@shakacode-tools/react-on-rails-pro-node-renderer/integrations/sentry').init();
|
|
135
|
+
+ require('react-on-rails-pro-node-renderer/integrations/sentry').init();
|
|
136
|
+
|
|
137
|
+
- require('@shakacode-tools/react-on-rails-pro-node-renderer/integrations/honeybadger').init();
|
|
138
|
+
+ require('react-on-rails-pro-node-renderer/integrations/honeybadger').init();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Step 5: Configure License Token
|
|
142
|
+
|
|
143
|
+
Add your React on Rails Pro license token as an environment variable:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
export REACT_ON_RAILS_PRO_LICENSE="your-license-token-here"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Or** configure it in your Rails initializer:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# config/initializers/react_on_rails_pro.rb
|
|
153
|
+
ReactOnRailsPro.configure do |config|
|
|
154
|
+
config.license_token = ENV["REACT_ON_RAILS_PRO_LICENSE"]
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
⚠️ **Security Warning**: Never commit your license token to version control. Always use environment variables or secure secret management systems (Rails credentials, Heroku config vars, AWS Secrets Manager, etc.).
|
|
159
|
+
|
|
160
|
+
**Where to get your license token:** Contact [justin@shakacode.com](mailto:justin@shakacode.com) if you don't have your license token.
|
|
161
|
+
|
|
162
|
+
### Verify Migration
|
|
163
|
+
|
|
164
|
+
#### 1. Verify Gem Installation
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
bundle list | grep react_on_rails_pro
|
|
168
|
+
# Should show: react_on_rails_pro (16.2.0) or higher
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### 2. Verify NPM Package Installation
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm list react-on-rails-pro-node-renderer
|
|
175
|
+
# or
|
|
176
|
+
yarn list --pattern react-on-rails-pro-node-renderer
|
|
177
|
+
|
|
178
|
+
# Should show: react-on-rails-pro-node-renderer@16.2.0 or higher
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### 3. Verify License Token
|
|
182
|
+
|
|
183
|
+
Start your Rails server. You should see a success message in the logs:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
React on Rails Pro license validated successfully
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
If the license is invalid or missing, you'll see an error with instructions.
|
|
190
|
+
|
|
191
|
+
#### 4. Test Your Application
|
|
192
|
+
|
|
193
|
+
- Start your Rails server
|
|
194
|
+
- Start the node renderer (if using): `npm run node-renderer`
|
|
195
|
+
- Verify that server-side rendering works correctly
|
|
196
|
+
|
|
197
|
+
### Troubleshooting
|
|
198
|
+
|
|
199
|
+
#### "Could not find gem 'react_on_rails_pro'"
|
|
200
|
+
|
|
201
|
+
- Ensure you removed the GitHub Packages source from your Gemfile
|
|
202
|
+
- Run `bundle install` again
|
|
203
|
+
- Check that you have the correct version specified
|
|
204
|
+
|
|
205
|
+
#### "Cannot find module 'react-on-rails-pro-node-renderer'"
|
|
206
|
+
|
|
207
|
+
- Verify you updated all require statements to the unscoped name
|
|
208
|
+
- Delete `node_modules` and reinstall: `rm -rf node_modules && npm install`
|
|
209
|
+
- Check that package.json has the correct unscoped package name
|
|
210
|
+
|
|
211
|
+
#### "License validation failed"
|
|
212
|
+
|
|
213
|
+
- Ensure `REACT_ON_RAILS_PRO_LICENSE` environment variable is set
|
|
214
|
+
- Verify the token string is correct (no extra spaces or quotes)
|
|
215
|
+
- Contact [justin@shakacode.com](mailto:justin@shakacode.com) if you need a new token
|
|
216
|
+
|
|
217
|
+
### Need Help?
|
|
218
|
+
|
|
219
|
+
If you encounter issues during migration, contact [justin@shakacode.com](mailto:justin@shakacode.com) for support.
|
data/eslint.config.mjs
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { includeIgnoreFile } from '@eslint/compat';
|
|
3
|
+
import js from '@eslint/js';
|
|
4
|
+
import { FlatCompat } from '@eslint/eslintrc';
|
|
5
|
+
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
6
|
+
import importPlugin from 'eslint-plugin-import';
|
|
7
|
+
import jest from 'eslint-plugin-jest';
|
|
8
|
+
import prettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
9
|
+
import globals from 'globals';
|
|
10
|
+
import typescriptEslint from 'typescript-eslint';
|
|
11
|
+
|
|
12
|
+
const compat = new FlatCompat({
|
|
13
|
+
baseDirectory: import.meta.dirname,
|
|
14
|
+
recommendedConfig: js.configs.recommended,
|
|
15
|
+
allConfig: js.configs.all,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export default defineConfig([
|
|
19
|
+
includeIgnoreFile(path.resolve(import.meta.dirname, '.gitignore')),
|
|
20
|
+
globalIgnores([
|
|
21
|
+
'gen-documentation/',
|
|
22
|
+
'spec/react_on_rails/dummy-for-generators',
|
|
23
|
+
// includes some generated code
|
|
24
|
+
'spec/dummy/client/app/packs/server-bundle.js',
|
|
25
|
+
'packages/node-renderer/lib/',
|
|
26
|
+
'packages/node-renderer/tests/fixtures',
|
|
27
|
+
'**/node_modules/',
|
|
28
|
+
'**/assets/webpack/',
|
|
29
|
+
'**/generated/',
|
|
30
|
+
'**/app/assets/javascripts/application.js',
|
|
31
|
+
'**/coverage/',
|
|
32
|
+
'**/cable.js',
|
|
33
|
+
'**/public/',
|
|
34
|
+
'**/tmp/',
|
|
35
|
+
'**/vendor/',
|
|
36
|
+
'**/dist/',
|
|
37
|
+
'**/.yalc/',
|
|
38
|
+
'**/*.chunk.js',
|
|
39
|
+
]),
|
|
40
|
+
{
|
|
41
|
+
files: ['**/*.[jt]s', '**/*.[cm][jt]s', '**/*.[jt]sx'],
|
|
42
|
+
},
|
|
43
|
+
js.configs.recommended,
|
|
44
|
+
compat.extends('eslint-config-shakacode'),
|
|
45
|
+
{
|
|
46
|
+
languageOptions: {
|
|
47
|
+
globals: globals.node,
|
|
48
|
+
|
|
49
|
+
parserOptions: {
|
|
50
|
+
// We have @babel/eslint-parser from eslint-config-shakacode, but don't use Babel in the main project
|
|
51
|
+
requireConfigFile: false,
|
|
52
|
+
|
|
53
|
+
babelOptions: {
|
|
54
|
+
presets: ['@babel/preset-env', '@babel/preset-react'],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
settings: {
|
|
60
|
+
'import/extensions': ['.js', '.ts'],
|
|
61
|
+
|
|
62
|
+
'import/parsers': {
|
|
63
|
+
'@typescript-eslint/parser': ['.ts'],
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
'import/resolver': {
|
|
67
|
+
alias: [['Assets', './spec/dummy/client/app/assets']],
|
|
68
|
+
node: true,
|
|
69
|
+
typescript: true,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
rules: {
|
|
74
|
+
'no-console': 'off',
|
|
75
|
+
'no-underscore-dangle': 'off',
|
|
76
|
+
'no-void': [
|
|
77
|
+
'error',
|
|
78
|
+
{
|
|
79
|
+
// Allow using void to suppress errors about misused promises
|
|
80
|
+
allowAsStatement: true,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
|
|
84
|
+
// Allow using void to suppress errors about misused promises
|
|
85
|
+
'no-restricted-syntax': 'off',
|
|
86
|
+
// https://github.com/benmosher/eslint-plugin-import/issues/340
|
|
87
|
+
'import/no-extraneous-dependencies': 'off',
|
|
88
|
+
'import/extensions': 'off',
|
|
89
|
+
'import/prefer-default-export': 'off',
|
|
90
|
+
'lines-between-class-members': [
|
|
91
|
+
'error',
|
|
92
|
+
{
|
|
93
|
+
enforce: [
|
|
94
|
+
{ blankLine: 'always', prev: '*', next: '*' },
|
|
95
|
+
{ blankLine: 'never', prev: 'field', next: 'field' },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
'no-mixed-operators': 'off',
|
|
100
|
+
'react/forbid-prop-types': 'off',
|
|
101
|
+
'react/function-component-definition': [
|
|
102
|
+
'error',
|
|
103
|
+
{
|
|
104
|
+
namedComponents: ['function-declaration', 'arrow-function'],
|
|
105
|
+
unnamedComponents: 'arrow-function',
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
'react/jsx-filename-extension': [
|
|
109
|
+
'error',
|
|
110
|
+
{
|
|
111
|
+
extensions: ['.jsx', '.tsx'],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
'react/jsx-props-no-spreading': [
|
|
115
|
+
'error',
|
|
116
|
+
{
|
|
117
|
+
custom: 'ignore',
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
'react/prop-types': 'off',
|
|
121
|
+
'react/static-property-placement': 'off',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
files: ['spec/dummy/**/*', 'spec/execjs-compatible-dummy'],
|
|
126
|
+
languageOptions: {
|
|
127
|
+
globals: globals.browser,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
files: ['**/*.ts{x,}'],
|
|
132
|
+
extends: [importPlugin.flatConfigs.typescript, typescriptEslint.configs.strictTypeChecked],
|
|
133
|
+
|
|
134
|
+
languageOptions: {
|
|
135
|
+
parserOptions: {
|
|
136
|
+
projectService: true,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
rules: {
|
|
141
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
142
|
+
|
|
143
|
+
'@typescript-eslint/no-unused-vars': [
|
|
144
|
+
'error',
|
|
145
|
+
{
|
|
146
|
+
argsIgnorePattern: '^_',
|
|
147
|
+
caughtErrorsIgnorePattern: '^_',
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
|
|
151
|
+
'@typescript-eslint/no-floating-promises': [
|
|
152
|
+
'error',
|
|
153
|
+
{
|
|
154
|
+
allowForKnownSafePromises: [
|
|
155
|
+
{
|
|
156
|
+
from: 'package',
|
|
157
|
+
package: 'fastify',
|
|
158
|
+
name: 'FastifyReply',
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
|
|
164
|
+
'no-shadow': 'off',
|
|
165
|
+
'@typescript-eslint/no-shadow': 'error',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
files: ['packages/node-renderer/tests/**', '**/*.test.{js,jsx,ts,tsx}'],
|
|
170
|
+
|
|
171
|
+
extends: [jest.configs['flat/recommended'], jest.configs['flat/style']],
|
|
172
|
+
|
|
173
|
+
rules: {
|
|
174
|
+
// Allows Jest mocks before import
|
|
175
|
+
'import/first': 'off',
|
|
176
|
+
'jest/no-disabled-tests': 'warn',
|
|
177
|
+
'jest/no-focused-tests': 'error',
|
|
178
|
+
'jest/no-identical-title': 'error',
|
|
179
|
+
'jest/prefer-to-have-length': 'warn',
|
|
180
|
+
'jest/valid-expect': 'error',
|
|
181
|
+
// Simplifies test code
|
|
182
|
+
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
files: ['packages/node-renderer/src/integrations/**'],
|
|
187
|
+
ignores: ['packages/node-renderer/src/integrations/api.ts'],
|
|
188
|
+
|
|
189
|
+
rules: {
|
|
190
|
+
// Integrations should only use the public integration API
|
|
191
|
+
'no-restricted-imports': [
|
|
192
|
+
'error',
|
|
193
|
+
{
|
|
194
|
+
patterns: ['../*'],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
files: ['spec/dummy/e2e-tests/*'],
|
|
201
|
+
|
|
202
|
+
rules: {
|
|
203
|
+
'no-empty-pattern': [
|
|
204
|
+
'error',
|
|
205
|
+
{
|
|
206
|
+
allowObjectPatternsAsParameters: true,
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
files: ['spec/dummy/e2e-tests/*'],
|
|
213
|
+
rules: {
|
|
214
|
+
'react-hooks/rules-of-hooks': ['off'],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
// must be the last config in the array
|
|
218
|
+
// https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
|
|
219
|
+
prettierRecommended,
|
|
220
|
+
]);
|