react_on_rails 11.0.5 → 13.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +338 -0
  3. data/.eslintignore +2 -1
  4. data/.eslintrc +32 -3
  5. data/.github/FUNDING.yml +1 -0
  6. data/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  8. data/.github/PULL_REQUEST_TEMPLATE.md +19 -0
  9. data/.github/workflows/lint-js-and-ruby.yml +54 -0
  10. data/.github/workflows/main.yml +183 -0
  11. data/.github/workflows/package-js-tests.yml +35 -0
  12. data/.github/workflows/rspec-package-specs.yml +46 -0
  13. data/.gitignore +3 -4
  14. data/.prettierignore +14 -0
  15. data/.prettierrc +20 -0
  16. data/.rubocop.yml +76 -34
  17. data/.travis.yml +15 -22
  18. data/CHANGELOG.md +443 -55
  19. data/CONTRIBUTING.md +62 -80
  20. data/Gemfile +1 -35
  21. data/Gemfile.development_dependencies +50 -0
  22. data/KUDOS.md +4 -1
  23. data/{docs/LICENSE.md → LICENSE.md} +1 -1
  24. data/NEWS.md +14 -4
  25. data/REACT-ON-RAILS-PRO-LICENSE +95 -0
  26. data/README.md +107 -802
  27. data/Rakefile +1 -8
  28. data/SUMMARY.md +51 -29
  29. data/book.json +5 -5
  30. data/docs/{basics/generator.md → additional-details/generator-details.md} +5 -13
  31. data/docs/{basics/installation-overview.md → additional-details/manual-installation-overview.md} +9 -14
  32. data/docs/{basics → additional-details}/migrating-from-react-rails.md +1 -1
  33. data/docs/additional-details/recommended-project-structure.md +69 -0
  34. data/docs/additional-details/tips-for-usage-with-sp6.md +15 -0
  35. data/docs/additional-details/upgrade-webpacker-v3-to-v4.md +10 -0
  36. data/docs/api/javascript-api.md +35 -6
  37. data/docs/api/redux-store-api.md +102 -0
  38. data/docs/api/view-helpers-api.md +133 -0
  39. data/docs/contributor-info/errors-with-hooks.md +45 -0
  40. data/docs/contributor-info/linters.md +5 -6
  41. data/docs/contributor-info/pull-requests.md +42 -0
  42. data/docs/contributor-info/releasing.md +1 -1
  43. data/docs/deployment/heroku-deployment.md +39 -0
  44. data/docs/getting-started.md +196 -0
  45. data/docs/guides/client-vs-server-rendering.md +27 -0
  46. data/docs/guides/configuration.md +289 -0
  47. data/docs/guides/deployment.md +5 -0
  48. data/docs/guides/file-system-based-automated-bundle-generation.md +197 -0
  49. data/docs/guides/hmr-and-hot-reloading-with-the-webpack-dev-server.md +104 -0
  50. data/docs/guides/how-react-on-rails-works.md +44 -0
  51. data/docs/guides/how-to-conditionally-server-render-based-on-device-type.md +40 -0
  52. data/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md +98 -0
  53. data/docs/guides/i18n.md +87 -0
  54. data/docs/guides/installation-into-an-existing-rails-app.md +66 -0
  55. data/docs/guides/minitest-configuration.md +31 -0
  56. data/docs/guides/rails-webpacker-react-integration-options.md +213 -0
  57. data/docs/guides/react-on-rails-overview.md +29 -0
  58. data/docs/guides/react-server-rendering.md +32 -0
  59. data/docs/guides/render-functions-and-railscontext.md +205 -0
  60. data/docs/guides/rspec-configuration.md +73 -0
  61. data/docs/guides/tutorial.md +371 -0
  62. data/docs/{basics → guides}/upgrading-react-on-rails.md +126 -3
  63. data/docs/guides/webpack-configuration.md +42 -0
  64. data/docs/home.md +23 -0
  65. data/docs/javascript/asset-pipeline.md +12 -0
  66. data/docs/{additional-reading → javascript}/code-splitting.md +21 -11
  67. data/docs/javascript/converting-from-custom-webpack-config-to-rails-webpacker-config.md +10 -0
  68. data/docs/javascript/credits.md +10 -0
  69. data/docs/{additional-reading → javascript}/images.md +5 -6
  70. data/docs/javascript/react-helmet.md +100 -0
  71. data/docs/javascript/react-router.md +90 -0
  72. data/docs/{additional-reading → javascript}/server-rendering-tips.md +15 -12
  73. data/docs/javascript/troubleshooting-when-using-shakapacker.md +77 -0
  74. data/docs/{additional-reading → javascript}/webpack.md +2 -2
  75. data/docs/misc/articles.md +20 -0
  76. data/docs/misc/doctrine.md +5 -6
  77. data/docs/outdated/deferred-rendering.md +39 -0
  78. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +4 -4
  79. data/docs/{additional-reading → outdated}/rails-assets.md +12 -20
  80. data/docs/{misc → outdated}/rails3.md +2 -2
  81. data/docs/rails/convert-rails-5-api-only-app.md +19 -0
  82. data/docs/rails/rails-engine-integration.md +32 -0
  83. data/docs/{additional-reading → rails}/rails_view_rendering_from_inline_javascript.md +2 -1
  84. data/docs/{additional-reading → rails}/turbolinks.md +13 -1
  85. data/docs/react-on-rails-pro/react-on-rails-pro.md +43 -0
  86. data/docs/testimonials/hvmn.md +25 -0
  87. data/docs/testimonials/resortpass.md +13 -0
  88. data/docs/testimonials/testimonials.md +28 -0
  89. data/jest.config.js +4 -0
  90. data/lib/generators/USAGE +1 -1
  91. data/lib/generators/react_on_rails/adapt_for_older_shakapacker_generator.rb +41 -0
  92. data/lib/generators/react_on_rails/base_generator.rb +55 -43
  93. data/lib/generators/react_on_rails/bin/dev +30 -0
  94. data/lib/generators/react_on_rails/bin/dev-static +30 -0
  95. data/lib/generators/react_on_rails/dev_tests_generator.rb +4 -3
  96. data/lib/generators/react_on_rails/generator_helper.rb +8 -6
  97. data/lib/generators/react_on_rails/generator_messages.rb +40 -0
  98. data/lib/generators/react_on_rails/install_generator.rb +37 -0
  99. data/lib/generators/react_on_rails/templates/.eslintrc +3 -1
  100. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +4 -6
  101. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static +9 -0
  102. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +21 -40
  103. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +4 -0
  104. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js +5 -0
  105. data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js +8 -0
  106. data/lib/generators/react_on_rails/templates/base/base/app/views/layouts/hello_world.html.erb +2 -1
  107. data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +32 -0
  108. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +20 -4
  109. data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +62 -0
  110. data/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt +17 -0
  111. data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +17 -0
  112. data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +25 -0
  113. data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +9 -0
  114. data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +117 -0
  115. data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +9 -0
  116. data/lib/generators/react_on_rails/templates/base/base/config/webpack/webpack.config.js.tt +15 -0
  117. data/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js.tt +36 -0
  118. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +8 -2
  119. data/lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb +1 -1
  120. data/lib/generators/react_on_rails/templates/dev_tests/spec/{features → system}/hello_world_spec.rb +2 -2
  121. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +6 -9
  122. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  123. data/lib/react_on_rails/configuration.rb +198 -145
  124. data/lib/react_on_rails/error.rb +2 -0
  125. data/lib/react_on_rails/git_utils.rb +5 -3
  126. data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +201 -190
  127. data/lib/react_on_rails/json_output.rb +1 -1
  128. data/lib/react_on_rails/json_parse_error.rb +28 -0
  129. data/lib/react_on_rails/locales/base.rb +169 -0
  130. data/lib/react_on_rails/locales/to_js.rb +33 -0
  131. data/lib/react_on_rails/locales/to_json.rb +23 -0
  132. data/lib/react_on_rails/packs_generator.rb +234 -0
  133. data/lib/react_on_rails/prerender_error.rb +35 -27
  134. data/lib/react_on_rails/react_component/render_options.rb +64 -9
  135. data/lib/react_on_rails/server_rendering_js_code.rb +55 -0
  136. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +126 -76
  137. data/lib/react_on_rails/server_rendering_pool.rb +0 -1
  138. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +9 -8
  139. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
  140. data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +13 -12
  141. data/lib/react_on_rails/test_helper.rb +24 -3
  142. data/lib/react_on_rails/utils.rb +94 -25
  143. data/lib/react_on_rails/version.rb +1 -1
  144. data/lib/react_on_rails/version_checker.rb +5 -1
  145. data/lib/react_on_rails/version_syntax_converter.rb +14 -12
  146. data/lib/react_on_rails/webpacker_utils.rb +105 -5
  147. data/lib/react_on_rails.rb +8 -2
  148. data/lib/tasks/assets.rake +28 -60
  149. data/lib/tasks/generate_packs.rake +11 -0
  150. data/lib/tasks/locale.rake +5 -4
  151. data/package-scripts.yml +49 -0
  152. data/package.json +52 -47
  153. data/rakelib/docker.rake +0 -5
  154. data/rakelib/dummy_apps.rake +5 -8
  155. data/rakelib/example_type.rb +12 -3
  156. data/rakelib/examples.rake +5 -4
  157. data/rakelib/lint.rake +5 -16
  158. data/rakelib/node_package.rake +2 -2
  159. data/rakelib/release.rake +37 -23
  160. data/rakelib/run_rspec.rake +16 -44
  161. data/rakelib/task_helpers.rb +16 -4
  162. data/react_on_rails.gemspec +6 -22
  163. data/tsconfig.json +14 -0
  164. data/webpackConfigLoader.js +5 -4
  165. data/yarn.lock +5935 -3106
  166. metadata +122 -272
  167. data/Gemfile.rails32 +0 -74
  168. data/docs/additional-reading/asset-pipeline.md +0 -20
  169. data/docs/additional-reading/babel.md +0 -5
  170. data/docs/additional-reading/caching-and-performance.md +0 -4
  171. data/docs/additional-reading/heroku-deployment.md +0 -92
  172. data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
  173. data/docs/additional-reading/node-server-rendering.md +0 -5
  174. data/docs/additional-reading/rails-engine-integration.md +0 -34
  175. data/docs/additional-reading/react-helmet.md +0 -80
  176. data/docs/additional-reading/react-router.md +0 -113
  177. data/docs/additional-reading/recommended-project-structure.md +0 -49
  178. data/docs/additional-reading/rspec-configuration.md +0 -56
  179. data/docs/additional-reading/webpack-dev-server.md +0 -15
  180. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  181. data/docs/api/ruby-api.md +0 -8
  182. data/docs/basics/configuration.md +0 -163
  183. data/docs/basics/i18n.md +0 -77
  184. data/docs/tutorial.md +0 -220
  185. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
  186. data/lib/react_on_rails/assets_precompile.rb +0 -150
  187. data/lib/react_on_rails/locales_to_js.rb +0 -134
  188. data/ruby-lint.yml +0 -25
  189. /data/docs/{additional-reading → additional-details}/updating-dependencies.md +0 -0
  190. /data/docs/{additional-reading → deployment}/elastic-beanstalk.md +0 -0
  191. /data/docs/{additional-reading → javascript}/angular-js-integration-migration.md +0 -0
  192. /data/docs/{additional-reading → javascript}/capistrano-deployment.md +0 -0
  193. /data/docs/{additional-reading → javascript}/foreman-issues.md +0 -0
  194. /data/docs/{additional-reading → javascript}/node-dependencies-and-npm.md +0 -0
  195. /data/docs/{additional-reading → javascript}/react-and-redux.md +0 -0
  196. /data/docs/{additional-reading → javascript}/troubleshooting-when-using-webpacker.md +0 -0
  197. /data/docs/{additional-reading → javascript}/webpack-v1-notes.md +0 -0
  198. /data/docs/{coding-style → misc}/style.md +0 -0
  199. /data/docs/{additional-reading → misc}/tips.md +0 -0
