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,349 @@
|
|
|
1
|
+
# Server-side rendering with code-splitting in React on Rails
|
|
2
|
+
by ShakaCode
|
|
3
|
+
|
|
4
|
+
*Last updated June 13, 2019*
|
|
5
|
+
|
|
6
|
+
# Deprecated
|
|
7
|
+
|
|
8
|
+
**Please, see [our new documentation on how to setup code splitting with loadable components](./code-splitting-loadable-components.md).**
|
|
9
|
+
|
|
10
|
+
# Introduction
|
|
11
|
+
|
|
12
|
+
Webpack has an interesting feature called dynamic code-splitting, which automatically breaks the bundle into parts where the `import ()` function is used.
|
|
13
|
+
|
|
14
|
+
For more convenient work with `import ()` there are libraries like react-loadable.
|
|
15
|
+
It provides a special function by which you can turn any react component into a dynamic component.
|
|
16
|
+
|
|
17
|
+
To use react-loadable in the react on rails project, you do not need to take any additional action until the server-side rendering is used.
|
|
18
|
+
|
|
19
|
+
If the project includes server rendering, then you need to exclude the use of dynamic imports on the server-rendering side. I.e. it needs to generate a server bundle in which contains statically imported components only. This is due to how the ExecJS renderer and the node-renderer cannot use promises.
|
|
20
|
+
|
|
21
|
+
# Dependencies
|
|
22
|
+
|
|
23
|
+
Install following libraries in client folder:
|
|
24
|
+
```
|
|
25
|
+
yarn add react-loadable webpack-conditional-loader
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- [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.
|
|
30
|
+
|
|
31
|
+
Add `webpack-conditional-loader` to the loaders, like this:
|
|
32
|
+
```js
|
|
33
|
+
{
|
|
34
|
+
test: /\.jsx?$/,
|
|
35
|
+
use: {
|
|
36
|
+
use: [{
|
|
37
|
+
loader: 'babel-loader',
|
|
38
|
+
options: {
|
|
39
|
+
cacheDirectory: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}, 'webpack-conditional-loader'],
|
|
43
|
+
exclude: /node_modules/,
|
|
44
|
+
},
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Optionally. Create alias for `DynamicImports.js` file in `resolve`:
|
|
48
|
+
```js
|
|
49
|
+
alias: {
|
|
50
|
+
DynamicImports: path.resolve(__dirname, 'client', 'DynamicImports.js'),
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
# Simple example of using dynamic components
|
|
55
|
+
|
|
56
|
+
Consider the component that we want to convert to a dynamic:
|
|
57
|
+
```
|
|
58
|
+
components
|
|
59
|
+
|_ Map
|
|
60
|
+
|_Map.jsx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Let's create `index.jsx` in `Map` directory with the following contents:
|
|
64
|
+
```jsx
|
|
65
|
+
let Component = null;
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
the comments `#if` that you see below is a C-like conditional directive
|
|
69
|
+
used by webpack-conditional-loader. This condition tells webpack's loader
|
|
70
|
+
to use only one specific code depends on existence of `IS_SSR` env variable
|
|
71
|
+
So, when `IS_SSR` variable is present, webpack-conditional-loader comments out the
|
|
72
|
+
code in `#if process.env.IS_SSR !== 'true' .... #end` clause before processing this
|
|
73
|
+
file by babel-loader.
|
|
74
|
+
*/
|
|
75
|
+
// #if process.env.IS_SSR === 'true'
|
|
76
|
+
import StaticComponent from './Map';
|
|
77
|
+
|
|
78
|
+
Component = StaticComponent;
|
|
79
|
+
// #endif
|
|
80
|
+
|
|
81
|
+
// #if process.env.IS_SSR !== 'true'
|
|
82
|
+
import React from 'react';
|
|
83
|
+
import Loadable from 'react-loadable';
|
|
84
|
+
|
|
85
|
+
import Loading from '../Loading';
|
|
86
|
+
|
|
87
|
+
const load = opts => Loadable({
|
|
88
|
+
delay: 10000,
|
|
89
|
+
loading: () => <Loading />,
|
|
90
|
+
render(loaded, props) {
|
|
91
|
+
const LoadedComponent = loaded.default;
|
|
92
|
+
return <LoadedComponent {...props} />;
|
|
93
|
+
},
|
|
94
|
+
...opts,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
/* Here we're wrapping our component in react-loadable HOC */
|
|
99
|
+
const DynamicComponent = load({
|
|
100
|
+
/*
|
|
101
|
+
We need to specify these params: `webpackChunkName`, `modules` and `webpack`
|
|
102
|
+
so react-loadable can load our chunk correctly
|
|
103
|
+
*/
|
|
104
|
+
loader: () => import(/* webpackChunkName: "Map" */'./Map'),
|
|
105
|
+
modules: ['./Map'],
|
|
106
|
+
webpack: () => [require.resolveWeak('./Map')],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
Component = DynamicComponent;
|
|
110
|
+
// #endif
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
When `IS_SSR` present, `Component` equals `StaticComponent`, otherwise `DynamicComponent`
|
|
114
|
+
*/
|
|
115
|
+
export default Component;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Now, if we want to use this component we should import it like this:
|
|
119
|
+
```jsx
|
|
120
|
+
import Map from './components/Map'
|
|
121
|
+
```
|
|
122
|
+
in this case, webpack will load `index.jsx` instead of `Map.jsx` if not some other special order specified.
|
|
123
|
+
|
|
124
|
+
Also, `IS_SSR=true` must added when creating server side bundle, like this:
|
|
125
|
+
```
|
|
126
|
+
NODE_ENV=production IS_SSR=true webpack --config webpack.config.ssr.prod.js
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The new chunk `Map.chunk.js` will be automatically extracted due dynamic code-splitting feature.
|
|
130
|
+
|
|
131
|
+
With this configuration, server rendering will work with static components, and client with dynamic components.
|
|
132
|
+
|
|
133
|
+
## Flickering
|
|
134
|
+
|
|
135
|
+
On the client, we can periodically see `Loading ...` instead of the right components.
|
|
136
|
+
This is due to the fact that react-loadable loads the module with the component only when it is mounted to the DOM.
|
|
137
|
+
|
|
138
|
+
React-loadable has the ability to preload the required component, for example, when we hover the cursor on the menu item. This will remove `Loading ...` in some situations.
|
|
139
|
+
More details can be found in the documentation react-loadable.
|
|
140
|
+
[https://github.com/jamiebuilds/react-loadable#preloading](https://github.com/jamiebuilds/react-loadable#preloading)
|
|
141
|
+
|
|
142
|
+
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
|
+
|
|
144
|
+
Unfortunately, the way specified in the documentation `react-loadable` does not work for us.
|
|
145
|
+
|
|
146
|
+
Here is another similar method.
|
|
147
|
+
|
|
148
|
+
For this we use the function `registerDynamicComponentOnServer`. We will place it in the new file `DynamicImports.js`:
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
export const registerDynamicComponentOnServer = name => {
|
|
153
|
+
const serverSide = typeof window === 'undefined'
|
|
154
|
+
|
|
155
|
+
if (serverSide) {
|
|
156
|
+
if (typeof global.dynamicComponents === 'undefined') {
|
|
157
|
+
global.dynamicComponents = []
|
|
158
|
+
}
|
|
159
|
+
if (global.dynamicComponents.indexOf(name) === -1) {
|
|
160
|
+
global.dynamicComponents.push(name)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
As you can see from the function body, it runs only for server-side rendering.
|
|
166
|
+
It simply adds the name of the component to the global array `dynamicComponents` which will be transferred to the client later.
|
|
167
|
+
|
|
168
|
+
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
|
+
|
|
170
|
+
components/Map/Map.jsx:
|
|
171
|
+
```javascript
|
|
172
|
+
...
|
|
173
|
+
import { registerDynamicComponentOnServer } from 'DynamicImports';
|
|
174
|
+
|
|
175
|
+
class Map extends React.Component {
|
|
176
|
+
constructor(props) {
|
|
177
|
+
super(props);
|
|
178
|
+
...
|
|
179
|
+
registerDynamicComponentOnServer('Map');
|
|
180
|
+
}
|
|
181
|
+
...
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
Then this global array must be passed to the client.
|
|
187
|
+
To do this, change server entry point as follows:
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
**ServerApp.js**:
|
|
191
|
+
```javascript
|
|
192
|
+
import React from 'react';
|
|
193
|
+
import ReactOnRails from 'react-on-rails';
|
|
194
|
+
|
|
195
|
+
import App from './App';
|
|
196
|
+
|
|
197
|
+
const ServerApp = (props, railsContext) => {
|
|
198
|
+
|
|
199
|
+
const html = renderToString(
|
|
200
|
+
<App
|
|
201
|
+
{...props}
|
|
202
|
+
components={{ MainPage, AboutPage }}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
html,
|
|
208
|
+
dynamicComponents: JSON.stringify(global.dynamicComponents),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
ReactOnRails.register({ App: ServerApp })
|
|
213
|
+
|
|
214
|
+
export default ServerApp
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
And add our array to view in rails, where our react_component is displayed
|
|
218
|
+
```slim
|
|
219
|
+
<% component = react_component("App", props: {}, prerender: true) %>
|
|
220
|
+
|
|
221
|
+
<%= component['html'] %>
|
|
222
|
+
|
|
223
|
+
<script>
|
|
224
|
+
window.dynamicComponents = '<%= component['dynamicComponents'] %>';
|
|
225
|
+
</script>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Note, the complexity of getting some data from the execution of JS during server rendering into some HTML script tags will eventually be made much simpler in React on Rails Pro.
|
|
229
|
+
See [https://github.com/shakacode/react_on_rails_pro/issues/67](https://github.com/shakacode/react_on_rails_pro/issues/67) for details on how this work.
|
|
230
|
+
|
|
231
|
+
In this case, the array is transferred with the names of the dynamic components that were rendered on server-side.
|
|
232
|
+
|
|
233
|
+
Using this array, we can preload the dynamic components on the client before hydrate. This is critical in the case of when the user has bookmarked a dynamically loaded page.
|
|
234
|
+
|
|
235
|
+
To do this, we will create an object with the component names as the keys, and the values with functions that dynamically import the component data.
|
|
236
|
+
|
|
237
|
+
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
|
+
|
|
239
|
+
**DynamicImports.js**
|
|
240
|
+
```javascript
|
|
241
|
+
const DynamicImports = {
|
|
242
|
+
Map: () => import('./components/Map')
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export const registerDynamicComponentOnServer = name => {
|
|
246
|
+
const serverSide = typeof window === 'undefined'
|
|
247
|
+
|
|
248
|
+
if (serverSide) {
|
|
249
|
+
if (typeof global.dynamicComponents === 'undefined') {
|
|
250
|
+
global.dynamicComponents = []
|
|
251
|
+
}
|
|
252
|
+
if (typeof DynamicImports[name] === 'undefined') {
|
|
253
|
+
throw new Error(`Dynamic import not defined for ${name}`)
|
|
254
|
+
}
|
|
255
|
+
if (global.dynamicComponents.indexOf(name) === -1) {
|
|
256
|
+
global.dynamicComponents.push(name)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export default DynamicImports
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Now we can load the component we need, knowing its name
|
|
265
|
+
For example:
|
|
266
|
+
```javascript
|
|
267
|
+
DynamicImports ['Map'] ()
|
|
268
|
+
```
|
|
269
|
+
This function will return Promise, which can be used for client rendering.
|
|
270
|
+
|
|
271
|
+
Change the Client.js to add the preloading of the required components:
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
**Client.js**
|
|
275
|
+
```javascript
|
|
276
|
+
import React from 'react';
|
|
277
|
+
import { hydrateRoot } from 'react-dom/client';
|
|
278
|
+
import Loadable from 'react-loadable'
|
|
279
|
+
|
|
280
|
+
import App from './App';
|
|
281
|
+
|
|
282
|
+
import DynamicImports from 'DynamicImports'
|
|
283
|
+
|
|
284
|
+
const App = (props, railsContext, domNodeId) => {
|
|
285
|
+
|
|
286
|
+
const dynamicComponents =
|
|
287
|
+
typeof window.dynamicComponents !== 'undefined'
|
|
288
|
+
? JSON.parse(window.dynamicComponents)
|
|
289
|
+
: []
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
const dynamicImports = []
|
|
293
|
+
dynamicComponents.map(name => {
|
|
294
|
+
const dynamicImportInvoked = DynamicImports[name]()
|
|
295
|
+
dynamicImports.push(dynamicImportInvoked)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
Promise.all(dynamicImports)
|
|
299
|
+
.then(() => Loadable.preloadReady())
|
|
300
|
+
.then(() => {
|
|
301
|
+
hydrateRoot(
|
|
302
|
+
<App
|
|
303
|
+
{...props}
|
|
304
|
+
components={{ MainPage, AboutPage }}
|
|
305
|
+
/>,
|
|
306
|
+
document.getElementById(domNodeId),
|
|
307
|
+
)
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export default App
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This code requires explanation.
|
|
315
|
+
|
|
316
|
+
The array with names of rendered components called `dynamicComponents` is used in the map function.
|
|
317
|
+
In this function, the dynamic import invoked and the result (promise) is added to `dynamicImports` array.
|
|
318
|
+
```javascript
|
|
319
|
+
const dynamicImports = []
|
|
320
|
+
dynamicComponents.map(name => {
|
|
321
|
+
const dynamicImportInvoked = DynamicImports[name]()
|
|
322
|
+
dynamicImports.push(dynamicImportInvoked)
|
|
323
|
+
})
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
This array is used in the function `Promise.all`
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
Promise.all(dynamicImports).then(() => ...)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Then fires `Loadable.preloadReady()`
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
.then(() => Loadable.preloadReady())
|
|
336
|
+
```
|
|
337
|
+
As in the doc:
|
|
338
|
+
Check for modules that are already loaded in the browser and call the matching LoadableComponent.preload methods.
|
|
339
|
+
|
|
340
|
+
We need to call this method to initialize already preloaded components.
|
|
341
|
+
|
|
342
|
+
In addition, note that in the creation of dynamic modules, the `modules` and` webpack` options are used, per the docs for react-loadable.
|
|
343
|
+
```javascript
|
|
344
|
+
modules: ['./AboutPage'],
|
|
345
|
+
webpack: () => [require.resolveWeak('./AboutPage')],
|
|
346
|
+
```
|
|
347
|
+
They are needed to make .preload method work properly
|
|
348
|
+
|
|
349
|
+
Thus, all dynamic modules will be loaded up to hydrate, and there will be no flicker.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
`config/initializers/react_on_rails_pro.rb`
|
|
4
|
+
|
|
5
|
+
1. You don't need to create a initializer if you are satisfied with the defaults as described below.
|
|
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/)
|
|
7
|
+
1. `config.prerender_caching` works for standard mini_racer server rendering and using an external rendering server.
|
|
8
|
+
|
|
9
|
+
## Example of Configuration
|
|
10
|
+
|
|
11
|
+
Also see [spec/dummy/config/initializers/react_on_rails_pro.rb](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/config/initializers/react_on_rails_pro.rb) for how the testing app is setup.
|
|
12
|
+
|
|
13
|
+
The below example is a typical production setup, using the separate `NodeRenderer`, where development takes the defaults when the ENV values are not specified.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
ReactOnRailsPro.configure do |config|
|
|
17
|
+
# If true, then capture timing of React on Rails Pro calls including server rendering and
|
|
18
|
+
# component rendering.
|
|
19
|
+
# Default for `tracing` is false.
|
|
20
|
+
config.tracing = true
|
|
21
|
+
|
|
22
|
+
# Array of globs to find any files for which changes should bust the fragment cache for
|
|
23
|
+
# cached_react_component and cached_react_component_hash. This should include any files used to
|
|
24
|
+
# generate the JSON props, webpack and/or webpacker configuration files, and npm package lockfiles.
|
|
25
|
+
# Default for `dependency_globs` is an empty array
|
|
26
|
+
config.dependency_globs = [ File.join(Rails.root, "app", "views", "**", "*.jbuilder") ]
|
|
27
|
+
|
|
28
|
+
# Array of globs to exclude from config.dependency_globs for ReactOnRailsPro cache key hashing
|
|
29
|
+
# Default for `excluded_dependency_globs` is an empty array
|
|
30
|
+
config.excluded_dependency_globs = [ File.join(Rails.root, "app", "views", "**", "dont_hash_this.jbuilder") ]
|
|
31
|
+
|
|
32
|
+
# Remote bundle caching saves deployment time by caching bundles.
|
|
33
|
+
# See /docs/bundle-caching.md for usage and an example of a module called S3BundleCacheAdapter.
|
|
34
|
+
config.remote_bundle_cache_adapter = nil
|
|
35
|
+
|
|
36
|
+
# ALL OPTIONS BELOW ONLY APPLY IF SERVER RENDERING
|
|
37
|
+
|
|
38
|
+
# If true, then cache the evaluation of JS for prerendering using the standard Rails cache.
|
|
39
|
+
# Applies to all rendering engines.
|
|
40
|
+
# Default for `prerender_caching` is false.
|
|
41
|
+
config.prerender_caching = true
|
|
42
|
+
|
|
43
|
+
# Retry request in case of time out on the node-renderer side
|
|
44
|
+
# 5 - default, if not specified
|
|
45
|
+
# 0 - no retry
|
|
46
|
+
config.renderer_request_retry_limit = 5
|
|
47
|
+
|
|
48
|
+
# NodeRenderer is for a renderer that is stateless. It does not need restarting when the JS bundles
|
|
49
|
+
# are updated. It is the only custom renderer currently supported. Leave blank to use the standard
|
|
50
|
+
# mini_racer rendering. Other option is NodeRenderer
|
|
51
|
+
# Default for `server_renderer` is "ExecJS"
|
|
52
|
+
config.server_renderer = "NodeRenderer"
|
|
53
|
+
|
|
54
|
+
# React on Rails Node Renderer now support render functions returning promises! To enable this optional functionality,
|
|
55
|
+
# toggle the following option.
|
|
56
|
+
# Default is false.
|
|
57
|
+
config.rendering_returns_promises = false
|
|
58
|
+
|
|
59
|
+
# If you're using the NodeRenderer, a value of true allows errors to be thrown from the bundle
|
|
60
|
+
# code for SSR so that an error tracking system on the NodeRender can use the exceptions.
|
|
61
|
+
# If you are using ExecJS as your rendering method, set this to false.
|
|
62
|
+
# Default is true.
|
|
63
|
+
config.throw_js_errors = true
|
|
64
|
+
|
|
65
|
+
# You may provide a password and/or a port that will be sent to renderer for simple authentication.
|
|
66
|
+
# `https://:<password>@url:<port>`. For example: https://:myPassword1@renderer:3800. Don't forget
|
|
67
|
+
# the leading `:` before the password. Your password must also not contain certain characters that
|
|
68
|
+
# would break calling URI(config.renderer_url). This includes: `@`, `#`, '/'.
|
|
69
|
+
# **Note:** Don't forget to set up **SSL** connection (https) otherwise password will useless
|
|
70
|
+
# since it will be easy to intercept it.
|
|
71
|
+
# If you provide an ENV value (maybe only for production) and there is no value, then you get the default.
|
|
72
|
+
# Default for `renderer_url` is "http://localhost:3800".
|
|
73
|
+
config.renderer_url = ENV["RENDERER_URL"]
|
|
74
|
+
|
|
75
|
+
# If you don't want to worry about special characters in your password within the url, use this config value
|
|
76
|
+
# Default for `renderer_password` is ""
|
|
77
|
+
# config.renderer_password = ENV["RENDERER_PASSWORD"]
|
|
78
|
+
|
|
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.
|
|
81
|
+
config.ssr_timeout = 5
|
|
82
|
+
|
|
83
|
+
# If false, then crash if no backup rendering when the remote renderer is not available
|
|
84
|
+
# Can be useful to set to false in development or testing to make sure that the remote renderer
|
|
85
|
+
# works and any non-availability of the remote renderer does not just do ExecJS.
|
|
86
|
+
# Suggest setting this to false if the SSR JS code cannot run in ExecJS
|
|
87
|
+
# Default for `renderer_use_fallback_exec_js` is false.
|
|
88
|
+
config.renderer_use_fallback_exec_js = false
|
|
89
|
+
|
|
90
|
+
# The maximum size of the http connection pool,
|
|
91
|
+
# Set +pool_size+ to limit the maximum number of connections allowed.
|
|
92
|
+
# Defaults to 1/4 the number of allowed file handles. You can have no more
|
|
93
|
+
# than this many threads with active HTTP transactions.
|
|
94
|
+
# Default for `renderer_http_pool_size` is 10
|
|
95
|
+
config.renderer_http_pool_size = 10
|
|
96
|
+
|
|
97
|
+
# Seconds to wait for an available connection before a timeout error is raised
|
|
98
|
+
# Default for `renderer_http_pool_timeout` is 5
|
|
99
|
+
config.renderer_http_pool_timeout = 5
|
|
100
|
+
|
|
101
|
+
# warn_timeout - Displays an error message if a request takes longer than the given time in seconds
|
|
102
|
+
# (used to give hints to increase the pool size). Default is 0.25
|
|
103
|
+
config.renderer_http_pool_warn_timeout = 0.25 # seconds
|
|
104
|
+
|
|
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.
|
|
107
|
+
# For example, suppose that we had to call `SomeLibrary.clearCache()`between every call to server
|
|
108
|
+
# renderer to ensure no leakage of state between calls. Note, SomeLibrary needs to be globally
|
|
109
|
+
# exposed in the server rendering webpack bundle. This code is visible in the tracing of the calls
|
|
110
|
+
# to do server rendering. Default is nil.
|
|
111
|
+
config.ssr_pre_hook_js = "SomeLibrary.clearCache();"
|
|
112
|
+
|
|
113
|
+
# When using the Node Renderer, you may require some extra assets in addition to the bundle.
|
|
114
|
+
# The assets_to_copy option allows the Node Renderer to have assets copied at the end of
|
|
115
|
+
# the assets:precompile task or directly by the
|
|
116
|
+
# react_on_rails_pro:copy_assets_to_remote_vm_renderer task.
|
|
117
|
+
# These assets are also transferred any time a new bundle is sent from Rails to the renderer.
|
|
118
|
+
# The value should be a file_path or an Array of file_paths. The files should have extensions
|
|
119
|
+
# to resolve the content types, such as "application/json".
|
|
120
|
+
config.assets_to_copy = [
|
|
121
|
+
Rails.root.join("public", "webpack", Rails.env, "loadable-stats.json"),
|
|
122
|
+
Rails.root.join("public", "webpack", Rails.env, "manifest.json")
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
################################################################################
|
|
126
|
+
# REACT SERVER COMPONENTS (RSC) CONFIGURATION
|
|
127
|
+
################################################################################
|
|
128
|
+
|
|
129
|
+
# Enable React Server Components support
|
|
130
|
+
# When enabled, React on Rails Pro will support RSC rendering and streaming
|
|
131
|
+
# Default is false
|
|
132
|
+
config.enable_rsc_support = true
|
|
133
|
+
|
|
134
|
+
# Path to the RSC bundle file (relative to webpack output directory or absolute path)
|
|
135
|
+
# The RSC bundle contains only server components and references to client components.
|
|
136
|
+
# It's generated using the RSC Webpack Loader which transforms client components into
|
|
137
|
+
# references. This bundle is specifically used for generating RSC payloads and is
|
|
138
|
+
# configured with the 'react-server' condition.
|
|
139
|
+
# Default is "rsc-bundle.js"
|
|
140
|
+
config.rsc_bundle_js_file = "rsc-bundle.js"
|
|
141
|
+
|
|
142
|
+
# Path to the React client manifest file (typically in your webpack output directory)
|
|
143
|
+
# This manifest contains mappings for client components that need hydration.
|
|
144
|
+
# It's automatically generated by the React Server Components Webpack plugin and is
|
|
145
|
+
# required for client-side hydration of components.
|
|
146
|
+
# Only set this if you've configured the plugin to use a different filename.
|
|
147
|
+
# Default is "react-client-manifest.json"
|
|
148
|
+
config.react_client_manifest_file = "react-client-manifest.json"
|
|
149
|
+
|
|
150
|
+
# Path to the React server-client manifest file (typically in your webpack output directory)
|
|
151
|
+
# This manifest is used during server-side rendering with RSC to properly resolve
|
|
152
|
+
# references between server and client components.
|
|
153
|
+
# It's automatically generated by the React Server Components Webpack plugin.
|
|
154
|
+
# Only set this if you've configured the plugin to use a different filename.
|
|
155
|
+
# Default is "react-server-client-manifest.json"
|
|
156
|
+
config.react_server_client_manifest_file = "react-server-client-manifest.json"
|
|
157
|
+
|
|
158
|
+
# These RSC configuration files are crucial when implementing React Server Components
|
|
159
|
+
# with streaming, which offers benefits like:
|
|
160
|
+
# - Reduced JavaScript bundle sizes
|
|
161
|
+
# - Faster page loading
|
|
162
|
+
# - Selective hydration of client components
|
|
163
|
+
# - Progressive rendering with Suspense boundaries
|
|
164
|
+
end
|
|
165
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Releasing React on Rails Pro
|
|
2
|
+
|
|
3
|
+
⚠️ **This documentation is outdated.**
|
|
4
|
+
|
|
5
|
+
React on Rails Pro is now released together with React on Rails using a unified release script.
|
|
6
|
+
|
|
7
|
+
## Current Release Process
|
|
8
|
+
|
|
9
|
+
Please refer to the main release documentation:
|
|
10
|
+
|
|
11
|
+
👉 **[/docs/contributor-info/releasing.md](../../../docs/contributor-info/releasing.md)**
|
|
12
|
+
|
|
13
|
+
Or run from the repository root:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd .. && rake -D release
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Reference
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# From repository root (not from react_on_rails_pro/)
|
|
23
|
+
cd /path/to/react_on_rails
|
|
24
|
+
|
|
25
|
+
# Release with version bump
|
|
26
|
+
rake release[17.0.0]
|
|
27
|
+
|
|
28
|
+
# Dry run first (recommended)
|
|
29
|
+
rake release[17.0.0,true]
|
|
30
|
+
|
|
31
|
+
# Test with local Verdaccio
|
|
32
|
+
rake release[17.0.0,false,verdaccio]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This unified script releases all 5 packages together:
|
|
36
|
+
- react-on-rails (NPM)
|
|
37
|
+
- react-on-rails-pro (NPM)
|
|
38
|
+
- react-on-rails-pro-node-renderer (NPM)
|
|
39
|
+
- react_on_rails (RubyGem)
|
|
40
|
+
- react_on_rails_pro (RubyGem)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Code Style
|
|
2
|
+
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
|
+
* Use of linters with our standard linter configuration.
|
|
5
|
+
* References to existing style guidelines that support the linter configuration.
|
|
6
|
+
* Anything additional goes next.
|
|
7
|
+
|
|
8
|
+
## Client Side JavaScript and React
|
|
9
|
+
* See the [Shakacode JavaScript Style Guide](https://github.com/shakacode/style-guide-javascript)
|
|
10
|
+
|
|
11
|
+
## Style Guides to Follow
|
|
12
|
+
Follow these style guidelines per the linter configuration. Basically, lint your code and if you have questions about the suggested fixes, look here:
|
|
13
|
+
|
|
14
|
+
### Ruby Coding Standards
|
|
15
|
+
* [ShakaCode Ruby Coding Standards](https://github.com/shakacode/style-guide-ruby)
|
|
16
|
+
* [Ruby Documentation](http://guides.rubyonrails.org/api_documentation_guidelines.html)
|
|
17
|
+
|
|
18
|
+
### JavaScript Coding Standards
|
|
19
|
+
* [ShakaCode Javascript](https://github.com/shakacode/style-guide-javascript)
|
|
20
|
+
* Use the [eslint-config-shakacode](https://github.com/shakacode/style-guide-javascript/tree/master/packages/eslint-config-shakacode) npm package with eslint.
|
|
21
|
+
* [JSDoc](http://usejsdoc.org/)
|
|
22
|
+
|
|
23
|
+
### Git coding Standards
|
|
24
|
+
* [Git Coding Standards](http://chlg.co/1GV2m9p)
|
|
25
|
+
|
|
26
|
+
### Sass Coding Standards
|
|
27
|
+
* [Sass Guidelines](http://sass-guidelin.es/) by [Hugo Giraudel](http://hugogiraudel.com/)
|
|
28
|
+
* [Github Front End Guidelines](http://primercss.io/guidelines/)
|
|
29
|
+
|
|
30
|
+
# Git Usage
|
|
31
|
+
* Follow a github-flow model where you branch off of master for features.
|
|
32
|
+
* 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.
|
|
33
|
+
* Run hosted CI and code coverage.
|