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/code-splitting.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Server-side rendering with code-splitting in React on Rails
|
|
2
|
+
|
|
2
3
|
by ShakaCode
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
_Last updated June 13, 2019_
|
|
5
6
|
|
|
6
7
|
# Deprecated
|
|
7
8
|
|
|
@@ -21,14 +22,16 @@ If the project includes server rendering, then you need to exclude the use of dy
|
|
|
21
22
|
# Dependencies
|
|
22
23
|
|
|
23
24
|
Install following libraries in client folder:
|
|
25
|
+
|
|
24
26
|
```
|
|
25
27
|
yarn add react-loadable webpack-conditional-loader
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
- [react-loadable](https://github.com/jamiebuilds/react-loadable) - take cares of loading and correctly displaying our dynamic components.
|
|
29
|
-
- [webpack-conditional-loader](https://www.npmjs.com/package/webpack-conditional-loader) - allow us conditionally extract parts of our code into different bundles.
|
|
31
|
+
- [webpack-conditional-loader](https://www.npmjs.com/package/webpack-conditional-loader) - allow us conditionally extract parts of our code into different bundles.
|
|
30
32
|
|
|
31
33
|
Add `webpack-conditional-loader` to the loaders, like this:
|
|
34
|
+
|
|
32
35
|
```js
|
|
33
36
|
{
|
|
34
37
|
test: /\.jsx?$/,
|
|
@@ -45,6 +48,7 @@ Add `webpack-conditional-loader` to the loaders, like this:
|
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
Optionally. Create alias for `DynamicImports.js` file in `resolve`:
|
|
51
|
+
|
|
48
52
|
```js
|
|
49
53
|
alias: {
|
|
50
54
|
DynamicImports: path.resolve(__dirname, 'client', 'DynamicImports.js'),
|
|
@@ -54,6 +58,7 @@ alias: {
|
|
|
54
58
|
# Simple example of using dynamic components
|
|
55
59
|
|
|
56
60
|
Consider the component that we want to convert to a dynamic:
|
|
61
|
+
|
|
57
62
|
```
|
|
58
63
|
components
|
|
59
64
|
|_ Map
|
|
@@ -61,6 +66,7 @@ components
|
|
|
61
66
|
```
|
|
62
67
|
|
|
63
68
|
Let's create `index.jsx` in `Map` directory with the following contents:
|
|
69
|
+
|
|
64
70
|
```jsx
|
|
65
71
|
let Component = null;
|
|
66
72
|
|
|
@@ -84,16 +90,16 @@ import Loadable from 'react-loadable';
|
|
|
84
90
|
|
|
85
91
|
import Loading from '../Loading';
|
|
86
92
|
|
|
87
|
-
const load = opts =>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
const load = (opts) =>
|
|
94
|
+
Loadable({
|
|
95
|
+
delay: 10000,
|
|
96
|
+
loading: () => <Loading />,
|
|
97
|
+
render(loaded, props) {
|
|
98
|
+
const LoadedComponent = loaded.default;
|
|
99
|
+
return <LoadedComponent {...props} />;
|
|
100
|
+
},
|
|
101
|
+
...opts,
|
|
102
|
+
});
|
|
97
103
|
|
|
98
104
|
/* Here we're wrapping our component in react-loadable HOC */
|
|
99
105
|
const DynamicComponent = load({
|
|
@@ -101,7 +107,7 @@ const DynamicComponent = load({
|
|
|
101
107
|
We need to specify these params: `webpackChunkName`, `modules` and `webpack`
|
|
102
108
|
so react-loadable can load our chunk correctly
|
|
103
109
|
*/
|
|
104
|
-
loader: () => import(/* webpackChunkName: "Map" */'./Map'),
|
|
110
|
+
loader: () => import(/* webpackChunkName: "Map" */ './Map'),
|
|
105
111
|
modules: ['./Map'],
|
|
106
112
|
webpack: () => [require.resolveWeak('./Map')],
|
|
107
113
|
});
|
|
@@ -116,12 +122,15 @@ export default Component;
|
|
|
116
122
|
```
|
|
117
123
|
|
|
118
124
|
Now, if we want to use this component we should import it like this:
|
|
125
|
+
|
|
119
126
|
```jsx
|
|
120
|
-
import Map from './components/Map'
|
|
127
|
+
import Map from './components/Map';
|
|
121
128
|
```
|
|
129
|
+
|
|
122
130
|
in this case, webpack will load `index.jsx` instead of `Map.jsx` if not some other special order specified.
|
|
123
131
|
|
|
124
132
|
Also, `IS_SSR=true` must added when creating server side bundle, like this:
|
|
133
|
+
|
|
125
134
|
```
|
|
126
135
|
NODE_ENV=production IS_SSR=true webpack --config webpack.config.ssr.prod.js
|
|
127
136
|
```
|
|
@@ -141,33 +150,34 @@ More details can be found in the documentation react-loadable.
|
|
|
141
150
|
|
|
142
151
|
But we can get rid of annoying flickering `Loading ...` the first time the page loads. The server renderer has already rendered the necessary components. Therefore, we can transfer this information from the server renderer to the client and preload the necessary modules.
|
|
143
152
|
|
|
144
|
-
Unfortunately, the way specified in the documentation `react-loadable` does not work for us.
|
|
153
|
+
Unfortunately, the way specified in the documentation `react-loadable` does not work for us.
|
|
145
154
|
|
|
146
155
|
Here is another similar method.
|
|
147
156
|
|
|
148
157
|
For this we use the function `registerDynamicComponentOnServer`. We will place it in the new file `DynamicImports.js`:
|
|
149
158
|
|
|
150
|
-
|
|
151
159
|
```javascript
|
|
152
|
-
export const registerDynamicComponentOnServer = name => {
|
|
153
|
-
const serverSide = typeof window === 'undefined'
|
|
160
|
+
export const registerDynamicComponentOnServer = (name) => {
|
|
161
|
+
const serverSide = typeof window === 'undefined';
|
|
154
162
|
|
|
155
163
|
if (serverSide) {
|
|
156
164
|
if (typeof global.dynamicComponents === 'undefined') {
|
|
157
|
-
global.dynamicComponents = []
|
|
165
|
+
global.dynamicComponents = [];
|
|
158
166
|
}
|
|
159
167
|
if (global.dynamicComponents.indexOf(name) === -1) {
|
|
160
|
-
global.dynamicComponents.push(name)
|
|
168
|
+
global.dynamicComponents.push(name);
|
|
161
169
|
}
|
|
162
170
|
}
|
|
163
|
-
}
|
|
171
|
+
};
|
|
164
172
|
```
|
|
173
|
+
|
|
165
174
|
As you can see from the function body, it runs only for server-side rendering.
|
|
166
175
|
It simply adds the name of the component to the global array `dynamicComponents` which will be transferred to the client later.
|
|
167
176
|
|
|
168
177
|
It must be imported into the component that needs to be made dynamic and called in the render method of this component. For example:
|
|
169
178
|
|
|
170
179
|
components/Map/Map.jsx:
|
|
180
|
+
|
|
171
181
|
```javascript
|
|
172
182
|
...
|
|
173
183
|
import { registerDynamicComponentOnServer } from 'DynamicImports';
|
|
@@ -182,39 +192,33 @@ class Map extends React.Component {
|
|
|
182
192
|
}
|
|
183
193
|
```
|
|
184
194
|
|
|
185
|
-
|
|
186
195
|
Then this global array must be passed to the client.
|
|
187
196
|
To do this, change server entry point as follows:
|
|
188
197
|
|
|
189
|
-
|
|
190
198
|
**ServerApp.js**:
|
|
199
|
+
|
|
191
200
|
```javascript
|
|
192
201
|
import React from 'react';
|
|
193
|
-
import ReactOnRails from 'react-on-rails';
|
|
202
|
+
import ReactOnRails from 'react-on-rails-pro';
|
|
194
203
|
|
|
195
204
|
import App from './App';
|
|
196
205
|
|
|
197
206
|
const ServerApp = (props, railsContext) => {
|
|
198
|
-
|
|
199
|
-
const html = renderToString(
|
|
200
|
-
<App
|
|
201
|
-
{...props}
|
|
202
|
-
components={{ MainPage, AboutPage }}
|
|
203
|
-
/>
|
|
204
|
-
);
|
|
207
|
+
const html = renderToString(<App {...props} components={{ MainPage, AboutPage }} />);
|
|
205
208
|
|
|
206
209
|
return {
|
|
207
210
|
html,
|
|
208
211
|
dynamicComponents: JSON.stringify(global.dynamicComponents),
|
|
209
212
|
};
|
|
210
|
-
}
|
|
213
|
+
};
|
|
211
214
|
|
|
212
|
-
ReactOnRails.register({ App: ServerApp })
|
|
215
|
+
ReactOnRails.register({ App: ServerApp });
|
|
213
216
|
|
|
214
|
-
export default ServerApp
|
|
217
|
+
export default ServerApp;
|
|
215
218
|
```
|
|
216
219
|
|
|
217
220
|
And add our array to view in rails, where our react_component is displayed
|
|
221
|
+
|
|
218
222
|
```slim
|
|
219
223
|
<% component = react_component("App", props: {}, prerender: true) %>
|
|
220
224
|
|
|
@@ -237,90 +241,87 @@ To do this, we will create an object with the component names as the keys, and t
|
|
|
237
241
|
We will add it to `DynamicImports.js` and add a check for the presence of the registered component in this object in the function` registerDynamicComponentOnServer`:
|
|
238
242
|
|
|
239
243
|
**DynamicImports.js**
|
|
244
|
+
|
|
240
245
|
```javascript
|
|
241
246
|
const DynamicImports = {
|
|
242
|
-
Map: () => import('./components/Map')
|
|
243
|
-
}
|
|
247
|
+
Map: () => import('./components/Map'),
|
|
248
|
+
};
|
|
244
249
|
|
|
245
|
-
export const registerDynamicComponentOnServer = name => {
|
|
246
|
-
const serverSide = typeof window === 'undefined'
|
|
250
|
+
export const registerDynamicComponentOnServer = (name) => {
|
|
251
|
+
const serverSide = typeof window === 'undefined';
|
|
247
252
|
|
|
248
253
|
if (serverSide) {
|
|
249
254
|
if (typeof global.dynamicComponents === 'undefined') {
|
|
250
|
-
global.dynamicComponents = []
|
|
255
|
+
global.dynamicComponents = [];
|
|
251
256
|
}
|
|
252
257
|
if (typeof DynamicImports[name] === 'undefined') {
|
|
253
|
-
throw new Error(`Dynamic import not defined for ${name}`)
|
|
258
|
+
throw new Error(`Dynamic import not defined for ${name}`);
|
|
254
259
|
}
|
|
255
260
|
if (global.dynamicComponents.indexOf(name) === -1) {
|
|
256
|
-
global.dynamicComponents.push(name)
|
|
261
|
+
global.dynamicComponents.push(name);
|
|
257
262
|
}
|
|
258
263
|
}
|
|
259
|
-
}
|
|
264
|
+
};
|
|
260
265
|
|
|
261
|
-
export default DynamicImports
|
|
266
|
+
export default DynamicImports;
|
|
262
267
|
```
|
|
263
268
|
|
|
264
269
|
Now we can load the component we need, knowing its name
|
|
265
270
|
For example:
|
|
271
|
+
|
|
266
272
|
```javascript
|
|
267
|
-
DynamicImports
|
|
273
|
+
DynamicImports['Map']();
|
|
268
274
|
```
|
|
275
|
+
|
|
269
276
|
This function will return Promise, which can be used for client rendering.
|
|
270
277
|
|
|
271
278
|
Change the Client.js to add the preloading of the required components:
|
|
272
279
|
|
|
273
|
-
|
|
274
280
|
**Client.js**
|
|
281
|
+
|
|
275
282
|
```javascript
|
|
276
283
|
import React from 'react';
|
|
277
284
|
import { hydrateRoot } from 'react-dom/client';
|
|
278
|
-
import Loadable from 'react-loadable'
|
|
285
|
+
import Loadable from 'react-loadable';
|
|
279
286
|
|
|
280
287
|
import App from './App';
|
|
281
288
|
|
|
282
|
-
import DynamicImports from 'DynamicImports'
|
|
289
|
+
import DynamicImports from 'DynamicImports';
|
|
283
290
|
|
|
284
291
|
const App = (props, railsContext, domNodeId) => {
|
|
285
|
-
|
|
286
292
|
const dynamicComponents =
|
|
287
|
-
typeof window.dynamicComponents !== 'undefined'
|
|
288
|
-
? JSON.parse(window.dynamicComponents)
|
|
289
|
-
: []
|
|
290
|
-
|
|
293
|
+
typeof window.dynamicComponents !== 'undefined' ? JSON.parse(window.dynamicComponents) : [];
|
|
291
294
|
|
|
292
|
-
const dynamicImports = []
|
|
293
|
-
dynamicComponents.map(name => {
|
|
294
|
-
const dynamicImportInvoked = DynamicImports[name]()
|
|
295
|
-
dynamicImports.push(dynamicImportInvoked)
|
|
296
|
-
})
|
|
295
|
+
const dynamicImports = [];
|
|
296
|
+
dynamicComponents.map((name) => {
|
|
297
|
+
const dynamicImportInvoked = DynamicImports[name]();
|
|
298
|
+
dynamicImports.push(dynamicImportInvoked);
|
|
299
|
+
});
|
|
297
300
|
|
|
298
301
|
Promise.all(dynamicImports)
|
|
299
302
|
.then(() => Loadable.preloadReady())
|
|
300
303
|
.then(() => {
|
|
301
304
|
hydrateRoot(
|
|
302
|
-
<App
|
|
303
|
-
{...props}
|
|
304
|
-
components={{ MainPage, AboutPage }}
|
|
305
|
-
/>,
|
|
305
|
+
<App {...props} components={{ MainPage, AboutPage }} />,
|
|
306
306
|
document.getElementById(domNodeId),
|
|
307
|
-
)
|
|
308
|
-
})
|
|
309
|
-
}
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
310
|
|
|
311
|
-
export default App
|
|
311
|
+
export default App;
|
|
312
312
|
```
|
|
313
313
|
|
|
314
314
|
This code requires explanation.
|
|
315
315
|
|
|
316
316
|
The array with names of rendered components called `dynamicComponents` is used in the map function.
|
|
317
317
|
In this function, the dynamic import invoked and the result (promise) is added to `dynamicImports` array.
|
|
318
|
+
|
|
318
319
|
```javascript
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
320
|
+
const dynamicImports = [];
|
|
321
|
+
dynamicComponents.map((name) => {
|
|
322
|
+
const dynamicImportInvoked = DynamicImports[name]();
|
|
323
|
+
dynamicImports.push(dynamicImportInvoked);
|
|
324
|
+
});
|
|
324
325
|
```
|
|
325
326
|
|
|
326
327
|
This array is used in the function `Promise.all`
|
|
@@ -334,16 +335,19 @@ Then fires `Loadable.preloadReady()`
|
|
|
334
335
|
```javascript
|
|
335
336
|
.then(() => Loadable.preloadReady())
|
|
336
337
|
```
|
|
338
|
+
|
|
337
339
|
As in the doc:
|
|
338
340
|
Check for modules that are already loaded in the browser and call the matching LoadableComponent.preload methods.
|
|
339
341
|
|
|
340
342
|
We need to call this method to initialize already preloaded components.
|
|
341
343
|
|
|
342
344
|
In addition, note that in the creation of dynamic modules, the `modules` and` webpack` options are used, per the docs for react-loadable.
|
|
345
|
+
|
|
343
346
|
```javascript
|
|
344
347
|
modules: ['./AboutPage'],
|
|
345
348
|
webpack: () => [require.resolveWeak('./AboutPage')],
|
|
346
349
|
```
|
|
350
|
+
|
|
347
351
|
They are needed to make .preload method work properly
|
|
348
352
|
|
|
349
353
|
Thus, all dynamic modules will be loaded up to hydrate, and there will be no flicker.
|
data/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
`config/initializers/react_on_rails_pro.rb`
|
|
3
|
+
`config/initializers/react_on_rails_pro.rb`
|
|
4
4
|
|
|
5
5
|
1. You don't need to create a initializer if you are satisfied with the defaults as described below.
|
|
6
6
|
1. Values beginning with `renderer` pertain only to using an external rendering server. You will need to ensure these values are consistent with your configuration for the external rendering server, as given in [JS configuration](https://www.shakacode.com/react-on-rails-pro/docs/node-renderer/js-configuration/)
|
|
@@ -32,12 +32,12 @@ ReactOnRailsPro.configure do |config|
|
|
|
32
32
|
# Remote bundle caching saves deployment time by caching bundles.
|
|
33
33
|
# See /docs/bundle-caching.md for usage and an example of a module called S3BundleCacheAdapter.
|
|
34
34
|
config.remote_bundle_cache_adapter = nil
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
# ALL OPTIONS BELOW ONLY APPLY IF SERVER RENDERING
|
|
37
37
|
|
|
38
38
|
# If true, then cache the evaluation of JS for prerendering using the standard Rails cache.
|
|
39
39
|
# Applies to all rendering engines.
|
|
40
|
-
# Default for `prerender_caching` is false.
|
|
40
|
+
# Default for `prerender_caching` is false.
|
|
41
41
|
config.prerender_caching = true
|
|
42
42
|
|
|
43
43
|
# Retry request in case of time out on the node-renderer side
|
|
@@ -77,9 +77,9 @@ ReactOnRailsPro.configure do |config|
|
|
|
77
77
|
# config.renderer_password = ENV["RENDERER_PASSWORD"]
|
|
78
78
|
|
|
79
79
|
# Set the `ssr_timeout` configuration so the Rails server will not wait more than this many seconds
|
|
80
|
-
# for a SSR request to return once issued.
|
|
80
|
+
# for a SSR request to return once issued.
|
|
81
81
|
config.ssr_timeout = 5
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
# If false, then crash if no backup rendering when the remote renderer is not available
|
|
84
84
|
# Can be useful to set to false in development or testing to make sure that the remote renderer
|
|
85
85
|
# works and any non-availability of the remote renderer does not just do ExecJS.
|
|
@@ -103,7 +103,7 @@ ReactOnRailsPro.configure do |config|
|
|
|
103
103
|
config.renderer_http_pool_warn_timeout = 0.25 # seconds
|
|
104
104
|
|
|
105
105
|
# Snippet of JavaScript to be run right at the beginning of the server rendering process. The code
|
|
106
|
-
# to be executed must either be self contained or reference some globally exposed module.
|
|
106
|
+
# to be executed must either be self contained or reference some globally exposed module.
|
|
107
107
|
# For example, suppose that we had to call `SomeLibrary.clearCache()`between every call to server
|
|
108
108
|
# renderer to ensure no leakage of state between calls. Note, SomeLibrary needs to be globally
|
|
109
109
|
# exposed in the server rendering webpack bundle. This code is visible in the tracing of the calls
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Creating a github OAuth Token
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
_[Document for ShakaCode Staff](https://docs.google.com/document/d/10snzXEWgkorcai76_OxlhjQcDae_WoxRfBCdVbmcQoU/edit)_
|
|
4
4
|
|
|
5
5
|
# Customer Steps
|
|
6
|
+
|
|
6
7
|
See [Installation](../installation.md).
|
|
@@ -1,33 +1,41 @@
|
|
|
1
1
|
# Code Style
|
|
2
|
+
|
|
2
3
|
This document describes the coding style of [ShakaCode](http://www.shakacode.com). Yes, it's opinionated, as all style guidelines should be. We shall put as little as possible into this guide and instead rely on:
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
- Use of linters with our standard linter configuration.
|
|
6
|
+
- References to existing style guidelines that support the linter configuration.
|
|
7
|
+
- Anything additional goes next.
|
|
7
8
|
|
|
8
9
|
## Client Side JavaScript and React
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
- See the [Shakacode JavaScript Style Guide](https://github.com/shakacode/style-guide-javascript)
|
|
10
12
|
|
|
11
13
|
## Style Guides to Follow
|
|
14
|
+
|
|
12
15
|
Follow these style guidelines per the linter configuration. Basically, lint your code and if you have questions about the suggested fixes, look here:
|
|
13
16
|
|
|
14
17
|
### Ruby Coding Standards
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
- [ShakaCode Ruby Coding Standards](https://github.com/shakacode/style-guide-ruby)
|
|
20
|
+
- [Ruby Documentation](http://guides.rubyonrails.org/api_documentation_guidelines.html)
|
|
17
21
|
|
|
18
22
|
### JavaScript Coding Standards
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
- [ShakaCode Javascript](https://github.com/shakacode/style-guide-javascript)
|
|
25
|
+
- Use the [eslint-config-shakacode](https://github.com/shakacode/style-guide-javascript/tree/master/packages/eslint-config-shakacode) npm package with eslint.
|
|
26
|
+
- [JSDoc](http://usejsdoc.org/)
|
|
22
27
|
|
|
23
28
|
### Git coding Standards
|
|
24
|
-
|
|
29
|
+
|
|
30
|
+
- [Git Coding Standards](http://chlg.co/1GV2m9p)
|
|
25
31
|
|
|
26
32
|
### Sass Coding Standards
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
|
|
34
|
+
- [Sass Guidelines](http://sass-guidelin.es/) by [Hugo Giraudel](http://hugogiraudel.com/)
|
|
35
|
+
- [GitHub Front End Guidelines](http://primercss.io/guidelines/)
|
|
29
36
|
|
|
30
37
|
# Git Usage
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
|
|
39
|
+
- Follow a github-flow model where you branch off of master for features.
|
|
40
|
+
- Before merging a branch to master, rebase it on top of master, by using command like `git fetch; git checkout my-branch; git rebase -i origin/master`. Clean up your commit message at this point. Be super careful to communicate with anybody else working on this branch and do not do this when others have uncommitted changes. Ideally, your merge of your feature back to master should be one nice commit.
|
|
41
|
+
- Run hosted CI and code coverage.
|
data/docs/home-pro.md
CHANGED
|
@@ -3,67 +3,77 @@
|
|
|
3
3
|
Node rendering and caching performance enhancements for [React on Rails](https://github.com/shakacode/react_on_rails). Now supports React 18 with updates to React on Rails! Check the [React on Rails CHANGELOG.md](https://github.com/shakacode/react_on_rails/blob/master/CHANGELOG.md) for details and the updates to the [loadable-components instructions](https://github.com/shakacode/react_on_rails_pro/blob/master/docs/code-splitting-loadable-components.md).
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
|
+
|
|
6
7
|
The best way to see how React on Rails Pro works is to install this repo locally and take a look at
|
|
7
8
|
the example application:
|
|
8
9
|
|
|
9
|
-
[spec/dummy](https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/README.md)
|
|
10
|
+
[spec/dummy](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/README.md)
|
|
11
|
+
|
|
10
12
|
1. Uses a @rails/webpacker standard configuration.
|
|
11
13
|
1. Has pages that demonstrate:
|
|
12
14
|
1. caching
|
|
13
15
|
2. loadable-components
|
|
14
|
-
1. Has all the basic react_on_rails specs that run against the Node Renderer
|
|
16
|
+
1. Has all the basic react_on_rails specs that run against the Node Renderer
|
|
15
17
|
1. Demonstrates using HMR and loadable-components with almost the same example that is present in [loadable-components for SSR](https://github.com/gregberge/loadable-components/tree/main/examples/server-side-rendering)
|
|
16
|
-
|
|
18
|
+
|
|
17
19
|
See the README.md in those sample apps for more details.
|
|
18
20
|
|
|
19
21
|
## Features
|
|
20
22
|
|
|
21
23
|
### 🚀 Next-Gen Server Rendering: Streaming with React 18's Latest APIs
|
|
24
|
+
|
|
22
25
|
React on Rails Pro supports React 18's Streaming Server-Side Rendering, allowing you to progressively render and stream HTML content to the client. This enables faster page loads and better user experience.
|
|
23
26
|
|
|
24
27
|
See [docs/streaming-server-rendering](./streaming-server-rendering.md) for more details.
|
|
25
28
|
|
|
26
29
|
### Caching
|
|
30
|
+
|
|
27
31
|
Caching of SSR is critical for achieving optimum performance.
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
- **Fragment Caching**: for `react_component` and `react_component_hash`, including lazy evaluation of props.
|
|
34
|
+
- **Prerender Caching**: Server rendering JavaScript evaluation is cached if `prerender_caching` is turned on in your Rails config. This applies to all JavaScript evaluation methods.
|
|
31
35
|
|
|
32
36
|
See [docs/caching](./caching.md) for more details.
|
|
33
37
|
|
|
34
38
|
### Clearing of Global State
|
|
39
|
+
|
|
35
40
|
Suppose you detect that some library used in server-rendering is leaking state between calls to server render. In that case, you can set the `config.ssr_pre_hook_js` in your `config/initializers/react_on_rails_pro.rb` to run some JavaScript to clear the globally leaked state at the beginning of each call to server render.
|
|
36
41
|
|
|
37
|
-
For more details, see [Rails Configuration](https://github.com/shakacode/react_on_rails/blob/master/docs/configuration.md).
|
|
42
|
+
For more details, see [Rails Configuration](https://github.com/shakacode/react_on_rails/blob/master/docs/configuration/configuration.md).
|
|
38
43
|
|
|
39
44
|
### React On Rails Pro Node Renderer
|
|
45
|
+
|
|
40
46
|
The "React on Rails Pro Node Renderer" provides more efficient server rendering on a standalone Node JS server.
|
|
41
47
|
See the [Node Renderer Docs](./node-renderer/basics.md).
|
|
42
48
|
|
|
43
49
|
### Bundle Caching
|
|
50
|
+
|
|
44
51
|
Don't wait for the same webpack bundles to be built over and over. See the [bundle-caching docs](./bundle-caching.md).
|
|
45
52
|
|
|
46
53
|
## Other Utility Methods
|
|
54
|
+
|
|
47
55
|
See the [Ruby API](./ruby-api.md).
|
|
48
56
|
|
|
49
57
|
## References
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
- [Installation](./installation.md)
|
|
60
|
+
- [Streaming Server Rendering](./streaming-server-rendering.md)
|
|
61
|
+
- [Caching](./caching.md)
|
|
62
|
+
- [Rails Configuration](./configuration.md)
|
|
63
|
+
- [Node Renderer Docs](./node-renderer/basics.md)
|
|
56
64
|
|
|
57
65
|
# Features
|
|
66
|
+
|
|
58
67
|
## Code Splitting
|
|
59
68
|
|
|
60
69
|
From [The Cost of JavaScript in 2018](https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4):
|
|
61
70
|
|
|
62
71
|
> To stay fast, only load JavaScript needed for the current page. Prioritize what a user will need and lazy-load the rest with code-splitting. This gives you the best chance at loading and getting interactive fast. Stacks with route-based code-splitting by default are game-changers.
|
|
63
72
|
|
|
64
|
-
|
|
65
73
|
## Caching
|
|
74
|
+
|
|
66
75
|
### Server Rendering
|
|
76
|
+
|
|
67
77
|
Server rendering of JavaScript evaluation is cached if `prerender_caching` is turned on in your Rails config. This applies to all JavaScript evaluation methods, including ExecJS and the Node VM Renderer.
|
|
68
78
|
|
|
69
79
|
### Pro: Fragment Caching
|
|
@@ -90,24 +100,31 @@ Note, even without server rendering (without step 3 above), fragment caching is
|
|
|
90
100
|
See [Caching](./caching.md) for more additional details.
|
|
91
101
|
|
|
92
102
|
## React On Rails Pro Node React Render
|
|
103
|
+
|
|
93
104
|
The "React on Rails Pro Node React Renderer" provides more efficient React Server Side Rendering on a standalone Node JS server.
|
|
94
105
|
|
|
95
106
|
### Overall Management Memory and CPU on both the Rendering and Ruby Servers
|
|
107
|
+
|
|
96
108
|
A separate Node rendering server is easier to manage in terms of monitoring memory and CPU performance, allocating dynos, etc. This also makes it easier to manage the ruby servers, as you no longer have to consider the impact of starting an embedded V8. Thus, you can never hang your Ruby servers due to JavaScript memory leaks.
|
|
97
109
|
|
|
98
110
|
### Proper Node Tooling
|
|
111
|
+
|
|
99
112
|
A disadvantage of Ruby embedded JavaScript (ExecJS) is that it precludes the use of standard Node tooling for doing things like profiling and tracking down memory leaks. With the renderer on a separate Node.js server, we were able to use node-memwatch (https://github.com/marcominetti/node-memwatch) to find few memory leaks in the Egghead React code.
|
|
100
113
|
|
|
101
114
|
### Caching of React Rendering
|
|
115
|
+
|
|
102
116
|
To limit the load on the renderer server or embedded ExecJS, caching of React rendering requests can be enabled by a config setting. Because current React rendering requests are idempotent (same value regardless of calls), caching should be feasible for all server rendering calls. The current renderer does not allow any asynchronous calls to fetch data. The rendering request includes all data for rendering.
|
|
103
117
|
|
|
104
118
|
### Rolling Restart of Node Workers
|
|
119
|
+
|
|
105
120
|
Due to poor performance and crashes due to memory leaks, the rolling restart of node workers was thus added as an option to the core rendering product. This option is cheap insurance against the renderer getting too slow from a memory leak due to a bug in some newly deployed JavaScript code.
|
|
106
121
|
|
|
107
122
|
### Docs
|
|
123
|
+
|
|
108
124
|
See the [Node React Render Docs](./node-renderer/basics.md).
|
|
109
125
|
|
|
110
126
|
## Other Utility Methods
|
|
127
|
+
|
|
111
128
|
See the [Ruby API](./ruby-api.md).
|
|
112
129
|
|
|
113
130
|
# Testimonials
|
|
@@ -121,9 +138,10 @@ For details, see [Egghead React on Rails Pro Deployment Highlights](https://gith
|
|
|
121
138
|
|
|
122
139
|
## Why should I use React on Rails Pro if ExecJS seems to work?
|
|
123
140
|
|
|
124
|
-
Caching is extremely useful to any server rendering you're doing, with or without ExecJS.
|
|
141
|
+
Caching is extremely useful to any server rendering you're doing, with or without ExecJS.
|
|
125
142
|
|
|
126
143
|
React on Rails pro support caching at 2 levels:
|
|
144
|
+
|
|
127
145
|
1. Caching of rendering request to ExecJS (or the Node renderer). This avoids extra calls to ExecJS.
|
|
128
146
|
2. Fragment caching of server rendering. This avoids even the calculations of prop values from the database and the cost of converting the props to a string (lots of CPU there)
|
|
129
147
|
|
|
@@ -142,5 +160,5 @@ For more info, email [justin@shakacode.com](mailto:justin@shakacode.com).
|
|
|
142
160
|
|
|
143
161
|
# References
|
|
144
162
|
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
- [Caching](./caching.md)
|
|
164
|
+
- [Rails Configuration](./configuration.md)
|