react_on_rails 11.0.3 → 12.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +320 -0
  3. data/.eslintignore +2 -1
  4. data/.eslintrc +30 -2
  5. data/.github/FUNDING.yml +1 -0
  6. data/.gitignore +3 -1
  7. data/.prettierignore +10 -0
  8. data/.prettierrc +23 -0
  9. data/.release-it.json +3 -0
  10. data/.rubocop.yml +39 -11
  11. data/.travis.yml +11 -22
  12. data/CHANGELOG.md +209 -4
  13. data/CONTRIBUTING.md +64 -84
  14. data/Gemfile +3 -5
  15. data/KUDOS.md +4 -1
  16. data/{docs/LICENSE.md → LICENSE.md} +1 -1
  17. data/PROJECTS.md +7 -1
  18. data/REACT-ON-RAILS-PRO-LICENSE +95 -0
  19. data/README.md +233 -634
  20. data/Rakefile +1 -5
  21. data/SUMMARY.md +42 -29
  22. data/book.json +5 -5
  23. data/docs/additional-reading/asset-pipeline.md +8 -16
  24. data/docs/additional-reading/convert-rails-5-api-only-app.md +19 -0
  25. data/docs/additional-reading/credits.md +10 -0
  26. data/docs/additional-reading/images.md +1 -1
  27. data/docs/additional-reading/rails-engine-integration.md +7 -0
  28. data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
  29. data/docs/additional-reading/react-helmet.md +30 -10
  30. data/docs/additional-reading/react-router.md +52 -75
  31. data/docs/additional-reading/server-rendering-tips.md +14 -11
  32. data/docs/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
  33. data/docs/additional-reading/webpack.md +2 -2
  34. data/docs/api/javascript-api.md +24 -4
  35. data/docs/api/redux-store-api.md +102 -0
  36. data/docs/api/view-helpers-api.md +133 -0
  37. data/docs/articles.md +20 -0
  38. data/docs/basics/client-vs-server-rendering.md +23 -0
  39. data/docs/basics/configuration.md +145 -61
  40. data/docs/basics/deployment.md +4 -0
  41. data/docs/basics/{generator.md → generator-details.md} +5 -8
  42. data/docs/basics/heroku-deployment.md +24 -0
  43. data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
  44. data/docs/basics/i18n.md +45 -23
  45. data/docs/basics/installation-into-an-existing-rails-app.md +59 -0
  46. data/docs/basics/minitest-configuration.md +31 -0
  47. data/docs/basics/react-server-rendering.md +29 -0
  48. data/docs/{additional-reading → basics}/recommended-project-structure.md +38 -10
  49. data/docs/basics/render-functions-and-railscontext.md +205 -0
  50. data/docs/basics/rspec-configuration.md +73 -0
  51. data/docs/basics/upgrading-react-on-rails.md +74 -3
  52. data/docs/basics/webpack-configuration.md +50 -0
  53. data/docs/contributor-info/errors-with-hooks.md +45 -0
  54. data/docs/contributor-info/pull-requests.md +44 -0
  55. data/docs/misc/doctrine.md +2 -2
  56. data/docs/{additional-reading → outdated}/code-splitting.md +19 -9
  57. data/docs/outdated/how-react-on-rails-works.md +44 -0
  58. data/docs/{basics/installation-overview.md → outdated/manual-installation-overview.md} +8 -13
  59. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
  60. data/docs/{additional-reading → outdated}/rails-assets.md +5 -13
  61. data/docs/testimonials/hvmn.md +25 -0
  62. data/docs/testimonials/resortpass.md +13 -0
  63. data/docs/testimonials/testimonials.md +28 -0
  64. data/docs/tutorial.md +182 -44
  65. data/jest.config.js +4 -0
  66. data/lib/generators/USAGE +1 -1
  67. data/lib/generators/react_on_rails/base_generator.rb +2 -2
  68. data/lib/generators/react_on_rails/dev_tests_generator.rb +3 -2
  69. data/lib/generators/react_on_rails/generator_helper.rb +4 -6
  70. data/lib/generators/react_on_rails/install_generator.rb +2 -0
  71. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -1
  72. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +26 -0
  73. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +20 -40
  74. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +4 -1
  75. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
  76. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  77. data/lib/react_on_rails/configuration.rb +171 -100
  78. data/lib/react_on_rails/error.rb +2 -0
  79. data/lib/react_on_rails/git_utils.rb +2 -0
  80. data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +133 -161
  81. data/lib/react_on_rails/json_output.rb +1 -1
  82. data/lib/react_on_rails/json_parse_error.rb +28 -0
  83. data/lib/react_on_rails/locales/base.rb +150 -0
  84. data/lib/react_on_rails/locales/to_js.rb +37 -0
  85. data/lib/react_on_rails/locales/to_json.rb +27 -0
  86. data/lib/react_on_rails/prerender_error.rb +56 -18
  87. data/lib/react_on_rails/react_component/render_options.rb +31 -3
  88. data/lib/react_on_rails/server_rendering_js_code.rb +42 -0
  89. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +93 -63
  90. data/lib/react_on_rails/server_rendering_pool.rb +1 -16
  91. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
  92. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
  93. data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +10 -6
  94. data/lib/react_on_rails/test_helper.rb +18 -7
  95. data/lib/react_on_rails/utils.rb +65 -25
  96. data/lib/react_on_rails/version.rb +1 -1
  97. data/lib/react_on_rails/version_checker.rb +5 -1
  98. data/lib/react_on_rails/version_syntax_converter.rb +14 -12
  99. data/lib/react_on_rails/webpacker_utils.rb +44 -10
  100. data/lib/react_on_rails.rb +7 -2
  101. data/lib/tasks/assets.rake +33 -46
  102. data/lib/tasks/locale.rake +4 -2
  103. data/package-scripts.yml +49 -0
  104. data/package.json +49 -40
  105. data/rakelib/dummy_apps.rake +1 -9
  106. data/rakelib/example_type.rb +3 -1
  107. data/rakelib/examples.rake +3 -0
  108. data/rakelib/lint.rake +2 -7
  109. data/rakelib/node_package.rake +2 -2
  110. data/rakelib/release.rake +4 -8
  111. data/rakelib/run_rspec.rake +5 -18
  112. data/react_on_rails.gemspec +5 -6
  113. data/tsconfig.json +14 -0
  114. data/webpackConfigLoader.js +5 -4
  115. data/yarn.lock +7645 -1821
  116. metadata +70 -60
  117. data/Gemfile.rails32 +0 -74
  118. data/docs/additional-reading/babel.md +0 -5
  119. data/docs/additional-reading/caching-and-performance.md +0 -4
  120. data/docs/additional-reading/heroku-deployment.md +0 -92
  121. data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
  122. data/docs/additional-reading/node-server-rendering.md +0 -5
  123. data/docs/additional-reading/rspec-configuration.md +0 -56
  124. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  125. data/docs/api/ruby-api.md +0 -8
  126. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
  127. data/lib/react_on_rails/assets_precompile.rb +0 -150
  128. data/lib/react_on_rails/locales_to_js.rb +0 -134
  129. /data/docs/{misc → outdated}/rails3.md +0 -0