@@ -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`](https://www.shakacode.com/react-on-rails/docs/api/view-helpers-api/#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 a React Function Component, 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). Note, a "renderer function" is a special type of "Render-Function." A "renderer function" takes a 3rd param of a DOM ID.
26
+ All options except `props, id, html_options` will inherit from your `react_on_rails.rb` initializer, as described [here](https://www.shakacode.com/react-on-rails/docs/guides/configuration/).
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
+ - **auto_load_bundle:** will automatically load the bundle for component by calling `append_javascript_pack_tag` and `append_stylesheet_pack_tag` under the hood.
31
+ - **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.
32
+ - **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.
33
+ - **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.
34
+ - **random_dom_id:** True to automatically generate random dom ids when using multiple instances of the same React component on one Rails view.
35
+ - **options if prerender (server rendering) is true:**
36
+ - **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.
37
+ - **logging_on_server:** Default is true. True will log JS console messages and errors to the server.
38
+ - **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.
39
+
40
+ -------------
41
+
42
+ ### react_component_hash
43
+
44
+ `react_component_hash` is used to return multiple HTML strings for server rendering, such as for
45
+ adding meta-tags to a page. It is exactly like react_component except for the following:
46
+
47
+ 1. `prerender: true` is automatically added to options, as this method doesn't make sense for
48
+ client only rendering.
49
+ 2. Your JavaScript Render-Function for server rendering must return an Object rather than a React Component.
50
+ 3. Your view code must expect an object and not a string.
51
+
52
+ Here is an example of ERB view code:
53
+
54
+ ```erb
55
+ <% react_helmet_app = react_component_hash("ReactHelmetApp", prerender: true,
56
+ props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
57
+ id: "react-helmet-0", trace: true) %>
58
+ <% content_for :title do %>
59
+ <%= react_helmet_app['title'] %>
60
+ <% end %>
61
+ <%= react_helmet_app["componentHtml"] %>
62
+ ```
63
+
64
+ And here is the JavaScript code:
65
+
66
+ ```js
67
+ export default (props, _railsContext) => {
68
+ const componentHtml = renderToString(<ReactHelmet {...props} />);
69
+ const helmet = Helmet.renderStatic();
70
+
71
+ const renderedHtml = {
72
+ componentHtml,
73
+ title: helmet.title.toString(),
74
+ };
75
+ return { renderedHtml };
76
+ };
77
+ ```
78
+
79
+ ------------
80
+
81
+ ### cached_react_component and cached_react_component_hash
82
+ 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:
83
+
84
+ 1. The `cache_key` takes the same parameters as any Rails `cache` view helper.
85
+ 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`:
86
+
87
+ ```ruby
88
+ <%= cached_react_component("App", cache_key: [@user, @post], prerender: true) do
89
+ some_slow_method_that_returns_props
90
+ end %>
91
+ ```
92
+ ------------
93
+
94
+ ### rails_context
95
+
96
+ 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`.
97
+
98
+ ------------
99
+
100
+ ### Renderer Functions (function that will call ReactDOM.render or ReactDOM.hydrate)
101
+
102
+ 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.
103
+
104
+ Why would you want to call `ReactDOM.hydrate` yourself? One possible use case is [code splitting](https://www.shakacode.com/react-on-rails/docs/javascript/code-splitting/). 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.
105
+
106
+ 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.
107
+
108
+ ------------
109
+
110
+ ### React Router
111
+
112
+ [React Router](https://github.com/reactjs/react-router) is supported, including server-side rendering! See:
113
+
114
+ 1. [React on Rails docs for react-router](https://www.shakacode.com/react-on-rails/docs/javascript/react-router/)
115
+ 2. Examples in [spec/dummy/app/views/react_router](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/app/views/react_router) and follow to the JavaScript code in the [spec/dummy/client/app/startup/ServerRouterApp.jsx](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/client/app/startup/ServerRouterApp.jsx).
116
+ 3. [Code Splitting docs](https://www.shakacode.com/react-on-rails/docs/javascript/code-splitting/) for information about how to set up code splitting for server rendered routes.
117
+
118
+ ------------
119
+
120
+ ## server_render_js
121
+
122
+ `server_render_js(js_expression, options = {})`
123
+
124
+ - 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
125
+ - Currently, the only option you may pass is `replay_console` (boolean)
126
+
127
+ 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.
128
+
129
+ ------------
130
+
131
+ # More details
132
+
133
+ See the [lib/react_on_rails/helper.rb](https://github.com/shakacode/react_on_rails/tree/master/lib/react_on_rails/helper.rb) source.
@@ -0,0 +1,45 @@
1
+ # Invalid hook call error
2
+
3
+ ```
4
+ react.development.js:1465 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
5
+ 1. You might have mismatching versions of React and the renderer (such as React DOM)
6
+ 2. You might be breaking the Rules of Hooks
7
+ 3. You might have more than one copy of React in the same app
8
+ See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
9
+ ```
10
+
11
+ The main reason to get this is due to multiple versions of React installed.
12
+
13
+ ```
14
+ cd <top level>
15
+ npm ls react
16
+
17
+ cd spec/dummy
18
+ npm ls react
19
+ ```
20
+
21
+ For the second one, you might get:
22
+
23
+ ```
24
+ react_on_rails@ /Users/justin/shakacode/react-on-rails/react_on_rails/spec/dummy
25
+ ├── react@16.13.1
26
+ └─┬ react-on-rails@12.0.0 -> /Users/justin/shakacode/react-on-rails/react_on_rails invalid
27
+ └── react@16.13.1 extraneous
28
+
29
+ npm ERR! invalid: react-on-rails@12.0.0 /Users/justin/shakacode/react-on-rails/react_on_rails/spec/dummy/node_modules/react-on-rails
30
+ npm ERR! extraneous: react@16.13.1 /Users/justin/shakacode/react-on-rails/react_on_rails/spec/dummy/node_modules/react-on-rails/node_modules/react
31
+ ```
32
+
33
+ Make sure there is only one version of React installed!
34
+
35
+ If you used yarn link, then you'll have two versions of React installed.
36
+
37
+ Instead use [Yalc](https://github.com/whitecolor/yalc).
38
+
39
+ ```
40
+ cd <top level>
41
+ yalc publish
42
+
43
+ cd spec/dummy
44
+ yalc link react-on-rails
45
+ ```
@@ -1,5 +1,5 @@
1
1
  # Linters
2
- These linters support the [ShakaCode Style Guidelines](./style.md)
2
+ These linters support the [ShakaCode Style Guidelines](https://www.shakacode.com/react-on-rails/docs/misc/style/)
3
3
 
4
4
  ## Autofix!
5
5
 
@@ -15,9 +15,9 @@ If you haven't tried the autofix options for `eslint` and `rubocop`, you're seri
15
15
  ```
