react_on_rails_pro 16.2.0.test.6 → 16.2.0
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 +4 -4
- data/.prettierignore +3 -0
- data/.rubocop.yml +7 -90
- data/CHANGELOG.md +16 -7
- data/CONTRIBUTING.md +64 -43
- data/Gemfile.development_dependencies +4 -4
- data/Gemfile.loader +11 -8
- data/Gemfile.lock +147 -124
- data/README.md +1 -1
- data/docs/bundle-caching.md +22 -8
- data/docs/caching.md +39 -27
- data/docs/code-splitting-loadable-components.md +71 -55
- data/docs/code-splitting.md +74 -70
- data/docs/configuration.md +6 -6
- data/docs/contributors-info/onboarding-customers.md +2 -1
- data/docs/contributors-info/releasing.md +1 -0
- data/docs/contributors-info/style.md +23 -15
- data/docs/home-pro.md +33 -15
- data/docs/installation.md +57 -9
- data/docs/js-memory-leaks.md +2 -3
- data/docs/node-renderer/debugging.md +5 -1
- data/docs/node-renderer/error-reporting-and-tracing.md +27 -15
- data/docs/node-renderer/heroku.md +4 -5
- data/docs/profiling-server-side-rendering-code.md +43 -42
- data/docs/react-server-components/add-streaming-and-interactivity.md +1 -1
- data/docs/react-server-components/create-without-ssr.md +18 -18
- data/docs/react-server-components/glossary.md +22 -3
- data/docs/react-server-components/how-react-server-components-work.md +25 -18
- data/docs/react-server-components/inside-client-components.md +19 -18
- data/docs/react-server-components/purpose-and-benefits.md +24 -14
- data/docs/react-server-components/rendering-flow.md +7 -3
- data/docs/react-server-components/server-side-rendering.md +23 -22
- data/docs/release-notes/4.0.md +103 -94
- data/docs/release-notes/v4-react-server-components.md +16 -16
- data/docs/streaming-server-rendering.md +2 -4
- data/docs/troubleshooting.md +5 -2
- data/docs/updating.md +55 -20
- data/lib/react_on_rails_pro/request.rb +18 -3
- data/lib/react_on_rails_pro/version.rb +1 -1
- data/rakelib/dummy_apps.rake +4 -4
- data/rakelib/lint.rake +1 -1
- data/rakelib/run_rspec.rake +3 -3
- metadata +4 -4
data/docs/installation.md
CHANGED
|
@@ -47,16 +47,15 @@ Set your license token as an environment variable:
|
|
|
47
47
|
export REACT_ON_RAILS_PRO_LICENSE="your-license-token-here"
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Or
|
|
50
|
+
Or create a config file at `config/react_on_rails_pro_license.key`:
|
|
51
51
|
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
ReactOnRailsPro.configure do |config|
|
|
55
|
-
config.license_token = ENV["REACT_ON_RAILS_PRO_LICENSE"]
|
|
56
|
-
end
|
|
52
|
+
```bash
|
|
53
|
+
echo "your-license-token-here" > config/react_on_rails_pro_license.key
|
|
57
54
|
```
|
|
58
55
|
|
|
59
|
-
⚠️ **Security Warning**: Never commit your license token to version control.
|
|
56
|
+
⚠️ **Security Warning**: Never commit your license token to version control. Add `config/react_on_rails_pro_license.key` to your `.gitignore`. For production, use environment variables or secure secret management systems (Rails credentials, Heroku config vars, AWS Secrets Manager, etc.).
|
|
57
|
+
|
|
58
|
+
For complete license setup instructions, see [LICENSE_SETUP.md](../LICENSE_SETUP.md).
|
|
60
59
|
|
|
61
60
|
## Rails Configuration
|
|
62
61
|
|
|
@@ -72,9 +71,58 @@ ReactOnRailsPro.configure do |config|
|
|
|
72
71
|
end
|
|
73
72
|
```
|
|
74
73
|
|
|
75
|
-
#
|
|
74
|
+
# Client Package Installation
|
|
75
|
+
|
|
76
|
+
All React on Rails Pro users need to install the `react-on-rails-pro` npm package for client-side React integration.
|
|
77
|
+
|
|
78
|
+
## Install react-on-rails-pro
|
|
79
|
+
|
|
80
|
+
### Using npm:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install react-on-rails-pro
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Using yarn:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
yarn add react-on-rails-pro
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Using pnpm:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pnpm add react-on-rails-pro
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Usage
|
|
99
|
+
|
|
100
|
+
**Important:** Import from `react-on-rails-pro`, not `react-on-rails`. The Pro package re-exports everything from the core package plus Pro-exclusive features.
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// Correct - use react-on-rails-pro
|
|
104
|
+
import ReactOnRails from 'react-on-rails-pro';
|
|
105
|
+
|
|
106
|
+
// Register components
|
|
107
|
+
ReactOnRails.register({ MyComponent });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Pro-exclusive imports:
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// React Server Components
|
|
114
|
+
import { RSCRoute } from 'react-on-rails-pro/RSCRoute';
|
|
115
|
+
import registerServerComponent from 'react-on-rails-pro/registerServerComponent/client';
|
|
116
|
+
|
|
117
|
+
// Async component loading
|
|
118
|
+
import { wrapServerComponentRenderer } from 'react-on-rails-pro/wrapServerComponentRenderer/client';
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
See the [React Server Components tutorial](./react-server-components/tutorial.md) for detailed usage.
|
|
122
|
+
|
|
123
|
+
# Node Renderer Installation
|
|
76
124
|
|
|
77
|
-
**Note:** You only need to install the Node
|
|
125
|
+
**Note:** You only need to install the Node Renderer if you are using the standalone node renderer (`NodeRenderer`). If you're using `ExecJS` (the default), skip this section.
|
|
78
126
|
|
|
79
127
|
## Install react-on-rails-pro-node-renderer
|
|
80
128
|
|
data/docs/js-memory-leaks.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# JS Memory Leaks
|
|
2
2
|
|
|
3
3
|
## Finding Memory Leaks
|
|
4
|
+
|
|
4
5
|
For memory leaks, see [node-memwatch](https://github.com/marcominetti/node-memwatch). Use the `—inspect` flag to make and compare heap snapshots.
|
|
5
6
|
|
|
6
7
|
## Causes of Memory Leaks
|
|
7
8
|
|
|
8
|
-
|
|
9
9
|
### Mobx (mobx-react)
|
|
10
10
|
|
|
11
11
|
```js
|
|
@@ -18,5 +18,4 @@ const App = (props, railsContext) => {
|
|
|
18
18
|
useStaticRendering(true);
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
- See details here: [Mobx site](https://github.com/mobxjs/mobx-react#server-side-rendering-with-usestaticrendering)
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
Because the renderer communicates over a port to the server, you can start a renderer instance in this repo and hack on it.
|
|
2
2
|
|
|
3
3
|
# Yalc vs Yarn Link
|
|
4
|
+
|
|
4
5
|
The project is setup to use [yalc](https://github.com/whitecolor/yalc). This means that at the top level
|
|
5
|
-
directory, `yalc publish` will send the node package files to the global yalc store. Running `yarn` in the
|
|
6
|
+
directory, `yalc publish` will send the node package files to the global yalc store. Running `yarn` in the
|
|
6
7
|
`/spec/dummy/client` directory will copy the files from the global yalc store over to the local `node_modules`
|
|
7
8
|
directory.
|
|
8
9
|
|
|
9
10
|
# Debugging the Node Renderer
|
|
11
|
+
|
|
10
12
|
1. cd to the top level of the project.
|
|
11
13
|
1. `yarn` to install any libraries.
|
|
12
14
|
1. To compile renderer files on changes, open console and run `yarn build:dev`.
|
|
@@ -17,9 +19,11 @@ directory.
|
|
|
17
19
|
1. Check out the top level nps task `nps renderer.debug` and `spec/dummy/package.json` which has script `"node-renderer-debug"`.
|
|
18
20
|
|
|
19
21
|
## Debugging using the Node debugger
|
|
22
|
+
|
|
20
23
|
1. See [this article](https://github.com/shakacode/react_on_rails/issues/1196) on setting up the debugger.
|
|
21
24
|
|
|
22
25
|
## Debugging Jest tests
|
|
26
|
+
|
|
23
27
|
1. See [the Jest documentation](https://jestjs.io/docs/troubleshooting) for overall guidance.
|
|
24
28
|
2. For RubyMine, see [the RubyMine documentation](https://www.jetbrains.com/help/ruby/running-unit-tests-on-jest.html) for the current information. The original [Testing With Jest in WebStorm](https://blog.jetbrains.com/webstorm/2018/10/testing-with-jest-in-webstorm/) post can be useful as well.
|
|
25
29
|
|
|
@@ -13,8 +13,8 @@ It should initialize the services according to your requirements and then enable
|
|
|
13
13
|
2. Call `Sentry.init` with the desired options according to [the documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/configuration/).
|
|
14
14
|
3. Then load the integration:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
```js
|
|
17
|
+
require('react-on-rails-pro-node-renderer/integrations/sentry').init();
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- Use `react-on-rails-pro-node-renderer/integrations/sentry6` instead of `.../sentry` for versions of Sentry SDK older than 7.63.0.
|
|
@@ -22,12 +22,13 @@ It should initialize the services according to your requirements and then enable
|
|
|
22
22
|
|
|
23
23
|
### Sentry Tracing
|
|
24
24
|
|
|
25
|
-
To enable Sentry Tracing:
|
|
25
|
+
To enable Sentry Tracing:
|
|
26
|
+
|
|
26
27
|
1. Include `enableTracing`, `tracesSampleRate`, or `tracesSampler` in your `Sentry.init` call. See [the Sentry documentation](https://docs.sentry.io/platforms/javascript/tracing/) for details, but ignore `Sentry.browserTracingIntegration()`.
|
|
27
|
-
2. Depending on your Sentry SDK version:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
2. Depending on your Sentry SDK version:
|
|
29
|
+
- if it is older than 7.63.0, install `@sentry/tracing` as well as `@sentry/node` (with the same exact version) and pass `integrations: [new Sentry.Integrations.Http({ tracing: true })]` to `Sentry.init`.
|
|
30
|
+
- for newer v7.x.y, pass `integrations: Sentry.autoDiscoverNodePerformanceMonitoringIntegrations()`.
|
|
31
|
+
- for v8.x.y, Node HTTP tracing is included by default.
|
|
31
32
|
3. Pass `{ tracing: true }` to the `init` function of the integration. It can be combined with `fastify: true`.
|
|
32
33
|
|
|
33
34
|
### Sentry Profiling
|
|
@@ -39,13 +40,14 @@ To enable Sentry Tracing:
|
|
|
39
40
|
1. [Set up Honeybadger](https://docs.honeybadger.io/lib/javascript/integration/node/). Call `Honeybadger.configure` with the desired options in the configuration script.
|
|
40
41
|
2. Then load the integration:
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
```js
|
|
44
|
+
require('react-on-rails-pro-node-renderer/integrations/honeybadger').init();
|
|
45
|
+
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
Use `init({ fastify: true })` to capture additional Fastify-related information.
|
|
47
48
|
|
|
48
49
|
## Other services
|
|
50
|
+
|
|
49
51
|
You can create your own integrations in the same way as the provided ones.
|
|
50
52
|
If you have access to the React on Rails Pro repository,
|
|
51
53
|
you can use [their implementations](https://github.com/shakacode/react_on_rails_pro/tree/master/packages/node-renderer/src/integrations) as examples.
|
|
@@ -57,13 +59,18 @@ Import these functions from `react-on-rails-pro-node-renderer/integrations/api`:
|
|
|
57
59
|
- Use `addNotifier` if the service uses the same reporting function for both JavaScript `Error`s and string messages.
|
|
58
60
|
|
|
59
61
|
For example, integrating with BugSnag can be as simple as
|
|
62
|
+
|
|
60
63
|
```js
|
|
61
64
|
const Bugsnag = require('@bugsnag/js');
|
|
62
65
|
const { addNotifier } = require('react-on-rails-pro-node-renderer/integrations/api');
|
|
63
66
|
|
|
64
|
-
Bugsnag.start({
|
|
67
|
+
Bugsnag.start({
|
|
68
|
+
/* your options */
|
|
69
|
+
});
|
|
65
70
|
|
|
66
|
-
addNotifier((msg) => {
|
|
71
|
+
addNotifier((msg) => {
|
|
72
|
+
Bugsnag.notify(msg);
|
|
73
|
+
});
|
|
67
74
|
```
|
|
68
75
|
|
|
69
76
|
### Tracing services
|
|
@@ -74,11 +81,14 @@ addNotifier((msg) => { Bugsnag.notify(msg); });
|
|
|
74
81
|
|
|
75
82
|
To track requests as [sessions](https://docs.bugsnag.com/platforms/javascript/capturing-sessions/#startsession) in BugSnag 8.x+,
|
|
76
83
|
the above example becomes
|
|
84
|
+
|
|
77
85
|
```js
|
|
78
86
|
const Bugsnag = require('@bugsnag/js');
|
|
79
87
|
const { addNotifier, setupTracing } = require('react-on-rails-pro-node-renderer/integrations/api');
|
|
80
88
|
|
|
81
|
-
Bugsnag.start({
|
|
89
|
+
Bugsnag.start({
|
|
90
|
+
/* your options */
|
|
91
|
+
});
|
|
82
92
|
|
|
83
93
|
addNotifier((msg) => {
|
|
84
94
|
Bugsnag.notify(msg);
|
|
@@ -119,7 +129,9 @@ Bugsnag v7 is a bit more complicated:
|
|
|
119
129
|
const Bugsnag = require('@bugsnag/js');
|
|
120
130
|
const { addNotifier, setupTracing } = require('react-on-rails-pro-node-renderer/integrations/api');
|
|
121
131
|
|
|
122
|
-
Bugsnag.start({
|
|
132
|
+
Bugsnag.start({
|
|
133
|
+
/* your options */
|
|
134
|
+
});
|
|
123
135
|
|
|
124
136
|
addNotifier((msg, { bugsnag = Bugsnag }) => {
|
|
125
137
|
bugsnag.notify(msg);
|
|
@@ -34,10 +34,12 @@ renderer: bin/node-renderer
|
|
|
34
34
|
cd client
|
|
35
35
|
yarn run node-renderer
|
|
36
36
|
```
|
|
37
|
+
|
|
37
38
|
Be sure your script to run the node-renderer sets some port, like 3800 which is also set as the
|
|
38
39
|
config.renderer_url for your Rails server.
|
|
39
40
|
|
|
40
41
|
### node-renderer
|
|
42
|
+
|
|
41
43
|
Any task in client/package.json that starts the node-renderer
|
|
42
44
|
|
|
43
45
|
### Modifying Precompile Task
|
|
@@ -76,14 +78,13 @@ Errno::EADDRINUSE: Address already in use - bind(2) for "0.0.0.0" port 21752
|
|
|
76
78
|
/app/vendor/bundle/ruby/2.6.0/gems/puma-4.3.3/lib/puma/binder.rb:229:in `initialize'
|
|
77
79
|
```
|
|
78
80
|
|
|
79
|
-
|
|
80
81
|
## Separate Rails and Node Render Instances
|
|
81
82
|
|
|
82
83
|
### Deploy Node renderer to Heroku
|
|
83
84
|
|
|
84
85
|
1. Create your **Heroku** app with **Node.js** buildpack, say `renderer-test.herokuapp.com`.
|
|
85
86
|
2. In your JS configuration file or
|
|
86
|
-
1. If setting the port, ensure the port uses `process.env.PORT` so it will use port number provided by **Heroku** environment. The default is to use the env value RENDERER_PORT if available.
|
|
87
|
+
1. If setting the port, ensure the port uses `process.env.PORT` so it will use port number provided by **Heroku** environment. The default is to use the env value `RENDERER_PORT` if available.
|
|
87
88
|
2. Set password in your configuration to something like `process.env.RENDERER_PASSWORD` and configure the corresponding **ENV variable** on your **Heroku** dyno so the `config/initializers/react_on_rails_pro.rb` uses this value.
|
|
88
89
|
3. Run deployment process (usually by pushing changes to **Git** repo associated with created **Heroku** app).
|
|
89
90
|
4. Once deployment process is finished, renderer should start listening from something like `renderer-test.herokuapp.com` host.
|
|
@@ -95,8 +96,6 @@ Errno::EADDRINUSE: Address already in use - bind(2) for "0.0.0.0" port 21752
|
|
|
95
96
|
3. Run deployment process (usually by pushing changes to **Git** repo associated with created **Heroku** app).
|
|
96
97
|
4. Once deployment process is finished, all rendering requests form your `react_on_rails` app should be served by `<your-heroku-app>.herokuapp.com` app via **HTTPS**.
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
99
|
## References
|
|
101
100
|
|
|
102
|
-
|
|
101
|
+
- [Heroku Node Settings](https://github.com/damianmr/heroku-node-settings)
|
|
@@ -7,53 +7,53 @@ This guide uses the RORP dummy app in profiling the server-side code.
|
|
|
7
7
|
## Profiling Server-Side Code Running On Node Renderer
|
|
8
8
|
|
|
9
9
|
1. Run node-renderer using the `--inspect` node option.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
|
|
11
|
+
Open the `spec/dummy/Procfile.dev` file and update the `node-renderer` process to run the renderer using `node --inspect` command. Change the following line
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
node-renderer: RENDERER_LOG_LEVEL=debug yarn run node-renderer
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
To
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=3800 node --inspect client/node-renderer.js
|
|
21
|
+
```
|
|
22
22
|
|
|
23
23
|
1. Run the App
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bin/dev
|
|
27
|
+
```
|
|
28
28
|
|
|
29
29
|
1. Visit `chrome://inspect` on Chrome browser and you should see something like this:
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
|
|
31
|
+

|
|
32
32
|
|
|
33
33
|
1. Click the `inspect` link. This should open a developer tools window. Open the performance tab there
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
|
|
35
|
+

|
|
36
36
|
|
|
37
37
|
1. Click the `record` button
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+

|
|
40
40
|
|
|
41
41
|
1. Open the web app you want to test and refresh it multiple times. We use the React on Rails Pro dummy app for this tutorial. So, we will open it in the browser by going to [http://localhost:3000](http://localhost:3000)
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
|
|
43
|
+

|
|
44
44
|
|
|
45
45
|
1. If you get any `Timeout Error` while visiting the page, you may need to increase the `ssr_timeout` in the Ruby on Rails initializer file. **Running node-renderer** using the `--inspect` flag makes it slower. So, you can increase the `ssr_timeout` to `10 seconds` by adding the following line to `config/initializers/react_on_rails_pro.rb` file
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
config.ssr_timeout = 10
|
|
49
|
+
```
|
|
50
50
|
|
|
51
51
|
1. Stop performance recording
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
|
|
53
|
+

|
|
54
54
|
|
|
55
55
|
1. You should see something like this
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|

|
|
58
58
|
|
|
59
59
|
## Profile Analysis
|
|
@@ -89,24 +89,25 @@ config.prerender_caching = false
|
|
|
89
89
|
To see the renderer behavior while there are many requests coming to it, you can use the `ApacheBench (ab)` tool that lets you make many HTTP requests to a specific end points at the same time.
|
|
90
90
|
|
|
91
91
|
1. The `ApacheBench (ab)` is installed on macOS by default. You can install it on Linux by running the following command
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
sudo apt-get install apache2-utils
|
|
95
|
+
```
|
|
96
96
|
|
|
97
97
|
1. Do all steps in `Profiling Server-Side Code Running On Node Renderer` section except the step number 6. Instead of opening the page in the browser, let the `ab` tool make many HTTP requests for you by running the following command.
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
ab -n 100 -c 10 http://localhost:3000/
|
|
101
|
-
```
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
```bash
|
|
100
|
+
ab -n 100 -c 10 http://localhost:3000/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
1. Now, when you open the node-renderer profile, you will see it very busy responding to all requests
|
|
104
|
+
|
|
105
|
+

|
|
106
106
|
|
|
107
107
|
1. Then, you can analyze the renderer behavior of each request as stated in `Profile Analysis` section.
|
|
108
108
|
|
|
109
109
|
### ExecJS
|
|
110
|
+
|
|
110
111
|
React on Rails Pro supports profiling with ExecJS starting from version **4.0.0**. You will need to do more work to profile ExecJS if you are using an older version.
|
|
111
112
|
|
|
112
113
|
If you are using **v4.0.0** or later, you can enable the profiler by setting the `profile_server_rendering_js_code` config by adding the following line to the ReactOnRails initializer.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Before reading this document, please read the [Create React Server Component without SSR](./create-without-ssr.md) document.
|
|
4
4
|
|
|
5
5
|
## Make the React Server Component Page Progressively Load
|
|
6
|
+
|
|
6
7
|
React Server Components support progressive loading, which means they can be built as asynchronous functions that resolve and render after the initial HTML is sent to the client. This enables a better user experience by:
|
|
7
8
|
|
|
8
9
|
1. Showing initial content quickly while async data loads;
|
|
@@ -163,7 +164,6 @@ It's important to note that while client components (like `ToggleContainer`) can
|
|
|
163
164
|
|
|
164
165
|
This pattern allows us to optimize performance by keeping most of the component logic on the server while selectively adding interactivity where needed on the client.
|
|
165
166
|
|
|
166
|
-
|
|
167
167
|
## Checking The Network Requests
|
|
168
168
|
|
|
169
169
|
Let's check what bundles are being loaded for this page. By opening the browser's developer tools and going to the "Network" tab, you can see JavaScript bundles being loaded for this page.
|
|
@@ -40,12 +40,12 @@ end
|
|
|
40
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
41
|
>
|
|
42
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
|
+
>
|
|
43
44
|
> - `useState` or other state hooks
|
|
44
45
|
> - `useEffect` or other effect hooks
|
|
45
46
|
> - Event handlers (onClick, onChange, etc.)
|
|
46
47
|
> - Browser APIs
|
|
47
48
|
|
|
48
|
-
|
|
49
49
|
For example:
|
|
50
50
|
|
|
51
51
|
```js
|
|
@@ -55,7 +55,6 @@ For example:
|
|
|
55
55
|
// ... existing code ...
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
|
|
59
58
|
3. Create a new Webpack configuration to generate React Server Components bundles (RSC bundles) (usually named `rsc-bundle.js`).
|
|
60
59
|
|
|
61
60
|
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.
|
|
@@ -63,6 +62,7 @@ RSC bundle is a clone of the server bundle `server-bundle.js` but we just add th
|
|
|
63
62
|
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
63
|
|
|
65
64
|
Create a new file `config/webpack/rscWebpackConfig.js`:
|
|
65
|
+
|
|
66
66
|
```js
|
|
67
67
|
// use the same config as serverWebpackConfig.js but add the RSC loader
|
|
68
68
|
const serverWebpackConfig = require('./serverWebpackConfig');
|
|
@@ -95,7 +95,7 @@ const configureRsc = () => {
|
|
|
95
95
|
const rules = rscConfig.module.rules;
|
|
96
96
|
rules.forEach((rule) => {
|
|
97
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.
|
|
98
|
+
// Ensure this loader runs before the JS loader (Babel loader in this case) to properly exclude client components from the RSC bundle.
|
|
99
99
|
// If your project uses a different JS loader, insert it before that loader instead.
|
|
100
100
|
const babelLoader = extractLoader(rule, 'babel-loader');
|
|
101
101
|
if (babelLoader) {
|
|
@@ -240,13 +240,13 @@ async function ReactServerComponent() {
|
|
|
240
240
|
uptime: Math.floor(os.uptime() / 3600), // Convert to hours
|
|
241
241
|
totalMemory: Math.floor(os.totalmem() / (1024 * 1024 * 1024)), // Convert to GB
|
|
242
242
|
freeMemory: Math.floor(os.freemem() / (1024 * 1024 * 1024)), // Convert to GB
|
|
243
|
-
cpus: os.cpus().length
|
|
243
|
+
cpus: os.cpus().length,
|
|
244
244
|
};
|
|
245
245
|
|
|
246
246
|
return (
|
|
247
247
|
<div className="server-component-demo">
|
|
248
248
|
<h2>React Server Component Demo</h2>
|
|
249
|
-
|
|
249
|
+
|
|
250
250
|
<section>
|
|
251
251
|
<h3>Date Calculations (using moment.js)</h3>
|
|
252
252
|
<p>Date Range: {formattedDateRange}</p>
|
|
@@ -277,16 +277,17 @@ async function ReactServerComponent() {
|
|
|
277
277
|
</section>
|
|
278
278
|
|
|
279
279
|
<div className="note">
|
|
280
|
-
<p
|
|
281
|
-
|
|
282
|
-
|
|
280
|
+
<p>
|
|
281
|
+
<strong>Note:</strong> The heavy libraries (moment.js, lodash) and Node.js modules (os) used in this
|
|
282
|
+
component stay on the server and are not shipped to the client, reducing the client bundle size
|
|
283
|
+
significantly.
|
|
284
|
+
</p>
|
|
283
285
|
</div>
|
|
284
286
|
</div>
|
|
285
287
|
);
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
export default ReactServerComponent;
|
|
289
|
-
|
|
290
291
|
```
|
|
291
292
|
|
|
292
293
|
## Create a React Server Component Page
|
|
@@ -318,7 +319,7 @@ If you didn't enable `auto_load_bundle`, you need to register the React Server C
|
|
|
318
319
|
|
|
319
320
|
```js
|
|
320
321
|
// client/app/packs/server-bundle.js
|
|
321
|
-
import registerServerComponent from 'react-on-rails/registerServerComponent/server';
|
|
322
|
+
import registerServerComponent from 'react-on-rails-pro/registerServerComponent/server';
|
|
322
323
|
import ReactServerComponentPage from './components/ReactServerComponentPage';
|
|
323
324
|
|
|
324
325
|
registerServerComponent({
|
|
@@ -328,22 +329,22 @@ registerServerComponent({
|
|
|
328
329
|
|
|
329
330
|
```js
|
|
330
331
|
// client/app/packs/client-bundle.js
|
|
331
|
-
import registerServerComponent from 'react-on-rails/registerServerComponent/client';
|
|
332
|
+
import registerServerComponent from 'react-on-rails-pro/registerServerComponent/client';
|
|
332
333
|
|
|
333
|
-
registerServerComponent(
|
|
334
|
-
{ rscPayloadGenerationUrlPath: 'rsc_payload/' },
|
|
335
|
-
'ReactServerComponentPage',
|
|
336
|
-
);
|
|
334
|
+
registerServerComponent({ rscPayloadGenerationUrlPath: 'rsc_payload/' }, 'ReactServerComponentPage');
|
|
337
335
|
```
|
|
338
336
|
|
|
339
337
|
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.
|
|
338
|
+
|
|
340
339
|
- For the server bundle, the component itself is passed to the `registerServerComponent` function, so the component is bundled into the server bundle.
|
|
341
340
|
- 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
341
|
|
|
343
342
|
As you can see at [How React Server Components work](how-react-server-components-work.md):
|
|
343
|
+
|
|
344
344
|
- Server components are rendered on the client using the rsc payload not the component itself.
|
|
345
345
|
|
|
346
346
|
And as you can see at [React Server Components Rendering Flow](./rendering-flow.md):
|
|
347
|
+
|
|
347
348
|
- In the future, the server bundle will use the RSC payload to render the server component on the server side as well.
|
|
348
349
|
|
|
349
350
|
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.
|
|
@@ -361,7 +362,6 @@ end
|
|
|
361
362
|
|
|
362
363
|
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
|
|
|
364
|
-
|
|
365
365
|
## Add Route to the React Server Component Page
|
|
366
366
|
|
|
367
367
|
Add the following route to the `config/routes.rb` file:
|
|
@@ -380,7 +380,7 @@ This route will be used to render the React Server Component Page.
|
|
|
380
380
|
Create a new file `app/views/pages/react_server_component_without_ssr.html.erb`:
|
|
381
381
|
|
|
382
382
|
```erb
|
|
383
|
-
<%= react_component("ReactServerComponentPage",
|
|
383
|
+
<%= react_component("ReactServerComponentPage",
|
|
384
384
|
prerender: false,
|
|
385
385
|
trace: true,
|
|
386
386
|
id: "ReactServerComponentPage-react-component-0") %>
|
|
@@ -417,6 +417,7 @@ Also, by looking at the console, we can see the log
|
|
|
417
417
|
```
|
|
418
418
|
[SERVER] Hello from ReactServerComponent
|
|
419
419
|
```
|
|
420
|
+
|
|
420
421
|
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
|
|
|
422
423
|
## How the React Server Component Page is Rendered on Browser?
|
|
@@ -445,4 +446,3 @@ The RSC payload format and how React processes it is explained in detail in the
|
|
|
445
446
|
## Next Steps
|
|
446
447
|
|
|
447
448
|
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
|
-
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# React Server Components Glossary
|
|
2
2
|
|
|
3
3
|
### RSC (React Server Component)
|
|
4
|
+
|
|
4
5
|
A React architecture that allows components to execute exclusively on the server while streaming results to the client. Benefits include:
|
|
6
|
+
|
|
5
7
|
- Reduced client-side JavaScript
|
|
6
8
|
- Direct access to server resources
|
|
7
9
|
- Improved initial page load
|
|
@@ -10,18 +12,21 @@ A React architecture that allows components to execute exclusively on the server
|
|
|
10
12
|
## Types of Components
|
|
11
13
|
|
|
12
14
|
### Server Components
|
|
15
|
+
|
|
13
16
|
Components that run exclusively on the server (not included in the client bundle). They can:
|
|
17
|
+
|
|
14
18
|
- Directly access server-side resources (databases, filesystems)
|
|
15
19
|
- Keep dependencies server-side
|
|
16
20
|
- Perform async operations
|
|
17
21
|
- Cannot contain state or browser-only APIs
|
|
18
22
|
|
|
19
23
|
For example:
|
|
24
|
+
|
|
20
25
|
```jsx
|
|
21
|
-
import fetch from
|
|
26
|
+
import fetch from 'node-fetch';
|
|
22
27
|
|
|
23
28
|
async function ServerComponent() {
|
|
24
|
-
const data = await (await fetch(
|
|
29
|
+
const data = await (await fetch('https://jsonplaceholder.org/posts/1')).json();
|
|
25
30
|
const databaseData = await getDatabaseData();
|
|
26
31
|
return (
|
|
27
32
|
<div>
|
|
@@ -33,11 +38,12 @@ async function ServerComponent() {
|
|
|
33
38
|
}
|
|
34
39
|
```
|
|
35
40
|
|
|
36
|
-
|
|
37
41
|
### Client Components
|
|
42
|
+
|
|
38
43
|
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
44
|
|
|
40
45
|
For example:
|
|
46
|
+
|
|
41
47
|
```jsx
|
|
42
48
|
function ClientComponent() {
|
|
43
49
|
const [count, setCount] = useState(0);
|
|
@@ -53,6 +59,7 @@ function ClientComponent() {
|
|
|
53
59
|
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
60
|
|
|
55
61
|
For example:
|
|
62
|
+
|
|
56
63
|
```jsx
|
|
57
64
|
function ParentServerComponent() {
|
|
58
65
|
return <ClientComponent serverComponent={<ServerComponent />} />;
|
|
@@ -62,33 +69,43 @@ function ParentServerComponent() {
|
|
|
62
69
|
## Bundle Related
|
|
63
70
|
|
|
64
71
|
### React Server Components Bundle (RSC Bundle) (usually `rsc-bundle.js`)
|
|
72
|
+
|
|
65
73
|
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
74
|
|
|
67
75
|
### Client Bundle
|
|
76
|
+
|
|
68
77
|
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
78
|
|
|
70
79
|
## Concepts
|
|
71
80
|
|
|
72
81
|
### Flight Format (RSC Format)
|
|
82
|
+
|
|
73
83
|
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
84
|
|
|
75
85
|
### Hydration
|
|
86
|
+
|
|
76
87
|
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
88
|
|
|
78
89
|
### RSC Payload (Flight Payload)
|
|
90
|
+
|
|
79
91
|
The serialized output of server components that gets streamed to the client. Contains:
|
|
92
|
+
|
|
80
93
|
- React render tree of the server component
|
|
81
94
|
- References to client components that need hydration
|
|
82
95
|
- Data for client components
|
|
83
96
|
|
|
84
97
|
### Selective Hydration
|
|
98
|
+
|
|
85
99
|
A feature where client components can hydrate independently and in parallel, allowing for:
|
|
100
|
+
|
|
86
101
|
- Progressive interactivity
|
|
87
102
|
- Prioritized hydration of visible components
|
|
88
103
|
- Better performance on slower devices
|
|
89
104
|
|
|
90
105
|
### Streaming
|
|
106
|
+
|
|
91
107
|
The ability to progressively send server component renders to the client before all data is ready. Benefits include:
|
|
108
|
+
|
|
92
109
|
- Faster Time to First Byte (TTFB)
|
|
93
110
|
- Progressive rendering of content
|
|
94
111
|
- Better user experience during slow data fetches
|
|
@@ -96,7 +113,9 @@ The ability to progressively send server component renders to the client before
|
|
|
96
113
|
## Technical
|
|
97
114
|
|
|
98
115
|
### Client Component Manifest
|
|
116
|
+
|
|
99
117
|
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
118
|
|
|
101
119
|
### RSC URL Path
|
|
120
|
+
|
|
102
121
|
The endpoint path where RSC requests are handled, defaulting to "rsc_payload/" in the React on Rails Pro configuration.
|