@@ -0,0 +1,102 @@
1
+ # Redux Store
2
+
3
+ _This redux API is no longer recommended as it prevents dynamic code splitting for performance. Instead, you should use the standard react_component view helper passing in a "render function."_
4
+
5
+ You don't need to use the `redux_store` api to use redux. This api was setup to support multiple calls to `react_component` on one page that all talk to the same redux store.
6
+
7
+ If you are only rendering one react component on a page, as is typical to do a "Single Page App" in React, then you should _probably_ pass the props to your React component in a "render function."
8
+
9
+ Consider using the `redux_store` helper for the two following use cases:
10
+
11
+ 1. You want to have multiple React components accessing the same store at once.
12
+ 2. You want to place the props to hydrate the client side stores at the very end of your HTML, probably server rendered, so that the browser can render all earlier HTML first. This is particularly useful if your props will be large. However, you're probably better off using [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki) if you're at all concerned about performance.
13
+
14
+ ## Multiple React Components on a Page with One Store
15
+
16
+ You may wish to have 2 React components share the same the Redux store. For example, if your navbar is a React component, you may want it to use the same store as your component in the main area of the page. You may even want multiple React components in the main area, which allows for greater modularity. Also, you may want this to work with Turbolinks to minimize reloading the JavaScript.
17
+
18
+ A good example of this would be something like a notifications counter in a header. As each notification is read in the body of the page, you would like to update the header. If both the header and body share the same Redux store, then this is trivial. Otherwise, we have to rely on other solutions, such as the header polling the server to see how many unread notifications exist.
19
+
20
+ Suppose the Redux store is called `appStore`, and you have 3 React components that each needs to connect to a store: `NavbarApp`, `CommentsApp`, and `BlogsApp`. I named them with `App` to indicate that they are the registered components.
21
+
22
+ You will need to make a function that can create the store you will be using for all components and register it via the `registerStore` method. Note: this is a **storeCreator**, meaning that it is a function that takes (props, location) and returns a store:
23
+
24
+ ```js
25
+ function appStore(props, railsContext) {
26
+ // Create a hydrated redux store, using props and the railsContext (object with
27
+ // Rails contextual information).
28
+ return myAppStore;
29
+ }
30
+
31
+ ReactOnRails.registerStore({
32
+ appStore
33
+ });
34
+ ```
35
+
36
+ When registering your component with React on Rails, you can get the store via `ReactOnRails.getStore`:
37
+
38
+ ```js
39
+ // getStore will initialize the store if not already initialized, so creates or retrieves store
40
+ const appStore = ReactOnRails.getStore("appStore");
41
+ return (
42
+ <Provider store={appStore}>
43
+ <CommentsApp />
44
+ </Provider>
45
+ );
46
+ ```
47
+
48
+ From your Rails view, you can use the provided helper `redux_store(store_name, props)` to create a fresh version of the store (because it may already exist if you came from visiting a previous page). Note: for this example, since we're initializing this from the main layout, we're using a generic name of `@react_props`. In other words, the Rails controller would set `@react_props` to the properties to hydrate the Redux store.
49
+
50
+ **app/views/layouts/application.html.erb**
51
+
52
+ ```erb
53
+ ...
54
+ <%= redux_store("appStore", props: @react_props) %>;
55
+ <%= react_component("NavbarApp") %>
56
+ yield
57
+ ...
58
+ ```
59
+
60
+ Components should be created as [stateless function(al) components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions). Since you can pass in initial props via the helper `redux_store`, you do not need to pass any props directly to the component. Instead, the component hydrates by connecting to the store.
61
+
62
+ **_comments.html.erb**
63
+
64
+ ```erb
65
+ <%= react_component("CommentsApp") %>
66
+ ```
67
+
68
+ **_blogs.html.erb**
69
+
70
+ ```erb
71
+ <%= react_component("BlogsApp") %>
72
+ ```
73
+
74
+ *Note:* You will not be doing any partial updates to the Redux store when loading a new page. When the page content loads, React on Rails will rehydrate a new version of the store with whatever props are placed on the page.
75
+
76
+ ## Controller Extension
77
+
78
+ Include the module `ReactOnRails::Controller` in your controller, probably in ApplicationController. This will provide the following controller method, which you can call in your controller actions:
79
+
80
+ `redux_store(store_name, props: {})`
81
+
82
+ - **store_name:** A name for the store. You'll refer to this name in 2 places in your JavaScript:
83
+ 1. You'll call `ReactOnRails.registerStore({storeName})` in the same place that you register your components.
84
+ 2. In your component definition, you'll call `ReactOnRails.getStore('storeName')` to get the hydrated Redux store to attach to your components.
85
+ - **props:** Named parameter `props`. ReactOnRails takes care of setting up the hydration of your store with props from the view.
86
+
87
+ For an example, see [spec/dummy/app/controllers/pages_controller.rb](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/app/controllers/pages_controller.rb). Note: this is preferable to using the equivalent view_helper `redux_store` in that you can be assured that the store is initialized before your components.
88
+
89
+ ## View Helper
90
+
91
+ `redux_store(store_name, props: {})`
92
+
93
+ This method has the same API as the controller extension. **HOWEVER**, we recommend the controller extension instead because the Rails executes the template code in the controller action's view file (`erb`, `haml`, `slim`, etc.) before the layout. So long as you call `redux_store` at the beginning of your action's view file, this will work. However, it's an easy mistake to put this call in the wrong place. Calling `redux_store` in the controller action ensures proper load order, regardless of where you call this in the controller action. Note: you won't know of this subtle ordering issue until you server render and you find that your store is not hydrated properly.
94
+
95
+ `redux_store_hydration_data`
96
+
97
+ Place this view helper (no parameters) at the end of your shared layout so ReactOnRails will render the redux store hydration data. Since we're going to be setting up the stores in the controllers, we need to know where on the view to put the client-side rendering of this hydration data, which is a hidden div with a matching class that contains a data props. For an example, see [spec/dummy/app/views/layouts/application.html.erb](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/app/views/layouts/application.html.erb).
98
+
99
+ # More Details
100
+
101
+ * [lib/react_on_rails/controller.rb](../../lib/react_on_rails/controller.rb) source
102
+ * [lib/react_on_rails/helper.rb](../../lib/react_on_rails/helper.rb) source
@@ -0,0 +1,133 @@
1
+ # View and Controller Helpers
2
+ ## View Helpers API
3
+
4
+ Once the bundled files have been generated in your `app/assets/webpack` folder and you have registered your components, you will want to render these components on your Rails views using the included helper method, `react_component`.
5
+
6
+ ------------
7
+
8
+ ### react_component
9
+
10
+ ```ruby
11
+ react_component(component_name,
12
+ props: {},
13
+ prerender: nil)
14
+ html_options: {})
15
+ ```
16
+
17
+ Uncommonly used options:
18
+ ```
19
+ trace: nil,
20
+ replay_console: nil,
21
+ raise_on_prerender_error: nil,
22
+ id: nil,
23
+ ```
24
+
25
+ - **component_name:** Can be a React component, created using an ES6 class or a render function that returns a React component (or, only on the server side, an object with shape { redirectLocation, error, renderedHtml }), or a "renderer function" that manually renders a React component to the dom (client side only).
26
+ All options except `props, id, html_options` will inherit from your `react_on_rails.rb` initializer, as described [here](../basics/configuration.md).
27
+ - **general options:**
28
+ - **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.
29
+ - **prerender:** enable server-side rendering of a component. Set to false when debugging!
30
+ - **id:** Id for the div, will be used to attach the React component. This will get assigned automatically if you do not provide an id. Must be unique.
31
+ - **html_options:** Any other HTML options get placed on the added div for the component. For example, you can set a class (or inline style) on the outer div so that it behaves like a span, with the styling of `display:inline-block`. You may also use an option of `tag: "span"` to replace the use of the default DIV tag to be a SPAN tag.
32
+ - **trace:** set to true to print additional debugging information in the browser. Defaults to true for development, off otherwise. Only on the **client side** will you will see the `railsContext` and your props.
33
+ - **random_dom_id:** True to automatically generate random dom ids when using multiple instances of the same React component on one Rails view.
34
+ - **options if prerender (server rendering) is true:**
35
+ - **replay_console:** Default is true. False will disable echoing server-rendering logs to the browser. While this can make troubleshooting server rendering difficult, so long as you have the configuration of `logging_on_server` set to true, you'll still see the errors on the server.
36
+ - **logging_on_server:** Default is true. True will log JS console messages and errors to the server.
37
+ - **raise_on_prerender_error:** Default is false. True will throw an error on the server side rendering. Your controller will have to handle the error.
38
+
39
+ -------------
40
+
41
+ ### react_component_hash
42
+
43
+ `react_component_hash` is used to return multiple HTML strings for server rendering, such as for
44
+ adding meta-tags to a page. It is exactly like react_component except for the following:
45
+
46
+ 1. `prerender: true` is automatically added to options, as this method doesn't make sense for
47
+ client only rendering.
48
+ 2. Your JavaScript render function for server rendering must return an Object rather than a React Component.
49
+ 3. Your view code must expect an object and not a string.
50
+
51
+ Here is an example of ERB view code:
52
+
53
+ ```erb
54
+ <% react_helmet_app = react_component_hash("ReactHelmetApp", prerender: true,
55
+ props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
56
+ id: "react-helmet-0", trace: true) %>
57
+ <% content_for :title do %>
58
+ <%= react_helmet_app['title'] %>
59
+ <% end %>
60
+ <%= react_helmet_app["componentHtml"] %>
61
+ ```
62
+
63
+ And here is the JavaScript code:
64
+
65
+ ```js
66
+ export default (props, _railsContext) => {
67
+ const componentHtml = renderToString(<ReactHelmet {...props} />);
68
+ const helmet = Helmet.renderStatic();
69
+
70
+ const renderedHtml = {
71
+ componentHtml,
72
+ title: helmet.title.toString(),
73
+ };
74
+ return { renderedHtml };
75
+ };
76
+ ```
77
+
78
+ ------------
79
+
80
+ ### cached_react_component and cached_react_component_hash
81
+ Fragment caching is a [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki) feature. The API is the same as the above, but for 2 differences:
82
+
83
+ 1. The `cache_key` takes the same parameters as any Rails `cache` view helper.
84
+ 1. The **props** are passed via a block so that evaluation of the props is not done unless the cache is broken. Suppose you put your props calculation into some method called `some_slow_method_that_returns_props`:
85
+
86
+ ```ruby
87
+ <%= cached_react_component("App", cache_key: [@user, @post], prerender: true) do
88
+ some_slow_method_that_returns_props
89
+ end %>
90
+ ```
91
+ ------------
92
+
93
+ ### rails_context
94
+
95
+ You can call `rails_context` or `rails_context(server_side: true|false)` from your controller or view to see what values are are in the Rails Context. Pass true or false depending on whether you want to see the server side or the client side rails_context. Typically, for computing cache keys, you should leave server_side as the default true. When calling this from a controller method, use `helpers.rails_context`.
96
+
97
+ ------------
98
+
99
+ ### Renderer Functions (function that will call ReactDOM.render or ReactDOM.hydrate)
100
+
101
+ A "renderer function" is a render function that accepts three arguments (rather than 2): `(props, railsContext, domNodeId) => { ... }`. Instead of returning a React component, a renderer is responsible for installing a callback that will call `ReactDOM.render` (in React 16+, `ReactDOM.hydrate`) to render a React component into the DOM. The "renderer function" is called at the same time the document ready event would instantate the React components into the DOM.
102
+
103
+ Why would you want to call `ReactDOM.hydrate` yourself? One possible use case is [code splitting](docs/outdated/code-splitting.md). In a nutshell, you don't want to load the React component on the DOM node yet. So you want to install some handler that will call `ReactDOM.hydrate` at a later time. In the case of code splitting with server rendering, the server rendered code has any async code loaded and used to server render. Thus, the client code must also fully load any asynch code before server rendering. Otherwise, the client code would first render partially, not matching the server rendering, and then a second later, the full code would render, resulting in an unpleasant flashing on the screen.
104
+
105
+ Renderer functions are not meant to be used on the server since there's no DOM on the server. Instead, use a render function. Attempting to server render with a renderer function will throw an error.
106
+
107
+ ------------
108
+
109
+ ### React Router
110
+
111
+ [React Router](https://github.com/reactjs/react-router) is supported, including server-side rendering! See:
112
+
113
+ 1. [React on Rails docs for react-router](../additional-reading/react-router.md)
114
+ 2. 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).
115
+ 3. [Code Splitting docs](docs/outdated/code-splitting.md) for information about how to set up code splitting for server rendered routes.
116
+
117
+ ------------
118
+
119
+ ## server_render_js
120
+
121
+ `server_render_js(js_expression, options = {})`
122
+
123
+ - js_expression, like 2 + 3, and not a block of js code. If you have more than one line that needs to be executed, wrap it in an [IIFE](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression). JS exceptions will be caught, and console messages will be handled properly
124
+ - Currently, the only option you may pass is `replay_console` (boolean)
125
+
126
+ This is a helper method that takes any JavaScript expression and returns the output from evaluating it. If you have more than one line that needs to be executed, wrap it in an IIFE. JS exceptions will be caught and console messages handled properly.
127
+
128
+ ------------
129
+
130
+ # More details
131
+
132
+ See the [lib/react_on_rails/helper.rb](../../lib/react_on_rails/helper.rb) source.
133
+
data/docs/articles.md ADDED
@@ -0,0 +1,20 @@
1
+ # Articles, Videos, and Podcasts
2
+
3
+ ## Articles
4
+
5
+ * [Introducing React on Rails v9 with Webpacker Support](https://blog.shakacode.com/introducing-react-on-rails-v9-with-webpacker-support-f2584c6c8fa4) for an overview of the integration of React on Rails with Webpacker.
6
+ * [Webpacker Lite: Why Fork Webpacker?](https://blog.shakacode.com/webpacker-lite-why-fork-webpacker-f0a7707fac92)
7
+ * [React on Rails, 2000+ 🌟 Stars](https://medium.com/shakacode/react-on-rails-2000-stars-32ff5cfacfbf#.6gmfb2gpy)
8
+ * [The React on Rails Doctrine](https://medium.com/@railsonmaui/the-react-on-rails-doctrine-3c59a778c724)
9
+ * [Simple Tutorial](docs/tutorial.md).
10
+
11
+ ## Videos
12
+
13
+ * [Video of running the v9 installer with Webpacker v3](https://youtu.be/M0WUM_XPaII). History, motivations, philosophy, and overview.
14
+ 1. [GORUCO 2017: Front-End Sadness to Happiness: The React on Rails Story by Justin Gordon](https://www.youtube.com/watch?v=SGkTvKRPYrk)
15
+ 2. [egghead.io: Creating a component with React on Rails](https://egghead.io/lessons/react-creating-a-component-with-react-on-rails)
16
+ 3. [egghead.io: Creating a redux component with React on Rails](https://egghead.io/lessons/react-add-redux-state-management-to-a-react-on-rails-project)
17
+ 4. [React On Rails Tutorial Series](https://www.youtube.com/playlist?list=PL5VAKH-U1M6dj84BApfUtvBjvF-0-JfEU)
18
+ 1. [History and Motivation](https://youtu.be/F4oymbUHvoY)
19
+ 2. [Basic Tutorial Walkthrough](https://youtu.be/_bjScw60FBk)
20
+ 3. [Code Walkthrough](https://youtu.be/McQ9UM-_ocQ)
@@ -0,0 +1,23 @@
1
+ # Client-Side Rendering vs. Server-Side Rendering
2
+
3
+ In most cases, you should use the `prerender: false` (default behavior) with the provided helper method to render the React component from your Rails views. In some cases, such as when SEO is vital, or many users will not have JavaScript enabled, you can enable server-rendering by passing `prerender: true` to your helper, or you can simply change the default in `config/initializers/react_on_rails`.
4
+
5
+ Now the server will interpret your JavaScript. The default is to use [ExecJS](https://github.com/rails/execjs) and pass the resulting HTML to the client. We recommend using [mini_racer](https://github.com/discourse/mini_racer) as ExecJS's runtime.
6
+
7
+ If you want to maximize the perfomance of your server rendering, then you want to use React on Rails Pro which uses NodeJS to do the server rendering. See the [docs for React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
8
+
9
+ If you open the HTML source of any web page using React on Rails, you'll see the 3 parts of React on Rails rendering:
10
+
11
+ 1. A script tag containing the properties of the React component, such as the registered name and any props. A JavaScript function runs after the page loads, using this data to build and initialize your React components.
12
+ 2. The wrapper div `<div id="HelloWorld-react-component-0">` specifies the div where to place the React rendering. It encloses the server-rendered HTML for the React component.
13
+ 3. Additional JavaScript is placed to console-log any messages, such as server rendering errors. Note: these server side logs can be configured only to be sent to the server logs.
14
+
15
+ **Note**: If server rendering is not used (prerender: false), then the major difference is that the HTML rendered for the React component only contains the outer div: `<div id="HelloWorld-react-component-0"/>`. The first specification of the React component is just the same.
16
+
17
+ # Different Server-Side Rendering Code (and a Server-Specific Bundle)
18
+
19
+ You may want different code for your server-rendered components running server side versus client side. For example, if you have an animation that runs when a component is displayed, you might need to turn that off when server rendering. One way to handle this is conditional code like `if (window) { doClientOnlyCode() }`.
20
+
21
+ Another way is to use a separate webpack configuration file that can use a different server side entry file, like 'serverRegistration.js' as opposed to 'clientRegistration.js.' That would set up different code for server rendering.
22
+
23
+ For details on techniques to use different code for client and server rendering, see: [How to use different versions of a file for client and server rendering](https://forum.shakacode.com/t/how-to-use-different-versions-of-a-file-for-client-and-server-rendering/1352). _Requires creating a free account._
@@ -1,66 +1,78 @@
1
1
  Here is the full set of config options. This file is `/config/initializers/react_on_rails.rb`
2
2
 
3
+ First, you should have a `/config/webpacker.yml` setup.
4
+
5
+ Here is the setup when using the recommended `/client` directory for your node_modules and source files:
6
+
7
+ ```yaml
8
+ # Note: Base output directory of /public is assumed for static files
9
+ default: &default
10
+ compile: false
11
+ # Used in your webpack configuration. Must be created in the
12
+ # public_output_path folder
13
+ manifest: manifest.json
14
+ cache_manifest: false
15
+
16
+ # Source path is used to check if webpack compilation needs to be run for `compile: true`
17
+ source_path: client/app
18
+
19
+ development:
20
+ <<: *default
21
+ # Generated files for development, in /public/webpack/dev
22
+ public_output_path: webpack/dev
23
+
24
+ test:
25
+ <<: *default
26
+ # Ensure that webpacker invokes webpack to build files for tests if not using the
27
+ # ReactOnRails rspec helper.
28
+ compile: true
29
+
30
+ # Generated files for tests, in /public/webpack/test
31
+ public_output_path: webpack/test
32
+
33
+ production:
34
+ <<: *default
35
+ # Generated files for production, in /public/webpack/production
36
+ public_output_path: webpack/production
37
+ cache_manifest: true
38
+ ```
39
+
40
+ Here's a representative `/config/initializers/react_on_rails.rb` setup when using this `/client` directory
41
+ for all client files, including your sources and node_modules.
42
+
43
+
3
44
  ```ruby
4
45
  # frozen_string_literal: true
5
46
 
6
47
  # NOTE: you typically will leave the commented out configurations set to their defaults.
7
48
  # Thus, you only need to pay careful attention to the non-commented settings in this file.
8
-
9
49
  ReactOnRails.configure do |config|
10
50
  # `trace`: General debugging flag.
11
51
  # The default is true for development, off otherwise.
12
52
  # With true, you get detailed logs of rendering and stack traces if you call setTimout,
13
53
  # setInterval, clearTimout when server rendering.
14
- config.trace = Rails.env.development?
15
-
16
-
17
- # defaults to "" (top level)
18
- #
19
- config.node_modules_location = ""
20
-
21
- # This configures the script to run to build the production assets by webpack. Set this to nil
22
- # if you don't want react_on_rails building this file for you.
54
+ config.trace = Rails.env.development? # default
55
+
56
+ # Configure if default DOM IDs have a random value or are fixed.
57
+ # false ==> Sets the dom id to "#{react_component_name}-react-component"
58
+ # true ==> Adds "-#{SecureRandom.uuid}" to that ID
59
+ # If you might use multiple instances of the same React component on a Rails page, then
60
+ # it is convenient to set this to true or else you have to either manually set the ids to
61
+ # avoid collisions. Most newer apps will have only one instance of a component on a page,
62
+ # so this should be false in most cases.
63
+ # This value can be overridden for a given call to react_component
64
+ config.random_dom_id = true # default
65
+
66
+ # defaults to "" (top level)
67
+ config.node_modules_location = "client" # If using webpacker you should use "".
68
+
69
+ # This configures the script to run to build the production assets by webpack . Set this to nil
70
+ # if you don't want react_on_rails building this file for you.
71
+ # Note, if you want to use this command then you should remove the file
72
+ # config/webpack/production.js
73
+ # If that file exists, React on Rails thinks that you'll use the rails/webpacker bin/webpack compiler.
23
74
  config.build_production_command = "RAILS_ENV=production bin/webpack"
24
75
 
25
- ################################################################################
26
- ################################################################################
27
- # TEST CONFIGURATION OPTIONS
28
- # Below options are used with the use of this test helper:
29
- # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
30
- ################################################################################
31
-
32
- # If you are using this in your spec_helper.rb (or rails_helper.rb):
33
- #
34
- # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
35
- #
36
- # with rspec then this controls what yarn command is run
37
- # to automatically refresh your webpack assets on every test run.
38
- #
39
- config.build_test_command = "RAILS_ENV=test bin/webpack"
40
-
41
- # Directory where your generated assets go. All generated assets must go to the same directory.
42
- # If you are using webpacker, this value will come from your config/webpacker.yml file.
43
- # This is the default in webpacker.yml:
44
- # public_output_path: packs-test
45
- # which means files in /public/packs-test
46
- #
47
- # Alternately, you may configure this. It is relative to your Rails root directory.
48
- # A custom, non-webpacker, config might use something like:
49
- #
50
- config.generated_assets_dir = File.join(%w[public webpack], Rails.env)
51
-
52
- # The test helper needs to know where your JavaScript files exist. The default is configured
53
- # by your config/webpacker.yml soure_path:
54
- # source_path: app/javascript
55
- #
56
- # If you have a non-default `node_modules_location`, that is assumed to be the location of your source
57
- # files.
58
-
59
- # Define the files we need to check for webpack compilation when running tests.
60
- # The default is `%w( manifest.json )` as will be sufficient for most webpacker builds.
61
- #
62
- config.webpack_generated_files = %w( manifest.json )
63
-
64
76
  ################################################################################
65
77
  ################################################################################
66
78
  # SERVER RENDERING OPTIONS
@@ -72,31 +84,43 @@ ReactOnRails.configure do |config|
72
84
  # JavaScript execution instances which should handle any component requested.
73
85
  #
74
86
  # While you may configure this to be the same as your client bundle file, this file is typically
75
- # different.
76
- #
87
+ # different. Note, be sure to include the exact file name with the ".js" if you are not hashing this file.
88
+ # If you are hashing this file (supposing you are using the same file for client rendering), then
89
+ # you should include a name that matches your bundle name in your webpack config.
77
90
  config.server_bundle_js_file = "server-bundle.js"
78
91
 
92
+ # THE BELOW OPTIONS FOR SERVER-SIDE RENDERING RARELY NEED CHANGING
93
+ #
94
+ # This value only affects server-side rendering when using the webpack-dev-server
95
+ # If you are hashing the server bundle and you want to use the same bundle for client and server,
96
+ # you'd set this to `true` so that React on Rails reads the server bundle from the webpack-dev-server.
97
+ # Normally, you have different bundles for client and server, thus, the default is false.
98
+ # Furthermore, if you are not hashing the server bundle (not in the manifest.json), then React on Rails
99
+ # will only look for the server bundle to be created in the typical file location, typically by
100
+ # a `webpack --watch` process.
101
+ # If true, ensure that in config/webpacker.yml that you have both dev_server.hmr and
102
+ # dev_server.inline set to false.
103
+ config.same_bundle_for_client_and_server = false
104
+
79
105
  # If set to true, this forces Rails to reload the server bundle if it is modified
80
106
  # Default value is Rails.env.development?
81
- #
107
+ # You probably will never change this.
82
108
  config.development_mode = Rails.env.development?
83
109
 
84
- # For server rendering so that it replays in the browser console.
110
+ # For server rendering so that the server-side console replays in the browser console.
85
111
  # This can be set to false so that server side messages are not displayed in the browser.
86
- # Default is true. Be cautious about turning this off.
112
+ # Default is true. Be cautious about turning this off, as it can make debugging difficult.
87
113
  # Default value is true
88
- #
89
114
  config.replay_console = true
90
115
 
91
116
  # Default is true. Logs server rendering messages to Rails.logger.info. If false, you'll only
92
117
  # see the server rendering messages in the browser console.
93
- #
94
118
  config.logging_on_server = true
95
119
 
96
- # Default is to false to NOT raise exception on server if the JS code throws.
97
- # Reason is that it's easier to debug this when you get the error over to the client.
98
- #
99
- config.raise_on_prerender_error = false
120
+ # Default is true only for development? to raise exception on server if the JS code throws for
121
+ # server rendering. The reason is that the server logs will show the error and force you to fix
122
+ # any server rendering issues immediately during development.
123
+ config.raise_on_prerender_error = Rails.env.development?
100
124
 
101
125
  ################################################################################
102
126
  # Server Renderer Configuration for ExecJS
@@ -120,6 +144,7 @@ ReactOnRails.configure do |config|
120
144
  # Replace the following line to the location where you keep translation.js & default.js for use
121
145
  # by the npm packages react-intl. Be sure this directory exists!
122
146
  # config.i18n_dir = Rails.root.join("client", "app", "libs", "i18n")
147
+ #
123
148
  # If not using the i18n feature, then leave this section commented out or set the value
124
149
  # of config.i18n_dir to nil.
125
150
  #
@@ -127,8 +152,12 @@ ReactOnRails.configure do |config|
127
152
  # that will source for automatic generation on translations.js & default.js
128
153
  # By default(without this option) all yaml files from Rails.root.join("config", "locales")
129
154
  # and installed gems are loaded
130
- config.i18n_yml_dir = Rails.root.join("config", "locales", "client")
155
+ config.i18n_yml_dir = Rails.root.join("config", "locales")
131
156
 
157
+ # Possible output formats are js and json
158
+ # The default format is json
159
+ config.i18n_output_format = 'json'
160
+
132
161
  ################################################################################
133
162
  ################################################################################
134
163
  # CLIENT RENDERING OPTIONS
@@ -137,6 +166,61 @@ ReactOnRails.configure do |config|
137
166
  ################################################################################
138
167
  # default is false
139
168
  config.prerender = false
169
+
170
+ # You can optionally add values to your rails_context. This object is passed
171
+ # every time a component renders.
172
+ # See example below for an example definition of RenderingExtension
173
+ #
174
+ # config.rendering_extension = RenderingExtension
175
+
176
+ ################################################################################
177
+ ################################################################################
178
+ # TEST CONFIGURATION OPTIONS
179
+ # Below options are used with the use of this test helper:
180
+ # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
181
+ #
182
+ # NOTE:
183
+ # Instead of using this test helper, you may ensure fresh test files using rails/webpacker via:
184
+ # 1. Have `config/webpacker/test.js` exporting an array of objects to configure both client and server bundles.
185
+ # 2. Set the compile option to true in config/webpacker.yml for env test
186
+ ################################################################################
187
+
188
+ # If you are using this in your spec_helper.rb (or rails_helper.rb):
189
+ #
190
+ # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
191
+ #
192
+ # with rspec then this controls what yarn command is run
193
+ # to automatically refresh your webpack assets on every test run.
194
+ #
195
+ config.build_test_command = "RAILS_ENV=test bin/webpack"
196
+
197
+ # CONFIGURE YOUR SOURCE FILES
198
+ # The test helper needs to know where your JavaScript files exist. The value is configured
199
+ # by your config/webpacker.yml source_path:
200
+ # source_path: client/app # if using recommended /client directory
201
+ #
202
+ # Define the files we need to check for webpack compilation when running tests.
203
+ # The default is `%w( manifest.json )` as will be sufficient for most webpacker builds.
204
+ # However, if you are generated a server bundle that is NOT hashed (present in manifest.json),
205
+ # then include the file in this list like this:
206
+ config.webpack_generated_files = %w( server-bundle.js manifest.json )
207
+ # Note, be sure NOT to include your server-bundle.js if it is hashed, or else React on Rails will
208
+ # think the server-bundle.js is missing every time for test runs.
140
209
  end
210
+ ```
211
+
212
+ Example of a RenderingExtension for custom values in the `rails_context`:
141
213
 
214
+ ```ruby
215
+ module RenderingExtension
216
+
217
+ # Return a Hash that contains custom values from the view context that will get merged with
218
+ # the standard rails_context values and passed to all calls to render functions used by the
219
+ # react_component and redux_store view helpers
220
+ def self.custom_context(view_context)
221
+ {
222
+ somethingUseful: view_context.session[:something_useful]
223
+ }
224
+ end
225
+ end
142
226
  ```
@@ -0,0 +1,4 @@
1
+ # Deployment
2
+
3
+ - `rails/webpacker` puts the necessary precompile steps automatically in the rake precompile step.
4
+ - See the [Heroku Deployment](docs/basics/heroku-deployment.md) doc for specifics regarding Heroku. The information for Heroku may apply to other deployments.
@@ -1,7 +1,4 @@
1
- - [Generator](#generator)
2
- - [Understanding the Organization of the Generated Client Code](#understanding-the-organization-of-the-generated-client-code)
3
- - [Redux](#redux)
4
- - [Using Images and Fonts](#using-images-and-fonts)
1
+ # Generator Details
5
2
 
6
3
  The `react_on_rails:install` generator combined with the example pull requests of generator runs will get you up and running efficiently. There's a fair bit of setup with integrating Webpack with Rails. Defaults for options are such that the default is for the flag to be off. For example, the default for `-R` is that `redux` is off, and the default of `-b` is that `skip-bootstrap` is off.
7
4
 
@@ -41,13 +38,13 @@ Then you may run
41
38
 
42
39
  More Details:
43
40
 
44
- `https://github.com/shakacode/react_on_rails/blob/master/docs/basics/generator.md`
41
+ `https://github.com/shakacode/react_on_rails/blob/master/docs/basics/generator-details.md`
45
42
  ```
46
43
 
47
44
  Another good option is to create a simple test app per the [Tutorial](../tutorial.md).
48
45
 
49
- ### Understanding the Organization of the Generated Client Code
50
- The generated client code follows our organization scheme. Each unique set of functionality, is given its own folder inside of `client/app/bundles`. This encourages for modularity of *domains*.
46
+ # Understanding the Organization of the Generated Client Code
47
+ The generated client code follows our organization scheme. Each unique set of functionality, is given its own folder inside of `app/javascript/app/bundles`. Note, the recommended for bigger projects is `client/app/bundles`. This encourages for modularity of *domains*.
51
48
 
52
49
  Inside of the generated "HelloWorld" domain you will find the following folders:
53
50
 
@@ -57,7 +54,7 @@ Inside of the generated "HelloWorld" domain you will find the following folders:
57
54
 
58
55
  You may also notice the `app/lib` folder. This is for any code that is common between bundles and therefore needs to be shared (for example, middleware).
59
56
 
60
- ### Redux
57
+ ## Redux
61
58
  If you have used the `--redux` generator option, you will notice the familiar additional redux folders in addition to the aforementioned folders. The Hello World example has also been modified to use Redux.
62
59
 
63
60
  Note the organizational paradigm of "bundles". These are like application domains and are used for grouping your code into webpack bundles, in case you decide to create different bundles for deployment. This is also useful for separating out logical parts of your application. The concept is that each bundle will have it's own Redux store. If you have code that you want to reuse across bundles, including components and reducers, place them under `/client/app/lib`.
@@ -0,0 +1,24 @@
1
+ # Heroku Deployment
2
+ ## Heroku buildpacks
3
+
4
+ React on Rails requires both a ruby environment (for Rails) and a Node environment (for Webpack), so you will need to have Heroku use multiple buildpacks.
5
+
6
+ Assuming you have downloaded and installed the Heroku command-line utility and have initialized the app, you will need to tell Heroku to use both buildpacks via the command-line:
7
+
8
+ ```
9
+ heroku buildpacks:set heroku/ruby
10
+ heroku buildpacks:add --index 1 heroku/nodejs
11
+ ```
12
+
13
+ For more information, see [Using Multiple Buildpacks for an App](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app)
14
+
15
+ ## assets:precompile
16
+
17
+ ### rails/webpacker webpack configuration
18
+ If you're using the standard rails/webpacker configuration of webpack, then rails/webpacker
19
+ will automatically modify or create an assets:precompile task to build your assets.
20
+
21
+ ### custom webpack configuration
22
+ If you're a custom webpack configuration, and you **do not have the default
23
+ `config/webpack/production.js`** file, then the `config/initializers/react_on_rails.rb`
24
+ configuration `config.build_production_command` will be used.