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.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -2
  3. data/Gemfile +1 -0
  4. data/README.md +15 -7
  5. data/app/helpers/react_on_rails_helper.rb +8 -1
  6. data/docs/additional-reading/code-splitting.md +155 -0
  7. data/docs/additional-reading/heroku-deployment.md +0 -1
  8. data/docs/additional-reading/rails-engine-integration.md +34 -0
  9. data/lib/generators/react_on_rails/base_generator.rb +4 -5
  10. data/lib/generators/react_on_rails/react_no_redux_generator.rb +10 -10
  11. data/lib/generators/react_on_rails/react_with_redux_generator.rb +12 -5
  12. data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +1 -1
  13. data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx +45 -0
  14. data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/startup/registration.jsx.tt +8 -0
  15. data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +5 -1
  16. data/lib/generators/react_on_rails/templates/node/base/client/node/server.js +1 -1
  17. data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt +1 -2
  18. data/lib/react_on_rails/version.rb +1 -1
  19. data/package.json +5 -8
  20. data/rakelib/lint.rake +2 -7
  21. metadata +7 -7
  22. data/.jscsrc +0 -30
  23. data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorld.jsx.tt +0 -29
  24. data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorldContainer.jsx +0 -25
  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: fa5e89cce86385ef87057cba58202b7a73ec7766
4
- data.tar.gz: 20e2c394c80be8b0bc5bc4f9f3d2b8e30a62a8ae
3
+ metadata.gz: 438f4802448657a19eec8b4e61a88fe92b400fa6
4
+ data.tar.gz: f7cbeef69e4172876e754b1a9f651a55d88a8068
5
5
  SHA512:
6
- metadata.gz: 5940a4eaec389437ea0559397b93630bfc1982658f2e6570f6606dbc88cce54d2cb828ad663fc41bb8938e28f3580e650d5bede7f68e6abe8872814b0d379c1e
7
- data.tar.gz: b1230e48c557b4060d859fcb94727e93f39928ecf209c882c55619b2a26311ba4fc6abfcdde69c7f16cbdc9253b5b83d976d245ed2632808539cdd4290759238
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.2.1...master
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
@@ -32,6 +32,7 @@ gem "web-console", "~> 2.0", group: :development
32
32
 
33
33
  # below are copied from spec/dummy/Gemfile
34
34
  gem "rspec-rails"
35
+ gem "rspec-retry"
35
36
  gem "capybara"
36
37
  gem "capybara-screenshot"
37
38
  gem "capybara-webkit"
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 Skype plus Slack/Github based coaching for React on Rails. [Click here](http://www.shakacode.com/work/index.html) for more information.
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`, or a generator function that returns a React component.
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. [Click here](http://www.shakacode.com/work/index.html) for more information.
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: controller.present? && controller.is_a?(ActionMailer::Base),
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 + ".coffee")
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 + file, file) }
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/app/bundles/HelloWorld/components/HelloWorld.jsx
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 copy_base_files
12
- base_path = "no_redux/base/"
13
- file = "client/app/bundles/HelloWorld/containers/HelloWorldContainer.jsx"
14
- copy_file(base_path + file, file)
15
- end
16
-
17
- def template_appropriate_version_of_hello_world_app
18
- filename = "HelloWorldApp.jsx"
19
- location = "client/app/bundles/HelloWorld/startup"
20
- template("no_redux/base/#{location}/HelloWorldApp.jsx.tt", "#{location}/#{filename}")
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).each do |file|
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 template_appropriate_version_of_hello_world_app
26
- filename = "HelloWorldApp.jsx"
27
- location = "client/app/bundles/HelloWorld/startup"
28
- template("redux/base/#{location}/HelloWorldApp.jsx.tt", "#{location}/#{filename}")
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
@@ -1,3 +1,3 @@
1
1
  <h1>Hello World</h1>
2
- <%%= react_component("HelloWorldApp", props: @hello_world_props, prerender: false) %>
2
+ <%%= react_component("<%= config[:component_name] %>", props: @hello_world_props, prerender: false) %>
3
3
 
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ import ReactOnRails from 'react-on-rails';
2
+
3
+ import <%= config[:component_name] %> from '<%= config[:app_relative_path] %>';
4
+
5
+ // This is how react_on_rails can see the HelloWorld in the browser.
6
+ ReactOnRails.register({
7
+ <%= config[:component_name] %>,
8
+ });
@@ -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/HelloWorldApp',
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();
@@ -16,5 +16,4 @@ const HelloWorldApp = (props, _railsContext) => (
16
16
  </Provider>
17
17
  );
18
18
 
19
- // This is how react_on_rails can see the HelloWorldApp in the browser.
20
- ReactOnRails.register({ HelloWorldApp });
19
+ export default HelloWorldApp;
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ReactOnRails
3
- VERSION = "6.2.1".freeze
3
+ VERSION = "6.3.0".freeze
4
4
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-on-rails",
3
- "version": "6.2.1",
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": "^6.0.0",
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.33.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 && npm run jscs && npm run flow",
60
- "lint:fix": "node_package/scripts/lint-fix",
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, jscs, flow, rubocop linters. Skip ruby-lint and scss"
37
- task lint: [:eslint, :jscs, :flow, :rubocop] do
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.2.1
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-20 00:00:00.000000000 Z
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.tt
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.5.1
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 });