react_on_rails 6.2.1 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -2
- data/Gemfile +1 -0
- data/README.md +15 -7
- data/app/helpers/react_on_rails_helper.rb +8 -1
- data/docs/additional-reading/code-splitting.md +155 -0
- data/docs/additional-reading/heroku-deployment.md +0 -1
- data/docs/additional-reading/rails-engine-integration.md +34 -0
- data/lib/generators/react_on_rails/base_generator.rb +4 -5
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +10 -10
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +12 -5
- data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx +45 -0
- data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/registration.jsx.tt +8 -0
- data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +5 -1
- data/lib/generators/react_on_rails/templates/node/base/client/node/server.js +1 -1
- data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt +1 -2
- data/lib/react_on_rails/version.rb +1 -1
- data/package.json +5 -8
- data/rakelib/lint.rake +2 -7
- metadata +7 -7
- data/.jscsrc +0 -30
- data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx.tt +0 -29
- data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorldContainer.jsx +0 -25
- data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 438f4802448657a19eec8b4e61a88fe92b400fa6
|
4
|
+
data.tar.gz: f7cbeef69e4172876e754b1a9f651a55d88a8068
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4a3dac61a8ee06122987ba2b3e388ae235681bc84ff891bd7da1bdd44c29bd5b5b0a16c69216db628e3a7933105b7c34c8027514f0cbcf7a8e75bb9d1d87501
|
7
|
+
data.tar.gz: 17d55ed293b3a04507874f20b8570b2a851bd76b66b2806d821dbeaa41881e94b7e32216c4f3bcec11809b7a1f0aaf054c867022c2de4c52d32faa747df52308
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
# Change Log
|
2
|
-
All notable changes to this project will be documented in this file. Items under `Unreleased` is upcoming features that will be out in next version.
|
2
|
+
All notable changes to this project's source code will be documented in this file. Items under `Unreleased` is upcoming features that will be out in next version.
|
3
3
|
|
4
4
|
Contributors: please follow the recommendations outlined at [keepachangelog.com](http://keepachangelog.com/). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare to the latest release version.
|
5
5
|
|
6
6
|
## [Unreleased]
|
7
7
|
|
8
|
+
## [6.3.0]
|
9
|
+
##### Changed
|
10
|
+
- Modified register API to allow registration of renderers, allowing a user to manually render their app to the DOM. This allows for code splitting and deferred loading. [#581](https://github.com/shakacode/react_on_rails/pull/581) by [jtibbertsma](https://github.com/jtibbertsma).
|
11
|
+
|
12
|
+
- Updated Basic Generator & Linters. Examples are simpler. [#624](https://github.com/shakacode/react_on_rails/pull/624) by [Judahmeek](https://github.com/Judahmeek).
|
13
|
+
|
14
|
+
- Slight improvement to the 'no hydrated stores' error. [#605](https://github.com/shakacode/react_on_rails/pull/605) by [cookiefission](https://github.com/cookiefission).
|
15
|
+
|
16
|
+
- Don't assume ActionMailer is available. [#608](https://github.com/shakacode/react_on_rails/pull/608) by [tuzz](https://github.com/tuzz).
|
17
|
+
|
8
18
|
## [6.2.1] - 2016-11-19
|
9
19
|
- Removed unnecesary passing of context in the HelloWorld Container example and basic generator. [#612](https://github.com/shakacode/react_on_rails/pull/612) by [justin808](https://github.com/justin808)
|
10
20
|
|
@@ -383,7 +393,8 @@ Best done with Object destructing:
|
|
383
393
|
##### Fixed
|
384
394
|
- Fix several generator related issues.
|
385
395
|
|
386
|
-
[Unreleased]: https://github.com/shakacode/react_on_rails/compare/6.
|
396
|
+
[Unreleased]: https://github.com/shakacode/react_on_rails/compare/6.3.0...master
|
397
|
+
[6.3.0]: https://github.com/shakacode/react_on_rails/compare/6.2.1...6.3.0
|
387
398
|
[6.2.1]: https://github.com/shakacode/react_on_rails/compare/6.2.0...6.2.1
|
388
399
|
[6.2.0]: https://github.com/shakacode/react_on_rails/compare/6.1.2...6.2.0
|
389
400
|
[6.1.2]: https://github.com/shakacode/react_on_rails/compare/6.1.1...6.1.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
**For a complete example of this gem, see our live demo at [www.reactrails.com](http://www.reactrails.com). ([Source Code](https://github.com/shakacode/react-webpack-rails-tutorial))**
|
4
4
|
|
5
|
-
Aloha from Justin Gordon ([bio](http://www.railsonmaui.com/about)) and the [ShakaCode](http://www.shakacode.com) Team! We're actively looking for new projects involving React, React-Native, and Rails. Please contact me at [justin@shakacode.com](mailto:justin@shakacode.com) if we could potentially help you in any way. Besides consulting on bigger projects, [ShakaCode](http://www.shakacode.com) is doing
|
5
|
+
Aloha from Justin Gordon ([bio](http://www.railsonmaui.com/about)) and the [ShakaCode](http://www.shakacode.com) Team! We're actively looking for new projects involving React, React-Native, and Rails. Please contact me at [justin@shakacode.com](mailto:justin@shakacode.com) if we could potentially help you in any way. Besides consulting on bigger projects, [ShakaCode](http://www.shakacode.com) is doing ScreenHero plus Slack/Github based coaching for React on Rails. See our blog post [Can ShakaCode Help You?](https://blog.shakacode.com/can-shakacode-help-you-4a5b1e5a8a63#.jex6tg9w9) for more information.
|
6
6
|
|
7
7
|
We're offering a free half-hour project consultation, on anything from React on Rails to any aspect of web application development for both consumer and enterprise products. In addition to React.js and Rails, we're doing React-Native iOS and Android apps!
|
8
8
|
|
@@ -310,6 +310,14 @@ You may want different initialization for your server rendered components. For e
|
|
310
310
|
|
311
311
|
If you do want different code to run, you'd setup a separate webpack compilation file and you'd specify a different, server side entry file. ex. 'serverHelloWorldApp.jsx'. Note, you might be initializing HelloWorld with version specialized for server rendering.
|
312
312
|
|
313
|
+
#### Generator Functions
|
314
|
+
Why would you create a function that returns a React component? For example, you may want the ability to use the passed-in props to initialize a redux store or setup react-router. Or you may want to return different components depending on what's in the props. ReactOnRails will automatically detect a registered generator function.
|
315
|
+
|
316
|
+
#### Renderer Functions
|
317
|
+
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).
|
318
|
+
|
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
|
+
|
313
321
|
## ReactOnRails View Helpers API
|
314
322
|
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.
|
315
323
|
|
@@ -327,7 +335,7 @@ react_component(component_name,
|
|
327
335
|
html_options: {})
|
328
336
|
```
|
329
337
|
|
330
|
-
+ **component_name:** Can be a React component, created using a ES6 class, or `React.createClass`,
|
338
|
+
+ **component_name:** Can be a React component, created using a ES6 class, or `React.createClass`, a generator function that returns a React component, or a renderer function that manually renders a React component to the dom (client side only).
|
331
339
|
+ **options:**
|
332
340
|
+ **props:** Ruby Hash which contains the properties to pass to the react object, or a JSON string. If you pass a string, we'll escape it for you.
|
333
341
|
+ **prerender:** enable server-side rendering of component. Set to false when debugging!
|
@@ -365,9 +373,6 @@ Note, you don't need to separately initialize your redux store. However, it's re
|
|
365
373
|
1. You want to have multiple components that access the same store.
|
366
374
|
2. You want to place the props to hydrate the client side stores at the very end of your HTML so that the browser can render all earlier HTML first. This is particularly useful if your props will be large.
|
367
375
|
|
368
|
-
### Generator Functions
|
369
|
-
Why would you create a function that returns a React component? For example, you may want the ability to use the passed-in props to initialize a redux store or setup react-router. Or you may want to return different components depending on what's in the props. ReactOnRails will automatically detect a registered generator function.
|
370
|
-
|
371
376
|
### server_render_js
|
372
377
|
`server_render_js(js_expression, options = {})`
|
373
378
|
|
@@ -439,7 +444,7 @@ See [ReactOnRails JavaScript API](docs/api/javascript-api.md).
|
|
439
444
|
|
440
445
|
Rails has built-in protection for Cross-Site Request Forgery (CSRF), see [Rails Documentation](http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf). To nicely utilize this feature in JavaScript requests, React on Rails is offerring two helpers that can be used as following for POST, PUT or DELETE requests:
|
441
446
|
|
442
|
-
```
|
447
|
+
```js
|
443
448
|
import ReactOnRails from 'react-on-rails';
|
444
449
|
|
445
450
|
// reads from DOM csrf token generated by Rails in <%= csrf_meta_tags %>
|
@@ -456,6 +461,7 @@ If you are using [jquery-ujs](https://github.com/rails/jquery-ujs) for AJAX call
|
|
456
461
|
|
457
462
|
1. [React on Rails docs for react-router](docs/additional-reading/react-router.md)
|
458
463
|
1. Examples in [spec/dummy/app/views/react_router](spec/dummy/app/views/react_router) and follow to the JavaScript code in the [spec/dummy/client/app/startup/ServerRouterApp.jsx](spec/dummy/client/app/startup/ServerRouterApp.jsx).
|
464
|
+
1. [Code Splitting docs](docs/additional-reading/code-splitting.md) for information about how to set up code splitting for server rendered routes.
|
459
465
|
|
460
466
|
## Deployment
|
461
467
|
* Version 6.0 puts the necessary precompile steps automatically in the rake precompile step. You can, however, disable this by setting certain values to nil in the [config/initializers/react_on_rails.rb](spec/dummy/config/initializers/react_on_rails.rb).
|
@@ -471,6 +477,7 @@ Node.js can be used as the backend for server-side rendering instead of [execJS]
|
|
471
477
|
**Try out our new [Documentation Gitbook](https://shakacode.gitbooks.io/react-on-rails/content/) for improved readability & reference!**
|
472
478
|
+ **Rails**
|
473
479
|
+ [Rails Assets](docs/additional-reading/rails-assets.md)
|
480
|
+
+ [Rails Engine Integration](docs/additional-reading/rails-engine-integration.md)
|
474
481
|
+ [Rails View Rendering from Inline JavaScript](docs/additional-reading/rails_view_rendering_from_inline_javascript.md)
|
475
482
|
+ [RSpec Configuration](docs/additional-reading/rspec-configuration.md)
|
476
483
|
+ [Turbolinks](docs/additional-reading/turbolinks.md)
|
@@ -486,6 +493,7 @@ Node.js can be used as the backend for server-side rendering instead of [execJS]
|
|
486
493
|
+ [Developing with the Webpack Dev Server](docs/additional-reading/webpack-dev-server.md)
|
487
494
|
+ [Node Server Rendering](docs/additional-reading/node-server-rendering.md)
|
488
495
|
+ [Server Rendering Tips](docs/additional-reading/server-rendering-tips.md)
|
496
|
+
+ [Code Splitting](docs/additional-reading/code-splitting.md)
|
489
497
|
|
490
498
|
+ **Development**
|
491
499
|
+ [React on Rails Basic Installation Tutorial](docs/tutorial.md) ([live demo](https://hello-react-on-rails.herokuapp.com))
|
@@ -554,7 +562,7 @@ We owe much gratitude to the work of the [react-rails gem](https://github.com/re
|
|
554
562
|
|
555
563
|
---
|
556
564
|
|
557
|
-
Aloha from Justin Gordon ([bio](http://www.railsonmaui.com/about)) and the [ShakaCode](http://www.shakacode.com) Team! We're actively looking for new projects involving React, React-Native, and Rails. Please contact me at [justin@shakacode.com](mailto:justin@shakacode.com) if we could potentially help you in any way. Besides consulting on bigger projects, [ShakaCode](http://www.shakacode.com) is doing Skype plus Slack/Github based coaching for React on Rails. [
|
565
|
+
Aloha from Justin Gordon ([bio](http://www.railsonmaui.com/about)) and the [ShakaCode](http://www.shakacode.com) Team! We're actively looking for new projects involving React, React-Native, and Rails. Please contact me at [justin@shakacode.com](mailto:justin@shakacode.com) if we could potentially help you in any way. Besides consulting on bigger projects, [ShakaCode](http://www.shakacode.com) is doing Skype plus Slack/Github based coaching for React on Rails. See our blog post [Can ShakaCode Help You?](https://blog.shakacode.com/can-shakacode-help-you-4a5b1e5a8a63#.jex6tg9w9) for more information.
|
558
566
|
|
559
567
|
We're offering a free half-hour project consultation, on anything from React on Rails to any aspect of web application development for both consumer and enterprise products. In addition to React.js and Rails, we're doing React-Native iOS and Android apps!
|
560
568
|
|
@@ -345,7 +345,7 @@ ReactOnRails.setStore('#{store_name}', store);
|
|
345
345
|
def rails_context(server_side:)
|
346
346
|
@rails_context ||= begin
|
347
347
|
result = {
|
348
|
-
inMailer:
|
348
|
+
inMailer: in_mailer?,
|
349
349
|
# Locale settings
|
350
350
|
i18nLocale: I18n.locale,
|
351
351
|
i18nDefaultLocale: I18n.default_locale
|
@@ -400,4 +400,11 @@ ReactOnRails.setStore('#{store_name}', store);
|
|
400
400
|
options = args.delete_if { |key, _value| %i(hot static).include?(key) }
|
401
401
|
send(tag_method_name, *assets, options) unless assets.empty?
|
402
402
|
end
|
403
|
+
|
404
|
+
def in_mailer?
|
405
|
+
return false unless controller.present?
|
406
|
+
return false unless defined?(ActionMailer::Base)
|
407
|
+
|
408
|
+
controller.is_a?(ActionMailer::Base)
|
409
|
+
end
|
403
410
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# Code Splitting
|
2
|
+
|
3
|
+
What is code splitting? From the webpack documentation:
|
4
|
+
|
5
|
+
> For big web apps it’s not efficient to put all code into a single file, especially if some blocks of code are only required under some circumstances. Webpack has a feature to split your codebase into “chunks” which are loaded on demand. Some other bundlers call them “layers”, “rollups”, or “fragments”. This feature is called “code splitting”.
|
6
|
+
|
7
|
+
## Server Rendering and Code Splitting
|
8
|
+
|
9
|
+
Let's say you're requesting a page that needs to fetch a code chunk from the server before it's able to render. If you do all your rendering on the client side, you don't have to do anything special. However, if the page is rendered on the server, you'll find that React will spit out the following error:
|
10
|
+
|
11
|
+
> Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
|
12
|
+
|
13
|
+
> (client) <!-- react-empty: 1 -
|
14
|
+
|
15
|
+
> (server) <div data-reactroot="
|
16
|
+
<!--This comment is here because the comment beginning on line 13 messes up Sublime's markdown parsing-->
|
17
|
+
|
18
|
+
Different markup is generated on the client than on the server. Why does this happen? When you register a component or generator function with `ReactOnRails.register`, react on rails will render the component as soon as the page loads. However, react-router renders a comment while waiting for the code chunk to be fetched from the server. This means that react will tear all of the server rendered code out of the DOM, and then rerender it a moment later once the code chunk arrives from the server, defeating most of the purpose of server rendering.
|
19
|
+
|
20
|
+
### The solution
|
21
|
+
|
22
|
+
To prevent this, you have to wait until the code chunk is fetched before doing the initial render on the client side. To accomplish this, react on rails allows you to register a renderer. This works just like registering a generator function, except that the function you pass takes three arguments: `renderer(props, railsContext, domNodeId)`, and is responsible for calling `ReactDOM.render` to render the component to the DOM. React on rails will automatically detect when a generator function takes three arguments, and will not call `ReactDOM.render`, instead allowing you to control the initial render yourself.
|
23
|
+
|
24
|
+
Here's an example of how you might use this in practice:
|
25
|
+
|
26
|
+
#### page.html.erb
|
27
|
+
```erb
|
28
|
+
<%= react_component("NavigationApp", prerender: true) %>
|
29
|
+
<%= react_component("RouterApp", prerender: true) %>
|
30
|
+
<%= redux_store_hydration_data %>
|
31
|
+
```
|
32
|
+
|
33
|
+
#### clientRegistration.js
|
34
|
+
```js
|
35
|
+
import ReactOnRails from 'react-on-rails';
|
36
|
+
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.
|
40
|
+
import RouterApp from './RouterAppRenderer';
|
41
|
+
import applicationStore from '../store/applicationStore';
|
42
|
+
|
43
|
+
ReactOnRails.registerStore({applicationStore});
|
44
|
+
ReactOnRails.register({
|
45
|
+
NavigationApp,
|
46
|
+
RouterApp,
|
47
|
+
});
|
48
|
+
```
|
49
|
+
|
50
|
+
#### serverRegistration.js
|
51
|
+
```js
|
52
|
+
import ReactOnRails from 'react-on-rails';
|
53
|
+
import NavigationApp from './NavigationApp';
|
54
|
+
|
55
|
+
// Note that we're importing a different RouterApp that in clientRegistration.js
|
56
|
+
import RouterApp from './RouterAppServer';
|
57
|
+
import applicationStore from '../store/applicationStore';
|
58
|
+
|
59
|
+
ReactOnRails.registerStore({applicationStore});
|
60
|
+
ReactOnRails.register({
|
61
|
+
NavigationApp,
|
62
|
+
RouterApp,
|
63
|
+
});
|
64
|
+
```
|
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).
|
66
|
+
|
67
|
+
#### RouterAppRenderer.jsx
|
68
|
+
```jsx
|
69
|
+
import ReactOnRails from 'react-on-rails';
|
70
|
+
import React from 'react';
|
71
|
+
import ReactDOM from 'react-dom';
|
72
|
+
import Router from 'react-router/lib/Router';
|
73
|
+
import match from 'react-router/lib/match';
|
74
|
+
import browserHistory from 'react-router/lib/browserHistory';
|
75
|
+
import { Provider } from 'react-redux';
|
76
|
+
|
77
|
+
import routes from '../routes/routes';
|
78
|
+
|
79
|
+
|
80
|
+
const RouterAppRenderer = (props, railsContext, domNodeId) => {
|
81
|
+
const store = ReactOnRails.getStore('applicationStore');
|
82
|
+
const history = browserHistory;
|
83
|
+
|
84
|
+
match({ history, routes }, (error, redirectionLocation, renderProps) => {
|
85
|
+
if (error) {
|
86
|
+
throw error;
|
87
|
+
}
|
88
|
+
|
89
|
+
const reactElement = (
|
90
|
+
<Provider store={store}>
|
91
|
+
<Router {...renderProps} />
|
92
|
+
</Provider>
|
93
|
+
);
|
94
|
+
|
95
|
+
ReactDOM.render(reactElement, document.getElementById(domNodeId));
|
96
|
+
});
|
97
|
+
};
|
98
|
+
|
99
|
+
export default RouterAppRenderer;
|
100
|
+
```
|
101
|
+
|
102
|
+
What's going on in this example is that we're putting the rendering code in the callback passed to `match`. The effect is that the client render doesn't happen until the code chunk gets fetched from the server, preventing the client/server checksum mismatch.
|
103
|
+
|
104
|
+
The idea is that match from react-router is async; it fetches the component using the getComponent method that you provide with the route definition, and then passes the props to the callback that are needed to do the complete render. Then we do the first render inside of the callback, so that the first render is the same as the server render.
|
105
|
+
|
106
|
+
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.
|
107
|
+
|
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
|
+
|
121
|
+
### Caveats
|
122
|
+
|
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.
|
124
|
+
|
125
|
+
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.
|
126
|
+
|
127
|
+
Also, do not attempt to register a renderer on the server. Instead, register either a generator function or a component. If you register a renderer in the server bundle, you'll get an error when react on rails tries to server render the component.
|
128
|
+
|
129
|
+
## How does Webpack know where to find my code chunks?
|
130
|
+
|
131
|
+
Add the following to the output key of your webpack config:
|
132
|
+
|
133
|
+
```js
|
134
|
+
config = {
|
135
|
+
output: {
|
136
|
+
publicPath: '/assets/',
|
137
|
+
}
|
138
|
+
};
|
139
|
+
```
|
140
|
+
|
141
|
+
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.
|
142
|
+
|
143
|
+
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")
|
154
|
+
|
155
|
+
It's worth mentioning that in Webpack v2, it's possible to register an error handler by calling `catch` on the promise returned by `System.import`, so if you want to do error handling, you should use v2. The [example](#working-example) in `spec/dummy` is currently using Webpack v1.
|
@@ -5,7 +5,6 @@ The generator has created the necessary files and gems for deployment to Heroku.
|
|
5
5
|
+ `12factor` gem: required by Heroku if using a version before Rails 5 (see their [README](https://github.com/heroku/rails_12factor#rails-5) for more information if upgrading from a lower version)
|
6
6
|
+ `'puma'` gem: recommended Heroku webserver
|
7
7
|
+ `config/puma.rb`: Puma webserver config file
|
8
|
-
+ `lib/tasks/assets.rake`: This rake task file is provided by the generator regardless of whether the user chose Heroku Deployment as an option. It is highlighted here because it is helpful to understand that this task is what generates your JavaScript bundles in production. Previously, users of this gem had to create a file `lib/tasks/assets.rake` to modify the Rails precompile task to deploy assets for production. However, we add this automatically in newer versions of React on Rails. If you need to customize this file, see [lib/tasks/assets.rake from React on Rails](https://github.com/shakacode/react_on_rails/blob/master/lib/tasks/assets.rake) as an example.
|
9
8
|
|
10
9
|
## More details on precompilation using webpack to create JavaScript assets
|
11
10
|
This is how the rake task gets modified. You should be able to call `clear_prerequisites` and setup your own custom precompile if needed.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
## In your engine
|
2
|
+
|
3
|
+
+ At the top of `config/initializers/react_on_rails.rb`
|
4
|
+
```ruby
|
5
|
+
ActiveSupport.on_load(:action_view) do
|
6
|
+
include ReactOnRailsHelper
|
7
|
+
end
|
8
|
+
```
|
9
|
+
+ In your `<engine_name>.gemspec`:
|
10
|
+
```ruby
|
11
|
+
s.add_dependency 'react_on_rails', '~> 6'
|
12
|
+
```
|
13
|
+
+ In your `lib/<engine_name>.rb` (the entry point for your engine)
|
14
|
+
```ruby
|
15
|
+
require "react_on_rails"
|
16
|
+
```
|
17
|
+
+ In your `lib/tasks/<engine_name>_tasks.rake`:
|
18
|
+
```ruby
|
19
|
+
Rake.application.remove_task('react_on_rails:assets:compile_environment')
|
20
|
+
|
21
|
+
task 'react_on_rails:assets:compile_environment' do
|
22
|
+
path = File.join(YourEngineName::Engine.root, 'client')
|
23
|
+
sh "cd #{path} && #{ReactOnRails.configuration.npm_build_production_command}"
|
24
|
+
end
|
25
|
+
```
|
26
|
+
## In the project including your engine
|
27
|
+
|
28
|
+
Place `gem 'react_on_rails', '~> 6'` before the gem pointing at your engine in your gemfile.
|
29
|
+
|
30
|
+
This is necessary because React on Rails attaches itself to the rake assets:precompile task. It then uses a direct path to cd into client, which will not exist in the main app that includes your engine. Since you'll always be precompiling assets in the parent app, this will always fail. The workaround then, is to remove the task and replace it with one that goes into your Engine's root. The reason you have to include the react on rails gem before your engine is so that the `react_on_rails:assets:compile_environment` task is defined by the time your engine gets loaded to remove it.
|
31
|
+
|
32
|
+
Requiring `react_on_rails` and including the helper will get rid of any issues where react on rails or react_component is undefined.
|
33
|
+
|
34
|
+
As far as solving the assets issue, `lib/tasks/assets.rake` in `react_on_rails` would somehow have to know that `react_on_rails` was included in an engine, and decide the path accordingly. This might be impossible, especially in the case of multiple engines using `react_on_rails` in a single application. Another solution would be to detach this rake task from the rails assets:precompile task, and let people use it separately.
|
@@ -44,7 +44,7 @@ module ReactOnRails
|
|
44
44
|
DATA
|
45
45
|
|
46
46
|
app_js_path = "app/assets/javascripts/application.js"
|
47
|
-
found_app_js = dest_file_exists?(app_js_path) || dest_file_exists?(app_js_path
|
47
|
+
found_app_js = dest_file_exists?(app_js_path) || dest_file_exists?("#{app_js_path}.coffee")
|
48
48
|
if found_app_js
|
49
49
|
prepend_to_file(found_app_js, data)
|
50
50
|
else
|
@@ -65,20 +65,19 @@ module ReactOnRails
|
|
65
65
|
def copy_base_files
|
66
66
|
base_path = "base/base/"
|
67
67
|
base_files = %w(app/controllers/hello_world_controller.rb
|
68
|
+
client/app/bundles/HelloWorld/components/HelloWorld.jsx
|
68
69
|
client/.babelrc
|
69
70
|
client/webpack.config.js
|
70
71
|
client/REACT_ON_RAILS_CLIENT_README.md)
|
71
|
-
base_files.each { |file| copy_file(base_path
|
72
|
+
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
72
73
|
end
|
73
74
|
|
74
75
|
def template_base_files
|
75
76
|
base_path = "base/base/"
|
76
77
|
%w(config/initializers/react_on_rails.rb
|
77
78
|
Procfile.dev
|
78
|
-
app/views/hello_world/index.html.erb
|
79
79
|
package.json
|
80
|
-
client/
|
81
|
-
client/package.json).each { |file| template(base_path + file + ".tt", file) }
|
80
|
+
client/package.json).each { |file| template("#{base_path}#{file}.tt", file) }
|
82
81
|
end
|
83
82
|
|
84
83
|
def add_base_gems_to_gemfile
|
@@ -8,16 +8,16 @@ module ReactOnRails
|
|
8
8
|
Rails::Generators.hide_namespace(namespace)
|
9
9
|
source_root(File.expand_path("../templates", __FILE__))
|
10
10
|
|
11
|
-
def
|
12
|
-
base_path = "
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
template("
|
11
|
+
def create_appropriate_templates
|
12
|
+
base_path = "base/base/"
|
13
|
+
location = "client/app/bundles/HelloWorld/"
|
14
|
+
source = base_path + location
|
15
|
+
config = {
|
16
|
+
component_name: "HelloWorld",
|
17
|
+
app_relative_path: "../components/HelloWorld"
|
18
|
+
}
|
19
|
+
template("#{source}/startup/registration.jsx.tt", "#{location}/startup/registration.jsx", config)
|
20
|
+
template("#{base_path}app/views/hello_world/index.html.erb.tt", "app/views/hello_world/index.html.erb", config)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -17,15 +17,22 @@ module ReactOnRails
|
|
17
17
|
client/app/bundles/HelloWorld/containers/HelloWorldContainer.jsx
|
18
18
|
client/app/bundles/HelloWorld/constants/helloWorldConstants.jsx
|
19
19
|
client/app/bundles/HelloWorld/reducers/helloWorldReducer.jsx
|
20
|
-
client/app/bundles/HelloWorld/store/helloWorldStore.jsx
|
20
|
+
client/app/bundles/HelloWorld/store/helloWorldStore.jsx
|
21
|
+
client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx).each do |file|
|
21
22
|
copy_file(base_path + file, file)
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
def
|
26
|
-
|
27
|
-
location = "client/app/bundles/HelloWorld/
|
28
|
-
|
26
|
+
def create_appropriate_templates
|
27
|
+
base_path = "base/base/"
|
28
|
+
location = "client/app/bundles/HelloWorld/"
|
29
|
+
source = base_path + location
|
30
|
+
config = {
|
31
|
+
component_name: "HelloWorldApp",
|
32
|
+
app_relative_path: "./HelloWorldApp"
|
33
|
+
}
|
34
|
+
template("#{source}/startup/registration.jsx.tt", "#{location}/startup/registration.jsx", config)
|
35
|
+
template("#{base_path}app/views/hello_world/index.html.erb.tt", "app/views/hello_world/index.html.erb", config)
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import React, { PropTypes } from 'react';
|
2
|
+
|
3
|
+
export default class HelloWorld extends React.Component {
|
4
|
+
static propTypes = {
|
5
|
+
name: PropTypes.string.isRequired, // this is passed from the Rails view
|
6
|
+
};
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @param props - Comes from your rails view.
|
10
|
+
* @param _railsContext - Comes from React on Rails
|
11
|
+
*/
|
12
|
+
constructor(props, _railsContext) {
|
13
|
+
super(props);
|
14
|
+
|
15
|
+
// How to set initial state in ES6 class syntax
|
16
|
+
// https://facebook.github.io/react/docs/reusable-components.html#es6-classes
|
17
|
+
this.state = { name: this.props.name };
|
18
|
+
}
|
19
|
+
|
20
|
+
updateName = (name) => {
|
21
|
+
this.setState({ name });
|
22
|
+
};
|
23
|
+
|
24
|
+
render() {
|
25
|
+
return (
|
26
|
+
<div>
|
27
|
+
<h3>
|
28
|
+
Hello, {this.state.name}!
|
29
|
+
</h3>
|
30
|
+
<hr />
|
31
|
+
<form >
|
32
|
+
<label htmlFor="name">
|
33
|
+
Say hello to:
|
34
|
+
</label>
|
35
|
+
<input
|
36
|
+
id="name"
|
37
|
+
type="text"
|
38
|
+
value={this.state.name}
|
39
|
+
onChange={(e) => this.updateName(e.target.value)}
|
40
|
+
/>
|
41
|
+
</form>
|
42
|
+
</div>
|
43
|
+
);
|
44
|
+
}
|
45
|
+
}
|
@@ -1,3 +1,7 @@
|
|
1
|
+
/* eslint comma-dangle: ["error",
|
2
|
+
{"functions": "never", "arrays": "only-multiline", "objects":
|
3
|
+
"only-multiline"} ] */
|
4
|
+
|
1
5
|
const webpack = require('webpack');
|
2
6
|
const path = require('path');
|
3
7
|
|
@@ -9,7 +13,7 @@ const config = {
|
|
9
13
|
'es5-shim/es5-shim',
|
10
14
|
'es5-shim/es5-sham',
|
11
15
|
'babel-polyfill',
|
12
|
-
'./app/bundles/HelloWorld/startup/
|
16
|
+
'./app/bundles/HelloWorld/startup/registration',
|
13
17
|
],
|
14
18
|
|
15
19
|
output: {
|
@@ -68,7 +68,7 @@ fs.watchFile(bundlePath + bundleFileName, (curr) => {
|
|
68
68
|
return;
|
69
69
|
}
|
70
70
|
|
71
|
-
// eslint-disable-next-line global-require
|
71
|
+
// eslint-disable-next-line global-require, import/no-dynamic-require
|
72
72
|
require(bundlePath + bundleFileName);
|
73
73
|
console.log(`Loaded server bundle: ${bundlePath + bundleFileName}`);
|
74
74
|
handler.initialize();
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "react-on-rails",
|
3
|
-
"version": "6.
|
3
|
+
"version": "6.3.0",
|
4
4
|
"description": "react-on-rails JavaScript for react_on_rails Ruby gem",
|
5
5
|
"main": "node_package/lib/ReactOnRails.js",
|
6
6
|
"directories": {
|
@@ -22,12 +22,11 @@
|
|
22
22
|
"babelify": "^7.3.0",
|
23
23
|
"blue-tape": "^1.0.0",
|
24
24
|
"eslint": "^3.8.1",
|
25
|
-
"eslint-config-shakacode": "^
|
25
|
+
"eslint-config-shakacode": "^13.2.0-beta.1",
|
26
26
|
"eslint-plugin-import": "^2.0.1",
|
27
27
|
"eslint-plugin-jsx-a11y": "^2.2.3",
|
28
28
|
"eslint-plugin-react": "^6.4.1",
|
29
|
-
"flow-bin": "^0.
|
30
|
-
"jscs": "^2.11.0",
|
29
|
+
"flow-bin": "^0.36.0",
|
31
30
|
"jsdom": "^9.8.0",
|
32
31
|
"react": "^15.3.2",
|
33
32
|
"react-dom": "^15.3.2",
|
@@ -54,11 +53,9 @@
|
|
54
53
|
"build": "npm run clean && npm run babel",
|
55
54
|
"build-watch": "babel --watch --out-dir node_package/lib node_package/src",
|
56
55
|
"eslint": "eslint .",
|
57
|
-
"jscs": "jscs -e -v .",
|
58
56
|
"flow": "flow check node_package",
|
59
|
-
"lint": "npm run eslint
|
60
|
-
"
|
61
|
-
"check": "npm run lint && npm run test",
|
57
|
+
"lint": "npm run eslint",
|
58
|
+
"check": "npm run lint && npm run flow && npm run test",
|
62
59
|
"prerelease": "npm run check && npm run clean && npm run build",
|
63
60
|
"release:patch": "node_package/scripts/release patch",
|
64
61
|
"release:minor": "node_package/scripts/release minor",
|
data/rakelib/lint.rake
CHANGED
@@ -23,18 +23,13 @@ namespace :lint do
|
|
23
23
|
sh_in_dir(gem_root, "npm run eslint")
|
24
24
|
end
|
25
25
|
|
26
|
-
desc "Run jscs from shell"
|
27
|
-
task :jscs do
|
28
|
-
sh_in_dir(gem_root, "npm run jscs")
|
29
|
-
end
|
30
|
-
|
31
26
|
desc "Run flow from shell"
|
32
27
|
task :flow do
|
33
28
|
sh_in_dir(gem_root, "npm run flow")
|
34
29
|
end
|
35
30
|
|
36
|
-
desc "Run all eslint,
|
37
|
-
task lint: [:eslint, :
|
31
|
+
desc "Run all eslint, flow, rubocop linters. Skip ruby-lint and scss"
|
32
|
+
task lint: [:eslint, :flow, :rubocop] do
|
38
33
|
puts "Completed all linting"
|
39
34
|
end
|
40
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: react_on_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|
@@ -317,7 +317,6 @@ files:
|
|
317
317
|
- ".eslintignore"
|
318
318
|
- ".eslintrc"
|
319
319
|
- ".gitignore"
|
320
|
-
- ".jscsrc"
|
321
320
|
- ".npmignore"
|
322
321
|
- ".rspec"
|
323
322
|
- ".rubocop.yml"
|
@@ -336,11 +335,13 @@ files:
|
|
336
335
|
- book.json
|
337
336
|
- docs/LICENSE
|
338
337
|
- docs/additional-reading/babel.md
|
338
|
+
- docs/additional-reading/code-splitting.md
|
339
339
|
- docs/additional-reading/heroku-deployment.md
|
340
340
|
- docs/additional-reading/hot-reloading-rails-development.md
|
341
341
|
- docs/additional-reading/node-dependencies-and-npm.md
|
342
342
|
- docs/additional-reading/node-server-rendering.md
|
343
343
|
- docs/additional-reading/rails-assets.md
|
344
|
+
- docs/additional-reading/rails-engine-integration.md
|
344
345
|
- docs/additional-reading/rails_view_rendering_from_inline_javascript.md
|
345
346
|
- docs/additional-reading/react-and-redux.md
|
346
347
|
- docs/additional-reading/react-router.md
|
@@ -380,7 +381,8 @@ files:
|
|
380
381
|
- lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt
|
381
382
|
- lib/generators/react_on_rails/templates/base/base/client/.babelrc
|
382
383
|
- lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md
|
383
|
-
- lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx
|
384
|
+
- lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx
|
385
|
+
- lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/registration.jsx.tt
|
384
386
|
- lib/generators/react_on_rails/templates/base/base/client/package.json.tt
|
385
387
|
- lib/generators/react_on_rails/templates/base/base/client/webpack.config.js
|
386
388
|
- lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt
|
@@ -390,8 +392,6 @@ files:
|
|
390
392
|
- lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb
|
391
393
|
- lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb
|
392
394
|
- lib/generators/react_on_rails/templates/dev_tests/spec/spec_helper.rb
|
393
|
-
- lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorldContainer.jsx
|
394
|
-
- lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt
|
395
395
|
- lib/generators/react_on_rails/templates/node/base/client/node/package.json
|
396
396
|
- lib/generators/react_on_rails/templates/node/base/client/node/server.js
|
397
397
|
- lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/actions/helloWorldActionCreators.jsx
|
@@ -460,7 +460,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
460
460
|
version: '0'
|
461
461
|
requirements: []
|
462
462
|
rubyforge_project:
|
463
|
-
rubygems_version: 2.
|
463
|
+
rubygems_version: 2.6.1
|
464
464
|
signing_key:
|
465
465
|
specification_version: 4
|
466
466
|
summary: Rails with react server rendering with webpack.
|
data/.jscsrc
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"preset": "airbnb",
|
3
|
-
"fileExtensions": [
|
4
|
-
".js",
|
5
|
-
".jsx"
|
6
|
-
],
|
7
|
-
"excludeFiles": [
|
8
|
-
"**/.c9/**",
|
9
|
-
"**/build/**",
|
10
|
-
"**/node_modules/**",
|
11
|
-
"**/assets/webpack/**",
|
12
|
-
"**/generated/**",
|
13
|
-
"**/docs/**",
|
14
|
-
"**/tmp/**",
|
15
|
-
"**/sample_generated/**",
|
16
|
-
"**/coverage/**",
|
17
|
-
"**/vendor/**",
|
18
|
-
"**/dummy-for-generators/**",
|
19
|
-
"**/dummy/**",
|
20
|
-
"**/node_package/lib/**",
|
21
|
-
"**/app/assets/javascripts/application.js"
|
22
|
-
],
|
23
|
-
"esprima": "babel-jscs",
|
24
|
-
"validateQuoteMarks": {
|
25
|
-
"mark": "'",
|
26
|
-
"escape": true,
|
27
|
-
"ignoreJSX": true
|
28
|
-
},
|
29
|
-
"requireTrailingComma": false
|
30
|
-
}
|
@@ -1,29 +0,0 @@
|
|
1
|
-
import React, { PropTypes } from 'react';
|
2
|
-
|
3
|
-
// Simple example of a React "dumb" component
|
4
|
-
const HelloWorld = ({ name, updateName }) => (
|
5
|
-
<div className="container">
|
6
|
-
<h3>
|
7
|
-
Hello, {name}!
|
8
|
-
</h3>
|
9
|
-
<hr />
|
10
|
-
<form className="form-horizontal">
|
11
|
-
<label htmlFor="name">
|
12
|
-
Say hello to:
|
13
|
-
</label>
|
14
|
-
<input
|
15
|
-
type="text" value={name} id="name"
|
16
|
-
onChange={(e) => updateName(e.target.value)}
|
17
|
-
/>
|
18
|
-
</form>
|
19
|
-
</div>
|
20
|
-
);
|
21
|
-
|
22
|
-
HelloWorld.propTypes = {
|
23
|
-
// If you have lots of data or action properties, you should consider grouping them by
|
24
|
-
// passing two properties: "data" and "actions".
|
25
|
-
updateName: PropTypes.func.isRequired,
|
26
|
-
name: PropTypes.string.isRequired,
|
27
|
-
};
|
28
|
-
|
29
|
-
export default HelloWorld;
|
@@ -1,25 +0,0 @@
|
|
1
|
-
import React, { PropTypes } from 'react';
|
2
|
-
import HelloWorld from '../components/HelloWorld';
|
3
|
-
|
4
|
-
// Simple example of a React "smart" component
|
5
|
-
export default class HelloWorldContainer extends React.Component {
|
6
|
-
static propTypes = {
|
7
|
-
name: PropTypes.string.isRequired, // this is passed from the Rails view
|
8
|
-
};
|
9
|
-
|
10
|
-
constructor(props) {
|
11
|
-
super(props);
|
12
|
-
|
13
|
-
// How to set initial state in ES6 class syntax
|
14
|
-
// https://facebook.github.io/react/docs/reusable-components.html#es6-classes
|
15
|
-
this.state = { name: this.props.name };
|
16
|
-
}
|
17
|
-
|
18
|
-
updateName = (name) => { this.setState({ name }); };
|
19
|
-
|
20
|
-
render() {
|
21
|
-
return (
|
22
|
-
<HelloWorld name={this.state.name} updateName={this.updateName} />
|
23
|
-
);
|
24
|
-
}
|
25
|
-
}
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import ReactOnRails from 'react-on-rails';
|
3
|
-
|
4
|
-
import HelloWorldContainer from '../containers/HelloWorldContainer';
|
5
|
-
|
6
|
-
// _railsContext is the Rails context, providing contextual information for rendering
|
7
|
-
const HelloWorldApp = (props, _railsContext) => (
|
8
|
-
<HelloWorldContainer {...props} />
|
9
|
-
);
|
10
|
-
|
11
|
-
// This is how react_on_rails can see the HelloWorldApp in the browser.
|
12
|
-
ReactOnRails.register({ HelloWorldApp });
|