Skip to content

Commit 15c0618

Browse files
committed
Address comments
Mostly additions to code-splitting.md. Also linked to the renderer function section in the readme from the error message in serverRenderReactComponent. Added a line to that section in README to address the error.
1 parent c9a3e17 commit 15c0618

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ Why would you create a function that returns a React component? For example, you
316316
#### Renderer Functions
317317
A renderer function is a generator function that accepts three arguments: `(props, railsContext, domNodeId) => { ... }`. Instead of returning a React component, a renderer is responsible for calling `ReactDOM.render` to manually render a React component into the dom. Why would you want to call `ReactDOM.render` yourself? One possible use case is [code splitting](docs/additional-reading/code-splitting.md).
318318

319+
Renderer functions are not meant to be used on the server, since there's no DOM on the server. Instead, use a generator function. Attempting to server render with a renderer function will cause an error.
320+
319321
## ReactOnRails View Helpers API
320322
Once the bundled files have been generated in your `app/assets/webpack` folder and you have exposed your components globally, you will want to run your code in your Rails views using the included helper method.
321323

docs/additional-reading/code-splitting.md

+30-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Here's an example of how you might use this in practice:
3434
```js
3535
import ReactOnRails from 'react-on-rails';
3636
import NavigationApp from './NavigationApp';
37+
38+
// Note that we're importing a different RouterApp that in serverRegistration.js
39+
// Renderer functions should not be used on the server, because there is no DOM.
3740
import RouterApp from './RouterAppRenderer';
3841
import applicationStore from '../store/applicationStore';
3942

@@ -48,6 +51,8 @@ ReactOnRails.register({
4851
```js
4952
import ReactOnRails from 'react-on-rails';
5053
import NavigationApp from './NavigationApp';
54+
55+
// Note that we're importing a different RouterApp that in clientRegistration.js
5156
import RouterApp from './RouterAppServer';
5257
import applicationStore from '../store/applicationStore';
5358

@@ -57,7 +62,7 @@ ReactOnRails.register({
5762
RouterApp,
5863
});
5964
```
60-
Note that you should not register a renderer on the server, since there won't be a domNodeId when we're server rendering. For an example of how to set up an app for server rendering, see the [react router docs](react-router.md).
65+
Note that you should not register a renderer on the server, since there won't be a domNodeId when we're server rendering. Note that the `RouterApp` imported by `serverRegistration.js` is from a different file. For an example of how to set up an app for server rendering, see the [react router docs](react-router.md).
6166

6267
#### RouterAppRenderer.jsx
6368
```jsx
@@ -100,9 +105,22 @@ The idea is that match from react-router is async; it fetches the component usin
100105

101106
The server render matches the deferred render because the server bundle is a single file, and so it doesn't need to wait for anything to be fetched.
102107

108+
### Working Example
109+
110+
There's an implemented example of code splitting in the `spec/dummy` folder of this repository.
111+
112+
See:
113+
114+
- [spec/dummy/client/app/startup/clientRegistration.jsx](../../spec/dummy/client/app/startup/clientRegistration.jsx)
115+
- [spec/dummy/client/app/startup/serverRegistration.jsx](../../spec/dummy/client/app/startup/serverRegistration.jsx)
116+
- [spec/dummy/client/app/startup/DeferredRenderAppRenderer.jsx](../../spec/dummy/client/app/startup/DeferredRenderAppRenderer.jsx) <-- Code splitting implemented here
117+
- [spec/dummy/client/app/startup/DeferredRenderAppServer.jsx](../../spec/dummy/client/app/startup/DeferredRenderAppServer.jsx)
118+
- [spec/dummy/client/app/components/DeferredRender.jsx](../../spec/dummy/client/app/components/DeferredRender.jsx)
119+
- [spec/dummy/client/app/components/DeferredRenderAsyncPage.jsx](../../spec/dummy/client/app/components/DeferredRenderAsyncPage.jsx)
120+
103121
### Caveats
104122

105-
If you're going to try to do code splitting with server rendered routes, you'll probably need to use seperate route definitions for client and server to prevent code splitting from happening for the server bundle. The server bundle should be one file containing all the JavaScript code.
123+
If you're going to try to do code splitting with server rendered routes, you'll probably need to use seperate route definitions for client and server to prevent code splitting from happening for the server bundle. The server bundle should be one file containing all the JavaScript code. This will require you to have seperate webpack configurations for client and server.
106124

107125
The reason is we do server rendering with ExecJS, which is not capable of doing anything asynchronous. It would be impossible to asyncronously fetch a code chunk while server rendering. See [this issue](https://github.com/shakacode/react_on_rails/issues/477) for a discussion.
108126

@@ -123,3 +141,13 @@ config = {
123141
This causes Webpack to prepend the code chunk filename with `/assets/` in the request url. The react on rails sets up the webpack config to put webpack bundles in `app/assets/javascripts/webpack`, and modifies `config/initializers/assets.rb` so that rails detects the bundles. This means that when we prepend the request url with `/assets/`, rails will know what webpack is asking for.
124142

125143
See [rails-assets.md](./rails-assets.md) to learn more about static assets.
144+
145+
If you forget to set the public path, webpack will request the code chunk at `/{filename}`. This will cause the request to be handled by the Rails router, which will send back a 404 response, assuming that you don't have a catch-all route. In your javascript console, you'll get the following error:
146+
147+
> GET http://localhost:3000/1.1-bundle.js
148+
149+
You'll also see the following in your Rails development log:
150+
151+
> Started GET "/1.1-bundle.js" for 127.0.0.1 at 2016-11-29 15:21:55 -0800
152+
>
153+
> ActionController::RoutingError (No route matches [GET] "/1.1-bundle.js")

node_package/src/serverRenderReactComponent.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ export default function serverRenderReactComponent(options) {
1515
try {
1616
const componentObj = ComponentRegistry.get(name);
1717
if (componentObj.isRenderer) {
18-
throw new Error(`Detected a renderer while server rendering component '${name}'`);
18+
throw new Error(`\
19+
Detected a renderer while server rendering component '${name}'. \
20+
See https://github.com/shakacode/react_on_rails#renderer-functions`);
1921
}
2022

2123
const reactElementOrRouterResult = createReactElement({

0 commit comments

Comments
 (0)