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,448 @@
|
|
|
1
|
+
# Create React Server Component without SSR
|
|
2
|
+
|
|
3
|
+
React Server Components are a new way to build web applications. It has many advantages you can see in the [React Server Components Glossary](./glossary.md). Also, we need to differentiate between Server Components and Server Side Rendering (SSR). You don't need to use SSR to use Server Components.
|
|
4
|
+
|
|
5
|
+
In this article, we will create a Server Component without SSR.
|
|
6
|
+
|
|
7
|
+
## Prepare RORP Project to use Server Components
|
|
8
|
+
|
|
9
|
+
To use Server Components in your React on Rails Pro project, you need to follow these steps:
|
|
10
|
+
|
|
11
|
+
1. Install the latest version of React on Rails and React on Rails Pro:
|
|
12
|
+
|
|
13
|
+
Note: These versions are not released yet, they are still in development. But they will have these versions when released.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
yarn add react-on-rails@15.0.0-alpha.2 react-on-rails-pro@4.0.0
|
|
17
|
+
bundle add react_on_rails@15.0.0.alpha.2 react_on_rails_pro@4.0.0
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Also, install version 19 of React, React DOM, and `react-on-rails-rsc`:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn add react@19.0.0 react-dom@19.0.0 react-on-rails-rsc@19.0.0
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
> [!NOTE]
|
|
27
|
+
> While React Server Components in React 19 are stable, the underlying APIs used to implement React Server Components bundlers may break between minor versions (19.x). According to the [React Documentation](https://react.dev/reference/rsc/server-components#how-do-i-build-support-for-server-components). React on Rails Pro currently only supports React 19.0.x.
|
|
28
|
+
|
|
29
|
+
2. Enable support for Server Components in React on Rails Pro configuration:
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
# config/initializers/react_on_rails_pro.rb
|
|
33
|
+
|
|
34
|
+
ReactOnRailsPro.configure do |config|
|
|
35
|
+
config.enable_rsc_support = true
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> [!IMPORTANT]
|
|
40
|
+
> After enabling RSC support, you must add the `'use client';` directive at the top of your JavaScript entry points (packs) that are not yet migrated to support Server Components.
|
|
41
|
+
>
|
|
42
|
+
> This directive tells React that these files should be treated as client components. You don't need to add this directive to all JavaScript files - only the entry points. Any file imported by a file marked with `'use client';` will automatically be treated as a client component as well. Without this directive, React will assume these files contain Server Components, which will cause errors if the components use client-side features like:
|
|
43
|
+
> - `useState` or other state hooks
|
|
44
|
+
> - `useEffect` or other effect hooks
|
|
45
|
+
> - Event handlers (onClick, onChange, etc.)
|
|
46
|
+
> - Browser APIs
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
For example:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
// app/javascript/client/app/ror-auto-load-components/HomePage.jsx
|
|
53
|
+
'use client';
|
|
54
|
+
|
|
55
|
+
// ... existing code ...
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
3. Create a new Webpack configuration to generate React Server Components bundles (RSC bundles) (usually named `rsc-bundle.js`).
|
|
60
|
+
|
|
61
|
+
RSC bundle is a clone of the server bundle `server-bundle.js` but we just add the RSC loader `react-on-rails-rsc/WebpackLoader` to the used loaders.
|
|
62
|
+
|
|
63
|
+
You can check the [How React Server Components work](how-react-server-components-work.md) for more information about the RSC loader (It's better to read it after reading this article).
|
|
64
|
+
|
|
65
|
+
Create a new file `config/webpack/rscWebpackConfig.js`:
|
|
66
|
+
```js
|
|
67
|
+
// use the same config as serverWebpackConfig.js but add the RSC loader
|
|
68
|
+
const serverWebpackConfig = require('./serverWebpackConfig');
|
|
69
|
+
|
|
70
|
+
// Function that extracts a specific loader from a webpack rule
|
|
71
|
+
function extractLoader(rule, loaderName) {
|
|
72
|
+
return rule.use.find((item) => {
|
|
73
|
+
let testValue;
|
|
74
|
+
|
|
75
|
+
if (typeof item === 'string') {
|
|
76
|
+
testValue = item;
|
|
77
|
+
} else if (typeof item.loader === 'string') {
|
|
78
|
+
testValue = item.loader;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return testValue.includes(loaderName);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const configureRsc = () => {
|
|
86
|
+
const rscConfig = serverWebpackConfig();
|
|
87
|
+
|
|
88
|
+
// Update the entry name to be `rsc-bundle` instead of `server-bundle`
|
|
89
|
+
const rscEntry = {
|
|
90
|
+
'rsc-bundle': rscConfig.entry['server-bundle'],
|
|
91
|
+
};
|
|
92
|
+
rscConfig.entry = rscEntry;
|
|
93
|
+
|
|
94
|
+
// Add the RSC loader before the babel loader
|
|
95
|
+
const rules = rscConfig.module.rules;
|
|
96
|
+
rules.forEach((rule) => {
|
|
97
|
+
if (Array.isArray(rule.use)) {
|
|
98
|
+
// Ensure this loader runs before the JS loader (Babel loader in this case) to properly exclude client components from the RSC bundle.
|
|
99
|
+
// If your project uses a different JS loader, insert it before that loader instead.
|
|
100
|
+
const babelLoader = extractLoader(rule, 'babel-loader');
|
|
101
|
+
if (babelLoader) {
|
|
102
|
+
rule.use.push({
|
|
103
|
+
loader: 'react-on-rails-rsc/WebpackLoader',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Add the `react-server` condition to the resolve config
|
|
110
|
+
// This condition is used by React and React on Rails to know that this bundle is a React Server Component bundle
|
|
111
|
+
// The `...` tells webpack to retain the default Webpack conditions (In this case will keep the `node` condition because the bundle targets node)
|
|
112
|
+
rscConfig.resolve = {
|
|
113
|
+
...rscConfig.resolve,
|
|
114
|
+
conditionNames: ['react-server', '...'],
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Update the output bundle name to be `rsc-bundle.js` instead of `server-bundle.js`
|
|
118
|
+
rscConfig.output.filename = 'rsc-bundle.js';
|
|
119
|
+
return rscConfig;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
module.exports = configureRsc;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Add the new RSC Webpack configuration to the bundle configuration returned by `webpackConfig` function in `config/webpack/ServerClientOrBoth.js` file:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
// config/webpack/ServerClientOrBoth.js
|
|
129
|
+
const rscWebpackConfig = require('./rscWebpackConfig');
|
|
130
|
+
// existing code...
|
|
131
|
+
|
|
132
|
+
const webpackConfig = (envSpecific) => {
|
|
133
|
+
const rscConfig = rscWebpackConfig();
|
|
134
|
+
// existing code...
|
|
135
|
+
} else if (process.env.RSC_BUNDLE_ONLY) {
|
|
136
|
+
// eslint-disable-next-line no-console
|
|
137
|
+
console.log('[React on Rails] Creating only the RSC bundle.');
|
|
138
|
+
result = rscConfig;
|
|
139
|
+
} else {
|
|
140
|
+
// default is the standard client and server build
|
|
141
|
+
// eslint-disable-next-line no-console
|
|
142
|
+
console.log('[React on Rails] Creating both client and server bundles.');
|
|
143
|
+
result = [clientConfig, serverConfig, rscConfig];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Finally, update `Procfile.dev` to generate the RSC bundle when running the development server:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
# Procfile.dev
|
|
154
|
+
# existing code...
|
|
155
|
+
|
|
156
|
+
rails-rsc-assets: HMR=true RSC_BUNDLE_ONLY=yes bin/shakapacker --watch
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This change will make the bundling process generate a new bundle named `rsc-bundle.js` in addition to the `server-bundle.js` and `client-bundle.js` bundles.
|
|
161
|
+
|
|
162
|
+
Then, we need to tell React on Rails to upload the `rsc-bundle.js` file to the renderer while uploading the server bundle.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
# config/initializers/react_on_rails.rb
|
|
166
|
+
ReactOnRailsPro.configure do |config|
|
|
167
|
+
config.rsc_bundle_js_file = "rsc-bundle.js"
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
4. Make the client bundle use the React Server Components plugin `react-on-rails-rsc/WebpackPlugin`, for more information about this plugin, you can check the [How React Server Components work](how-react-server-components-work.md) (It's better to read it after reading this article).
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
// config/webpack/clientWebpackConfig.js
|
|
175
|
+
const { RSCWebpackPlugin } = require('react-on-rails-rsc/WebpackPlugin');
|
|
176
|
+
// existing code...
|
|
177
|
+
|
|
178
|
+
const configureClient = () => {
|
|
179
|
+
// existing code...
|
|
180
|
+
|
|
181
|
+
config.plugins.push(new RSCWebpackPlugin({ isServer: false }));
|
|
182
|
+
|
|
183
|
+
return config;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
module.exports = configureClient;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
5. Make the server bundle use the React Server Components plugin `react-on-rails-rsc/WebpackPlugin`
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
// config/webpack/serverWebpackConfig.js
|
|
193
|
+
const { RSCWebpackPlugin } = require('react-on-rails-rsc/WebpackPlugin');
|
|
194
|
+
// existing code...
|
|
195
|
+
|
|
196
|
+
const configureServer = () => {
|
|
197
|
+
// existing code...
|
|
198
|
+
|
|
199
|
+
config.plugins.push(new RSCWebpackPlugin({ isServer: true }));
|
|
200
|
+
|
|
201
|
+
return config;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
module.exports = configureServer;
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Create a React Server Component
|
|
208
|
+
|
|
209
|
+
Create a new file `app/javascript/components/ReactServerComponent.js`:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
// app/javascript/components/ReactServerComponent.js
|
|
213
|
+
import React from 'react';
|
|
214
|
+
|
|
215
|
+
// Heavy libraries that won't be sent to the client
|
|
216
|
+
import moment from 'moment';
|
|
217
|
+
import lodash from 'lodash';
|
|
218
|
+
|
|
219
|
+
// Server components can use Node.js modules, access the server files, make database queries, etc.
|
|
220
|
+
import os from 'os';
|
|
221
|
+
|
|
222
|
+
// This async component demonstrates server-side functionality
|
|
223
|
+
async function ReactServerComponent() {
|
|
224
|
+
console.log('Hello from ReactServerComponent');
|
|
225
|
+
|
|
226
|
+
// Using moment.js for complex date calculations
|
|
227
|
+
const now = moment();
|
|
228
|
+
const nextWeek = moment().add(7, 'days');
|
|
229
|
+
const formattedDateRange = `${now.format('MMMM Do YYYY')} to ${nextWeek.format('MMMM Do YYYY')}`;
|
|
230
|
+
|
|
231
|
+
// Using lodash for data manipulation
|
|
232
|
+
const sampleArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
233
|
+
const chunks = lodash.chunk(sampleArray, 3);
|
|
234
|
+
|
|
235
|
+
// Getting system information using Node's os module
|
|
236
|
+
const serverInfo = {
|
|
237
|
+
platform: os.platform(),
|
|
238
|
+
type: os.type(),
|
|
239
|
+
release: os.release(),
|
|
240
|
+
uptime: Math.floor(os.uptime() / 3600), // Convert to hours
|
|
241
|
+
totalMemory: Math.floor(os.totalmem() / (1024 * 1024 * 1024)), // Convert to GB
|
|
242
|
+
freeMemory: Math.floor(os.freemem() / (1024 * 1024 * 1024)), // Convert to GB
|
|
243
|
+
cpus: os.cpus().length
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<div className="server-component-demo">
|
|
248
|
+
<h2>React Server Component Demo</h2>
|
|
249
|
+
|
|
250
|
+
<section>
|
|
251
|
+
<h3>Date Calculations (using moment.js)</h3>
|
|
252
|
+
<p>Date Range: {formattedDateRange}</p>
|
|
253
|
+
</section>
|
|
254
|
+
|
|
255
|
+
<section>
|
|
256
|
+
<h3>Array Manipulation (using lodash)</h3>
|
|
257
|
+
<div>
|
|
258
|
+
{chunks.map((chunk, index) => (
|
|
259
|
+
<div key={index}>
|
|
260
|
+
Chunk {index + 1}: {chunk.join(', ')}
|
|
261
|
+
</div>
|
|
262
|
+
))}
|
|
263
|
+
</div>
|
|
264
|
+
</section>
|
|
265
|
+
|
|
266
|
+
<section>
|
|
267
|
+
<h3>Server System Information (using Node.js os module)</h3>
|
|
268
|
+
<ul>
|
|
269
|
+
<li>Platform: {serverInfo.platform}</li>
|
|
270
|
+
<li>OS Type: {serverInfo.type}</li>
|
|
271
|
+
<li>OS Release: {serverInfo.release}</li>
|
|
272
|
+
<li>Server Uptime: {serverInfo.uptime} hours</li>
|
|
273
|
+
<li>Total Memory: {serverInfo.totalMemory} GB</li>
|
|
274
|
+
<li>Free Memory: {serverInfo.freeMemory} GB</li>
|
|
275
|
+
<li>CPU Cores: {serverInfo.cpus}</li>
|
|
276
|
+
</ul>
|
|
277
|
+
</section>
|
|
278
|
+
|
|
279
|
+
<div className="note">
|
|
280
|
+
<p><strong>Note:</strong> The heavy libraries (moment.js, lodash) and Node.js
|
|
281
|
+
modules (os) used in this component stay on the server and are not shipped
|
|
282
|
+
to the client, reducing the client bundle size significantly.</p>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export default ReactServerComponent;
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Create a React Server Component Page
|
|
293
|
+
|
|
294
|
+
Create a new file `app/javascript/packs/components/ReactServerComponentPage.jsx`:
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
// app/javascript/packs/components/ReactServerComponentPage.jsx
|
|
298
|
+
|
|
299
|
+
import React from 'react';
|
|
300
|
+
import ReactServerComponent from '../../components/ReactServerComponent';
|
|
301
|
+
|
|
302
|
+
const ReactServerComponentPage = () => {
|
|
303
|
+
return (
|
|
304
|
+
<div>
|
|
305
|
+
<ReactServerComponent />
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export default ReactServerComponentPage;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Register the React Server Component Page
|
|
314
|
+
|
|
315
|
+
If you enabled `auto_load_bundle` in your `config/initializers/react_on_rails.rb` file, you don't need to register the React Server Component Page. It will be registered automatically.
|
|
316
|
+
|
|
317
|
+
If you didn't enable `auto_load_bundle`, you need to register the React Server Component Page manually.
|
|
318
|
+
|
|
319
|
+
```js
|
|
320
|
+
// client/app/packs/server-bundle.js
|
|
321
|
+
import registerServerComponent from 'react-on-rails/registerServerComponent/server';
|
|
322
|
+
import ReactServerComponentPage from './components/ReactServerComponentPage';
|
|
323
|
+
|
|
324
|
+
registerServerComponent({
|
|
325
|
+
ReactServerComponentPage,
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
// client/app/packs/client-bundle.js
|
|
331
|
+
import registerServerComponent from 'react-on-rails/registerServerComponent/client';
|
|
332
|
+
|
|
333
|
+
registerServerComponent(
|
|
334
|
+
{ rscPayloadGenerationUrlPath: 'rsc_payload/' },
|
|
335
|
+
'ReactServerComponentPage',
|
|
336
|
+
);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
As you can see, server components are not registered using the `ReactOnRails.register` function. Instead, we use the `registerServerComponent` function to register the server component. Also, `registerServerComponent` has different options for the client bundle and the server bundle.
|
|
340
|
+
- For the server bundle, the component itself is passed to the `registerServerComponent` function, so the component is bundled into the server bundle.
|
|
341
|
+
- For the client bundle, we pass the component name as an argument to the `registerServerComponent` function, so the component is not bundled into the client bundle.
|
|
342
|
+
|
|
343
|
+
As you can see at [How React Server Components work](how-react-server-components-work.md):
|
|
344
|
+
- Server components are rendered on the client using the rsc payload not the component itself.
|
|
345
|
+
|
|
346
|
+
And as you can see at [React Server Components Rendering Flow](./rendering-flow.md):
|
|
347
|
+
- In the future, the server bundle will use the RSC payload to render the server component on the server side as well.
|
|
348
|
+
|
|
349
|
+
The `rscPayloadGenerationUrlPath` option will be explained in detail later in this document. For now, just know that it specifies the base URL path for React Server Component requests.
|
|
350
|
+
|
|
351
|
+
## Add the React Server Component Rendering URL Path to the Rails Routes
|
|
352
|
+
|
|
353
|
+
Add the following route to your `config/routes.rb` file:
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
# config/routes.rb
|
|
357
|
+
Rails.application.routes.draw do
|
|
358
|
+
rsc_payload_route
|
|
359
|
+
end
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
This will add the `/rsc_payload` path to the routes. This is the base URL path that will receive requests from the client to render the React Server Components. `rsc_payload_route` is explained in the [How React Server Components work](how-react-server-components-work.md) document.
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
## Add Route to the React Server Component Page
|
|
366
|
+
|
|
367
|
+
Add the following route to the `config/routes.rb` file:
|
|
368
|
+
|
|
369
|
+
```ruby
|
|
370
|
+
# config/routes.rb
|
|
371
|
+
Rails.application.routes.draw do
|
|
372
|
+
get "react_server_component_without_ssr", to: "pages#react_server_component_without_ssr"
|
|
373
|
+
end
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
This route will be used to render the React Server Component Page.
|
|
377
|
+
|
|
378
|
+
## Create the React Server Component Page View
|
|
379
|
+
|
|
380
|
+
Create a new file `app/views/pages/react_server_component_without_ssr.html.erb`:
|
|
381
|
+
|
|
382
|
+
```erb
|
|
383
|
+
<%= react_component("ReactServerComponentPage",
|
|
384
|
+
prerender: false,
|
|
385
|
+
trace: true,
|
|
386
|
+
id: "ReactServerComponentPage-react-component-0") %>
|
|
387
|
+
|
|
388
|
+
<h1>React Server Component without SSR</h1>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Run the Development Server
|
|
392
|
+
|
|
393
|
+
Run the development server:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
bin/dev
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Navigate to the React Server Component Page:
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
http://localhost:3000/react_server_component_without_ssr
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
You should see the React Server Component Page rendered in the browser.
|
|
406
|
+
|
|
407
|
+

|
|
408
|
+
|
|
409
|
+
## Checking the React Server Component Page
|
|
410
|
+
|
|
411
|
+
Looking at the network tab in your browser's developer tools, you'll notice that the React Server Component Page bundle `ReactServerComponentPage.js` is only 1.4KB in size (note that this is in development mode, so the bundle is not minified). Examining the bundle's contents reveals that it doesn't include the actual `ReactServerComponent` component code or any of its dependencies like `lodash` or `moment` libraries. This small bundle size demonstrates one of the key benefits of React Server Components - the ability to keep client-side JavaScript bundles minimal by executing component code on the server.
|
|
412
|
+
|
|
413
|
+

|
|
414
|
+
|
|
415
|
+
Also, by looking at the console, we can see the log
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
[SERVER] Hello from ReactServerComponent
|
|
419
|
+
```
|
|
420
|
+
The `[SERVER]` prefix indicates that the component was executed on the server side. The absence of any client-side logs confirms that no client-side rendering or hydration occurred. This demonstrates a key characteristic of React Server Components - they run exclusively on the server without requiring any JavaScript execution in the browser, leading to improved performance and reduced client-side bundle sizes.
|
|
421
|
+
|
|
422
|
+
## How the React Server Component Page is Rendered on Browser?
|
|
423
|
+
|
|
424
|
+
We can get the answer from the network tab in the browser's developer tools. We can see there is a fetch request to the `/rsc_payload/ReactServerComponentPage` path. This is the `rsc_payload` route that we added to the routes in the previous steps and it accepts the component name `ReactServerComponentPage` as a parameter.
|
|
425
|
+
|
|
426
|
+

|
|
427
|
+
|
|
428
|
+
If we click on the fetch request, we can see the response.
|
|
429
|
+
|
|
430
|
+

|
|
431
|
+
|
|
432
|
+
The response contains two main parts:
|
|
433
|
+
|
|
434
|
+
1. The React Server Component (RSC) payload - This is a special format designed by React for serializing server components and transmitting them to the client. The RSC payload includes:
|
|
435
|
+
- The component's rendered output
|
|
436
|
+
- Any data props that were passed to the client components
|
|
437
|
+
- References to client components that need to be hydrated
|
|
438
|
+
|
|
439
|
+
2. React on Rails metadata - Additional data needed by React on Rails for:
|
|
440
|
+
- Replaying server-side console logs in the client
|
|
441
|
+
- Error tracking and reporting
|
|
442
|
+
|
|
443
|
+
The RSC payload format and how React processes it is explained in detail in the [How React Server Components work](how-react-server-components-work.md) document.
|
|
444
|
+
|
|
445
|
+
## Next Steps
|
|
446
|
+
|
|
447
|
+
Now that you understand the basics of React Server Components, you can proceed to the next article: [Add Streaming and Interactivity to RSC Page](./add-streaming-and-interactivity.md) to learn how to enhance your RSC page with streaming capabilities and client-side interactivity.
|
|
448
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# React Server Components Glossary
|
|
2
|
+
|
|
3
|
+
### RSC (React Server Component)
|
|
4
|
+
A React architecture that allows components to execute exclusively on the server while streaming results to the client. Benefits include:
|
|
5
|
+
- Reduced client-side JavaScript
|
|
6
|
+
- Direct access to server resources
|
|
7
|
+
- Improved initial page load
|
|
8
|
+
- Better SEO
|
|
9
|
+
|
|
10
|
+
## Types of Components
|
|
11
|
+
|
|
12
|
+
### Server Components
|
|
13
|
+
Components that run exclusively on the server (not included in the client bundle). They can:
|
|
14
|
+
- Directly access server-side resources (databases, filesystems)
|
|
15
|
+
- Keep dependencies server-side
|
|
16
|
+
- Perform async operations
|
|
17
|
+
- Cannot contain state or browser-only APIs
|
|
18
|
+
|
|
19
|
+
For example:
|
|
20
|
+
```jsx
|
|
21
|
+
import fetch from "node-fetch";
|
|
22
|
+
|
|
23
|
+
async function ServerComponent() {
|
|
24
|
+
const data = await (await fetch("https://jsonplaceholder.org/posts/1")).json();
|
|
25
|
+
const databaseData = await getDatabaseData();
|
|
26
|
+
return (
|
|
27
|
+
<div>
|
|
28
|
+
<h1>{data.title}</h1>
|
|
29
|
+
<p>{data.body}</p>
|
|
30
|
+
<p>{databaseData}</p>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Client Components
|
|
38
|
+
Components marked with `'use client'` directive that run on client. They can contain state, effects, and event handlers. These components get hydrated in the browser.
|
|
39
|
+
|
|
40
|
+
For example:
|
|
41
|
+
```jsx
|
|
42
|
+
function ClientComponent() {
|
|
43
|
+
const [count, setCount] = useState(0);
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<p>Count: {count}</p>
|
|
47
|
+
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Note: Server components can import client components, but client components cannot import server components. However, server components can be passed as props to client components.
|
|
54
|
+
|
|
55
|
+
For example:
|
|
56
|
+
```jsx
|
|
57
|
+
function ParentServerComponent() {
|
|
58
|
+
return <ClientComponent serverComponent={<ServerComponent />} />;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Bundle Related
|
|
63
|
+
|
|
64
|
+
### React Server Components Bundle (RSC Bundle) (usually `rsc-bundle.js`)
|
|
65
|
+
A new server-side bundle introduced by React Server Components. It contains server components and their dependencies only. It doesn't include client components. It should be the same as the `server_bundle.js` bundle. But it uses the `react-on-rails-rsc/WebpackLoader` loader to trim the client components from the bundle.
|
|
66
|
+
|
|
67
|
+
### Client Bundle
|
|
68
|
+
The JavaScript bundle that runs in the browser, containing client components and their dependencies. This bundle is responsible for hydration and client-side interactivity.
|
|
69
|
+
|
|
70
|
+
## Concepts
|
|
71
|
+
|
|
72
|
+
### Flight Format (RSC Format)
|
|
73
|
+
The wire format used by React Server Components to stream component data from server to client. It's a compact binary format that represents the component tree and its data.
|
|
74
|
+
|
|
75
|
+
### Hydration
|
|
76
|
+
The process where React attaches event handlers and state to server-rendered HTML in the browser. With RSC, hydration happens selectively only for Client Components.
|
|
77
|
+
|
|
78
|
+
### RSC Payload (Flight Payload)
|
|
79
|
+
The serialized output of server components that gets streamed to the client. Contains:
|
|
80
|
+
- React render tree of the server component
|
|
81
|
+
- References to client components that need hydration
|
|
82
|
+
- Data for client components
|
|
83
|
+
|
|
84
|
+
### Selective Hydration
|
|
85
|
+
A feature where client components can hydrate independently and in parallel, allowing for:
|
|
86
|
+
- Progressive interactivity
|
|
87
|
+
- Prioritized hydration of visible components
|
|
88
|
+
- Better performance on slower devices
|
|
89
|
+
|
|
90
|
+
### Streaming
|
|
91
|
+
The ability to progressively send server component renders to the client before all data is ready. Benefits include:
|
|
92
|
+
- Faster Time to First Byte (TTFB)
|
|
93
|
+
- Progressive rendering of content
|
|
94
|
+
- Better user experience during slow data fetches
|
|
95
|
+
|
|
96
|
+
## Technical
|
|
97
|
+
|
|
98
|
+
### Client Component Manifest
|
|
99
|
+
A JSON file mapping component paths to their corresponding JavaScript chunks. Used by RSC to determine which client-side code to load for hydration.
|
|
100
|
+
|
|
101
|
+
### RSC URL Path
|
|
102
|
+
The endpoint path where RSC requests are handled, defaulting to "rsc_payload/" in the React on Rails Pro configuration.
|