16
16
  eslint --fix .
17
17
  ```
18
-
19
- or
20
-
18
+
19
+ or
20
+
21
21
  ```
22
22
  npm run lint -- --fix
23
23
  ```
@@ -32,7 +32,7 @@ Rules are configured with a 0, 1 or 2. Setting a rule to 0 is turning it off, se
32
32
 
33
33
  Rules can also take a few additional options. In this case, the rule can be set to an array, the first item of which is the 0/1/2 flag and the rest are options.
34
34
 
35
- See file [.eslintrc](../../client/.eslintrc) for examples of configuration
35
+ See file [.eslintrc](https://github.com/shakacode/react_on_rails/tree/master/.eslintrc) for examples of configuration
36
36
 
37
37
  ### Specify/Override rules in code
38
38
 
@@ -66,4 +66,3 @@ You can disable all rules for a line or block, or only specific rules, as shown
66
66
  * [ESLint quick start](http://untilfalse.com/eslint-quick-start/)
67
67
  * [RuboCop](https://github.com/bbatsov/rubocop)
68
68
  * [ESLint](http://eslint.org/)
69
-
@@ -0,0 +1,42 @@
1
+ # Pull Requests
2
+
3
+ ## Checklist before Committing
4
+ 1. `rake`: runs all linters and specs (you need Docker setup, see below)
5
+ 2. Did you need any more tests for your change?
6
+ 3. Did you document your change? Update the README.md?
7
+ 4. Did you add a CHANGELOG.md entry?
8
+
9
+
10
+ For non-doc fixes:
11
+
12
+ * Provide changelog entry in the [unreleased section of the CHANGELOG.md](https://github.com/shakacode/react_on_rails/blob/master/CHANGELOG.md#unreleased).
13
+ * Ensure CI passes and that you added a test that passes with the fix and fails without the fix.
14
+ * Squash all commits down to one with a nice commit message *ONLY* once final review is given. Make sure this single commit is rebased on top of master.
15
+ * Please address all code review comments.
16
+ * Ensure that docs are updated accordingly if a feature is added.
17
+
18
+ ## Commit Messages
19
+
20
+ From [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/)
21
+
22
+ #### The seven rules of a great git commit message
23
+ > Keep in mind: This has all been said before.
24
+
25
+ 1. Separate subject from body with a blank line
26
+ 1. Limit the subject line to 50 characters
27
+ 1. Capitalize the subject line
28
+ 1. Do not end the subject line with a period
29
+ 1. Use the imperative mood in the subject line
30
+ 1. Wrap the body at 72 characters
31
+ 1. Use the body to explain what and why vs. how
32
+
33
+ ## Doc Changes
34
+
35
+ When making doc changes, we want the change to work on both the gitbook and the regular github site. The issue is that non-doc files will not go to the gitbook site, so doc references to non doc files must use the github URL.
36
+
37
+ ### Links to other docs:
38
+ * When making references to doc files, use a relative URL path like:
39
+ `[Installation Overview](https://www.shakacode.com/react-on-rails/docs/additional-details/manual-installation-overview/)`
40
+
41
+ * When making references to source code files, use a full url path like:
42
+ `[spec/dummy/config/initializers/react_on_rails.rb](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/config/initializers/react_on_rails.rb)`
@@ -3,7 +3,7 @@
3
3
  We're now releasing this as a combined ruby gem plus npm package. We will keep the version numbers in sync.
4
4
 
5
5
  ## Testing the Gem before Release from a Rails App
6
- See [Contributing](../../CONTRIBUTING.md)
6
+ See [Contributing](https://github.com/shakacode/react_on_rails/tree/master/CONTRIBUTING.md)
7
7
 
8
8
  ## Releasing a new gem version
9
9
  Run `rake -D release` to see instructions on how to release via the rake task.
@@ -0,0 +1,39 @@
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
+ ```bash
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
+ ### Shakapacker webpack configuration
18
+
19
+ Shakapacker hooks up a new `shakapacker:compile` task to `assets:precompile`, which gets run whenever you run `assets:precompile`.
20
+ If you are not using Sprockets, `shakapacker:compile` is automatically aliased to `assets:precompile`.
21
+
22
+ If you're using the standard `shakacode/shakapacker` configuration of webpack, then `shakacode/shakapacker`
23
+ will automatically modify or create an `assets:precompile` task to build your assets.
24
+
25
+ Alternatively, you can specify `config.build_production_command` to have
26
+ `react_on_rails` invoke a command for you during `assets:precompile`.
27
+
28
+ ```bash
29
+ config.build_production_command = "RAILS_ENV=production NODE_ENV=production bin/shakapacker"
30
+ ```
31
+
32
+ ### Consider Removing Shakapacker's clean task
33
+
34
+ If you are deploying on Heroku, then you don't need Shakapacker's clean task which
35
+ might delete files that you need.
36
+
37
+ ```bash
38
+ Rake::Task['shakapacker:clean'].clear
39
+ ```
@@ -0,0 +1,196 @@
1
+ # Getting Started
2
+
3
+ Note, the best way to understand how to use ReactOnRails is to study a few simple examples. You can do a quick demo setup, either on your existing app or on a new Rails app.
4
+
5
+ This documentation assumes the usage of ReactOnRails with Shakapacker 7. For installation on Shakapacker 6, check [tips for usage with Shakapacker 6](https://www.shakacode.com/react-on-rails/docs/aditional-details/tips-for-usage-with-sp6) first.
6
+
7
+ 1. Do the quick [tutorial](https://www.shakacode.com/react-on-rails/docs/guides/tutorial/).
8
+ 2. Add React on Rails to an existing Rails app per [the instructions](https://www.shakacode.com/react-on-rails/docs/guides/installation-into-an-existing-rails-app/).
9
+ 3. Look at [spec/dummy](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy), a simple, no DB example.
10
+ 3. Look at [github.com/shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial); it's a full-featured example live at [www.reactrails.com](http://reactrails.com).
11
+
12
+ ## Basic Installation
13
+
14
+ You need a Rails application with Shakapacker installed and configured on it. Check [Shakapacker documentation](https://github.com/shakacode/shakapacker) for more details but typically you need the following steps:
15
+
16
+ ```bash
17
+ rails new PROJECT_NAME --skip-javascript
18
+ cd PROJECT_NAME
19
+ bundle add shakapacker --strict
20
+ rails shakapacker:install
21
+ ```
22
+
23
+ You may need to check [the instructions for installing into an existing Rails app](https://www.shakacode.com/react-on-rails/docs/guides/installation-into-an-existing-rails-app/) if you have an already working Rails application.
24
+
25
+ 1. Add the `react_on_rails` gem to Gemfile:
26
+
27
+ ```bash
28
+ bundle add react_on_rails --strict
29
+ ```
30
+
31
+ Commit this to git (or else you cannot run the generator in the next step unless you pass the option `--ignore-warnings`).
32
+
33
+ 2. Run the install generator:
34
+
35
+ ```bash
36
+ rails generate react_on_rails:install
37
+ ```
38
+
39
+ 3. Start the app:
40
+
41
+ - Run `./bin/dev` for HMR
42
+ - Run `./bin/dev-static` for statically created bundles (no HMR)
43
+
44
+ 4. Visit http://localhost:3000/hello_world.
45
+
46
+
47
+ ### Turning on server rendering
48
+
49
+ With the code from running the React on Rails generator above:
50
+
51
+ 1. Edit `app/views/hello_world/index.html.erb` and set the `prerender` option to `true`.
52
+
53
+ You may need to use `Node` as your js runtime environment by setting `EXECJS_RUNTIME=Node` into your environment variables.
54
+
55
+ 2. Refresh the page.
56
+
57
+ Below is the line where you turn server rendering on by setting `prerender` to true:
58
+
59
+ ```erb
60
+ <%= react_component("HelloWorld", props: @hello_world_props, prerender: true) %>
61
+ ```
62
+
63
+ Note, if you got an error in your console regarding "ReferenceError: window is not defined",
64
+ then you need to edit `config/shakapacker.yml` and set `hmr: false` and `inline: false`.
65
+ See [rails/webpacker PR 2644](https://github.com/rails/webpacker/pull/2644) for a fix for this
66
+ issue.
67
+
68
+ ## Basic Usage
69
+
70
+ ### Configuration
71
+
72
+ * Configure `config/initializers/react_on_rails.rb`. You can adjust some necessary settings and defaults. See file [docs/basics/configuration.md](https://www.shakacode.com/react-on-rails/docs/guides/configuration/) for documentation of all configuration options.
73
+ * Configure `config/shakapacker.yml`. If you used the generator and the default Shakapacker setup, you don't need to touch this file. If you are customizing your setup, then consult the [spec/dummy/config/shakapacker.yml](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/config/shakapacker.yml) example or the official default [shakapacker.yml](https://github.com/shakacode/shakapacker/blob/master/lib/install/config/shakapacker.yml).
74
+ * Most apps should rely on the Shakapacker setup for Webpack. Shakapacker v6+ includes support for webpack version 5.
75
+
76
+ ## Including your React Component on your Rails Views
77
+
78
+ - React components are rendered via your Rails Views. Here's an ERB sample:
79
+
80
+ ```erb
81
+ <%= react_component("HelloWorld", props: @some_props) %>
82
+ ```
83
+
84
+ - **Server-Side Rendering**: Your React component is first rendered into HTML on the server. Use the **prerender** option:
85
+
86
+ ```erb
87
+ <%= react_component("HelloWorld", props: @some_props, prerender: true) %>
88
+ ```
89
+
90
+ - The `component_name` parameter is a string matching the name you used to expose your React component globally. So, in the above examples, if you had a React component named "HelloWorld", you would register it with the following lines:
91
+
92
+ ```js
93
+ import ReactOnRails from 'react-on-rails';
94
+ import HelloWorld from './HelloWorld';
95
+ ReactOnRails.register({ HelloWorld });
96
+ ```
97
+
98
+ Exposing your component in this way is how React on Rails is able to reference your component from a Rails view. You can expose as many components as you like, as long as their names do not collide. See below for the details of how you expose your components via the react_on_rails webpack configuration. You may call `ReactOnRails.register` many times.
99
+
100
+ - `@some_props` can be either a hash or JSON string. This is an optional argument assuming you do not need to pass any options (if you want to pass options, such as `prerender: true`, but you do not want to pass any properties, simply pass an empty hash `{}`). This will make the data available in your component:
101
+
102
+ ```ruby
103
+ # Rails View
104
+ <%= react_component("HelloWorld", props: { name: "Stranger" }) %>
105
+ ```
106
+
107
+ - This is what your HelloWorld.js file might contain. The railsContext is always available for any parameters that you _always_ want available for your React components. It has _nothing_ to do with the concept of the [React Context](https://reactjs.org/docs/context.html). See [Render-Functions and the RailsContext](https://www.shakacode.com/react-on-rails/docs/guides/render-functions-and-railscontext/) for more details on this topic.
108
+
109
+ ```js
110
+ import React from 'react';
111
+
112
+ export default (props, railsContext) => {
113
+ // Note wrap in a function to make this a React function component
114
+ return () => (
115
+ <div>
116
+ Your locale is {railsContext.i18nLocale}.<br/>
117
+ Hello, {props.name}!
118
+ </div>
119
+ );
120
+ };
121
+ ```
122
+
123
+ See the [View Helpers API](https://www.shakacode.com/react-on-rails/docs/api/view-helpers-api/) for more details on `react_component` and its sibling function `react_component_hash`.
124
+
125
+ ## Globally Exposing Your React Components
126
+
127
+ For the React on Rails view helper `react_component` to use your React components, you will have to **register** them in your JavaScript code.
128
+
129
+ Use modules just as you would when using Webpack and React without Rails. The difference is that instead of mounting React components directly to an element using `React.render`, you **register your components to ReactOnRails and then mount them with helpers inside of your Rails views**.
130
+
131
+ This is how to expose a component to the `react_component` view helper.
132
+
133
+ ```javascript
134
+ // app/javascript/packs/hello-world-bundle.js
135
+ import HelloWorld from '../components/HelloWorld';
136
+ import ReactOnRails from 'react-on-rails';
137
+ ReactOnRails.register({ HelloWorld });
138
+ ```
139
+
140
+ #### Different Server-Side Rendering Code (and a Server-Specific Bundle)
141
+
142
+ 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() }`.
143
+
144
+ 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.
145
+
146
+ 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._)
147
+
148
+ ## Specifying Your React Components: Register directly or use render-functions
149
+
150
+ You have two ways to specify your React components. You can either register the React component (either function or class component) directly, or you can create a function that returns a React component, which we using the name of a "render-function". Creating a render-function allows you to:
151
+
152
+ 1. Access to the `railsContext`. See the [documentation for the railsContext](https://www.shakacode.com/react-on-rails/docs/guides/render-functions-and-railscontext/) in terms of why you might need it. You **need** a Render-Function to access the `railsContext`.
153
+ 2. Use the passed-in props to initialize a redux store or set up `react-router`.
154
+ 3. Return different components depending on what's in the props.
155
+
156
+ Note, the return value of a **Render-Function** should be either a React Function or Class Component or an object representing server rendering results.
157
+
158
+ **Do not return a React Element (JSX).**
159
+
160
+ ReactOnRails will automatically detect a registered Render-Function by the fact that the function takes
161
+ more than 1 parameter. In other words, if you want the ability to provide a function that returns the
162
+ React component, then you need to specify at least a second parameter. This is the `railsContext`.
163
+ If you're not using this parameter, declare your function with the unused param:
164
+
165
+ ```js
166
+ const MyComponentGenerator = (props, _railsContext) => {
167
+ if (props.print) {
168
+ // This is a React FunctionComponent because it is wrapped in a function.
169
+ return () => <H1>{JSON.stringify(props)}</H1>;
170
+ }
171
+ }
172
+ ```
173
+
174
+ Thus, there is no difference between registering a React Function Component or class Component versus a "Render-Function." Just call `ReactOnRails.register`.
175
+
176
+ ## react_component_hash for Render-Functions
177
+
178
+ Another reason to use a Render-Function is that sometimes in server rendering, specifically with React Router, you need to return the result of calling ReactDOMServer.renderToString(element). You can do this by returning an object with the following shape: `{ renderedHtml, redirectLocation, error }`. Make sure you use this function with `react_component_hash`.
179
+
180
+ For server rendering, if you wish to return multiple HTML strings from a Render-Function, you may return an Object from your Render-Function with a single top-level property of `renderedHtml`. Inside this Object, place a key called `componentHtml`, along with any other needed keys. An example scenario of this is when you are using side effects libraries like [React Helmet](https://github.com/nfl/react-helmet). Your Ruby code will get this Object as a Hash containing keys `componentHtml` and any other custom keys that you added:
181
+
182
+ ```js
183
+ { renderedHtml: { componentHtml, customKey1, customKey2} }
184
+ ```
185
+
186
+ For details on using react_component_hash with react-helmet, see [our react-helmet documentation](https://www.shakacode.com/react-on-rails/docs/additional-reading/react-helmet/).
187
+
188
+ ## Error Handling
189
+
190
+ * All errors from ReactOnRails will be of type ReactOnRails::Error.
191
+ * Prerendering (server rendering) errors get context information for HoneyBadger and Sentry for easier debugging.
192
+
193
+ ## I18n
194
+
195
+ React on Rails provides an option for automatic conversions of Rails `*.yml` locale files into `*.json` or `*.js*.
196
+ See the [How to add I18n](https://www.shakacode.com/react-on-rails/docs/guides/i18n/) for a summary of adding I18n.
@@ -0,0 +1,27 @@
1
+ # Client-Side Rendering vs. Server-Side Rendering
2
+
3
+ *Also, see [our react server-rendering documentation](https://www.shakacode.com/react-on-rails/docs/guides/react-server-rendering/).*
4
+
5
+ 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`.
6
+
7
+ 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. By default, ExecJS uses the Node.js runtime. You can use alternative runtimes as outlined in [ExecJS readme](https://github.com/rails/execjs/blob/master/README.md).
8
+
9
+ Note: if you use the [mini_racer](https://github.com/rubyjs/mini_racer) runtime and run into a `ReferenceError: TextEncoder is not defined` error, see [this comment](https://github.com/shakacode/react_on_rails/issues/1457#issuecomment-1165026717) for a solution.
10
+
11
+ If you want to maximize the performance 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).
12
+
13
+ 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:
14
+
15
+ 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.
16
+ 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.
17
+ 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.
18
+
19
+ **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.
20
+
21
+ # Different Server-Side Rendering Code (and a Server-Specific Bundle)
22
+
23
+ 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() }`.
24
+
25
+ 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.
26
+
27
+ 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._