react_on_rails 11.3.0 → 12.0.0.pre.beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +320 -0
  3. data/.eslintignore +2 -1
  4. data/.eslintrc +23 -1
  5. data/.github/FUNDING.yml +1 -0
  6. data/.gitignore +3 -1
  7. data/.prettierignore +10 -1
  8. data/.prettierrc +3 -0
  9. data/.rubocop.yml +37 -11
  10. data/.travis.yml +9 -22
  11. data/CHANGELOG.md +65 -6
  12. data/CONTRIBUTING.md +60 -71
  13. data/Gemfile +3 -4
  14. data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
  15. data/README.md +129 -92
  16. data/Rakefile +0 -7
  17. data/SUMMARY.md +7 -11
  18. data/book.json +5 -5
  19. data/docs/additional-reading/asset-pipeline.md +8 -16
  20. data/docs/additional-reading/react-helmet.md +30 -10
  21. data/docs/additional-reading/react-router.md +52 -75
  22. data/docs/additional-reading/server-rendering-tips.md +12 -7
  23. data/docs/api/javascript-api.md +3 -3
  24. data/docs/api/redux-store-api.md +4 -2
  25. data/docs/api/view-helpers-api.md +6 -7
  26. data/docs/basics/configuration.md +83 -69
  27. data/docs/basics/deployment.md +2 -4
  28. data/docs/basics/heroku-deployment.md +24 -0
  29. data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
  30. data/docs/basics/i18n.md +45 -23
  31. data/docs/basics/installation-into-an-existing-rails-app.md +4 -9
  32. data/docs/basics/react-server-rendering.md +1 -1
  33. data/docs/basics/recommended-project-structure.md +5 -22
  34. data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
  35. data/docs/basics/rspec-configuration.md +27 -16
  36. data/docs/basics/upgrading-react-on-rails.md +58 -2
  37. data/docs/basics/webpack-configuration.md +18 -8
  38. data/docs/contributor-info/errors-with-hooks.md +45 -0
  39. data/docs/contributor-info/pull-requests.md +44 -0
  40. data/docs/misc/doctrine.md +1 -1
  41. data/docs/{misc-pending → outdated}/code-splitting.md +12 -8
  42. data/docs/{basics → outdated}/how-react-on-rails-works.md +8 -4
  43. data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
  44. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
  45. data/docs/{misc-pending → outdated}/rails-assets.md +2 -12
  46. data/docs/{misc → outdated}/rails3.md +0 -0
  47. data/docs/tutorial.md +94 -68
  48. data/jest.config.js +4 -0
  49. data/lib/generators/react_on_rails/base_generator.rb +2 -2
  50. data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
  51. data/lib/generators/react_on_rails/generator_helper.rb +4 -6
  52. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -1
  53. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +26 -0
  54. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +20 -40
  55. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +4 -1
  56. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
  57. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  58. data/lib/react_on_rails.rb +3 -1
  59. data/lib/react_on_rails/configuration.rb +58 -28
  60. data/lib/react_on_rails/error.rb +2 -0
  61. data/lib/react_on_rails/helper.rb +41 -91
  62. data/lib/react_on_rails/json_parse_error.rb +2 -0
  63. data/lib/react_on_rails/locales/base.rb +150 -0
  64. data/lib/react_on_rails/locales/to_js.rb +37 -0
  65. data/lib/react_on_rails/locales/to_json.rb +27 -0
  66. data/lib/react_on_rails/prerender_error.rb +11 -15
  67. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +41 -46
  68. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
  69. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
  70. data/lib/react_on_rails/utils.rb +14 -19
  71. data/lib/react_on_rails/version.rb +1 -1
  72. data/lib/react_on_rails/version_checker.rb +1 -0
  73. data/lib/react_on_rails/webpacker_utils.rb +19 -2
  74. data/lib/tasks/assets.rake +33 -46
  75. data/lib/tasks/locale.rake +4 -2
  76. data/package-scripts.yml +11 -8
  77. data/package.json +29 -28
  78. data/rakelib/dummy_apps.rake +1 -9
  79. data/rakelib/example_type.rb +3 -1
  80. data/rakelib/examples.rake +3 -0
  81. data/rakelib/lint.rake +2 -7
  82. data/rakelib/node_package.rake +2 -2
  83. data/rakelib/release.rake +0 -6
  84. data/rakelib/run_rspec.rake +5 -18
  85. data/react_on_rails.gemspec +4 -5
  86. data/tsconfig.json +14 -0
  87. data/webpackConfigLoader.js +3 -2
  88. data/yarn.lock +4333 -2209
  89. metadata +46 -57
  90. data/Gemfile.rails32 +0 -73
  91. data/docs/additional-reading/babel.md +0 -5
  92. data/docs/additional-reading/heroku-deployment.md +0 -92
  93. data/docs/additional-reading/hot-reloading-rails-development-asset-pipeline.md +0 -47
  94. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  95. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
  96. data/lib/react_on_rails/assets_precompile.rb +0 -153
  97. data/lib/react_on_rails/locales_to_js.rb +0 -138
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ preset: 'ts-jest/presets/js-with-ts',
3
+ testEnvironment: 'jsdom',
4
+ };
@@ -33,7 +33,7 @@ module ReactOnRails
33
33
  app/views/layouts/hello_world.html.erb
34
34
  config/initializers/react_on_rails.rb
35
35
  Procfile.dev
36
- Procfile.dev-server]
36
+ Procfile.dev-hmr]
37
37
  base_files.each { |file| copy_file("#{base_path}#{file}", file) }
38
38
  end
39
39
 
@@ -107,7 +107,7 @@ module ReactOnRails
107
107
  foreman start -f Procfile.dev
108
108
 
109
109
  - To turn on HMR, edit config/webpacker.yml and set HMR to true. Restart the rails server
110
- and bin/webpack-dev-server. Or use Procfile.dev-server.
110
+ and bin/webpack-dev-server. Or use Procfile.dev-hmr.
111
111
 
112
112
  - To server render, change this line app/views/hello_world/index.html.erb to
113
113
  `prerender: true` to see server rendering (right click on page and select "view source").
@@ -50,7 +50,7 @@ module ReactOnRails
50
50
  contents = File.read(package_json)
51
51
  replacement_value = <<-STRING
52
52
  "scripts": {
53
- "postinstall": "yarn link react-on-rails",
53
+ "postinstall": "yalc link react-on-rails",
54
54
  STRING
55
55
  new_client_package_json_contents = contents.gsub(/ {2}"scripts": {/,
56
56
  replacement_value)
@@ -15,13 +15,11 @@ module GeneratorHelper
15
15
  end
16
16
 
17
17
  def setup_file_error(file, data)
18
- # rubocop:disable Layout/IndentHeredoc
19
- <<-MSG
20
- #{file} was not found.
21
- Please add the following content to your #{file} file:
22
- #{data}
18
+ <<~MSG
19
+ #{file} was not found.
20
+ Please add the following content to your #{file} file:
21
+ #{data}
23
22
  MSG
24
- # rubocop:enable Layout/IndentHeredoc
25
23
  end
26
24
 
27
25
  def empty_directory_with_keep_file(destination, config = {})
@@ -4,4 +4,6 @@ web: rails s -p 3000
4
4
  # Next line runs a watch process with webpack to compile the changed files.
5
5
  # When making frequent changes to client side assets, you will prefer building webpack assets
6
6
  # upon saving rather than when you refresh your browser page.
7
- client: sh -c 'rm -rf public/packs/* || true && bundle exec rake react_on_rails:locale && bin/webpack -w'
7
+ # Note, if using React on Rails localization you will need to run
8
+ # `bundle exec rake react_on_rails:locale` before you run bin/webpack
9
+ client: sh -c 'rm -rf public/packs/* || true && bin/webpack -w'
@@ -0,0 +1,26 @@
1
+ # Procfile for development using HMR
2
+
3
+ web: rails s -p 3000
4
+
5
+ # Note, hot and live reloading don't work with the default generator setup on
6
+ # top of the rails/webpacker Webpack config with server rendering.
7
+ # If you have server rendering enabled (prerender is true), you either need to
8
+ # a. Ensure that you have dev_server.hmr and dev_server.inline BOTH set to false,
9
+ # and you have this option in your config/initializers/react_on_rails.rb:
10
+ # config.same_bundle_for_client_and_server = true
11
+ # If you have either config/webpacker.yml option set to true, you'll see errors like
12
+ # "ReferenceError: window is not defined" (if hmr is true)
13
+ # "TypeError: Cannot read property 'prototype' of undefined" (if inline is true)
14
+ # b. Skip using the webpack-dev-server. bin/webpack --watch is typically
15
+ fast enough.
16
+ # c. See the React on Rails README for a link to documentation for how to setup
17
+ # SSR with HMR and React hot loading using the webpack-dev-server only for the
18
+ # client bundles and a static file for the server bundle.
19
+
20
+ # Run the webpack-dev-server for client and maybe server files
21
+ webpack-dev-server: bin/webpack-dev-server
22
+
23
+ # Keep the JS fresh for server rendering. Remove if not server rendering.
24
+ # Especially if you have not configured generation of a server bundle without a hash.
25
+ # as that will conflict with the manifest created by the bin/webpack-dev-server
26
+ # rails-server-assets: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
@@ -1,45 +1,25 @@
1
1
  import PropTypes from 'prop-types';
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
 
4
- export default class HelloWorld extends React.Component {
5
- static propTypes = {
6
- name: PropTypes.string.isRequired, // this is passed from the Rails view
7
- };
4
+ const HelloWorld = (props) => {
5
+ const [name, setName] = useState(props.name);
8
6
 
9
- /**
10
- * @param props - Comes from your rails view.
11
- */
12
- constructor(props) {
13
- super(props);
7
+ return (
8
+ <div>
9
+ <h3>Hello, {name}!</h3>
10
+ <hr />
11
+ <form>
12
+ <label htmlFor="name">
13
+ Say hello to:
14
+ <input id="name" type="text" value={name} onChange={(e) => setName(e.target.value)} />
15
+ </label>
16
+ </form>
17
+ </div>
18
+ );
19
+ };
14
20
 
15
- // How to set initial state in ES6 class syntax
16
- // https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
17
- this.state = { name: this.props.name };
18
- }
21
+ HelloWorld.propTypes = {
22
+ name: PropTypes.string.isRequired, // this is passed from the Rails view
23
+ };
19
24
 
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
- }
25
+ export default HelloWorld;
@@ -6,7 +6,8 @@
6
6
  ReactOnRails.configure do |config|
7
7
  # This configures the script to run to build the production assets by webpack. Set this to nil
8
8
  # if you don't want react_on_rails building this file for you.
9
- config.build_production_command = "RAILS_ENV=production NODE_ENV=production bin/webpack"
9
+ # If nil, then the standard rails/webpacker assets:precompile will run
10
+ # config.build_production_command = nil
10
11
 
11
12
  ################################################################################
12
13
  ################################################################################
@@ -22,6 +23,8 @@ ReactOnRails.configure do |config|
22
23
  # with rspec then this controls what yarn command is run
23
24
  # to automatically refresh your webpack assets on every test run.
24
25
  #
26
+ # Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`
27
+ # and set the config/webpacker.yml option for test to true.
25
28
  config.build_test_command = "RAILS_ENV=test bin/webpack"
26
29
 
27
30
  ################################################################################
@@ -4,19 +4,15 @@ import React from 'react';
4
4
  const HelloWorld = ({ name, updateName }) => (
5
5
  <div>
6
6
  <h3>
7
- Hello, {name}!
7
+ Hello,
8
+ {name}!
8
9
  </h3>
9
10
  <hr />
10
- <form >
11
+ <form>
11
12
  <label htmlFor="name">
12
13
  Say hello to:
14
+ <input id="name" type="text" value={name} onChange={(e) => updateName(e.target.value)} />
13
15
  </label>
14
- <input
15
- id="name"
16
- type="text"
17
- value={name}
18
- onChange={(e) => updateName(e.target.value)}
19
- />
20
16
  </form>
21
17
  </div>
22
18
  );
@@ -1,8 +1,6 @@
1
1
  import { createStore } from 'redux';
2
2
  import helloWorldReducer from '../reducers/helloWorldReducer';
3
3
 
4
- const configureStore = (railsProps) => (
5
- createStore(helloWorldReducer, railsProps)
6
- );
4
+ const configureStore = (railsProps) => createStore(helloWorldReducer, railsProps);
7
5
 
8
6
  export default configureStore;
@@ -22,4 +22,6 @@ require "react_on_rails/webpacker_utils"
22
22
  require "react_on_rails/test_helper/webpack_assets_compiler"
23
23
  require "react_on_rails/test_helper/webpack_assets_status_checker"
24
24
  require "react_on_rails/test_helper/ensure_assets_compiled"
25
- require "react_on_rails/locales_to_js"
25
+ require "react_on_rails/locales/base"
26
+ require "react_on_rails/locales/to_js"
27
+ require "react_on_rails/locales/to_json"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Metrics/ClassLength
4
+
3
5
  module ReactOnRails
4
6
  def self.configure
5
7
  yield(configuration)
@@ -31,10 +33,11 @@ module ReactOnRails
31
33
  webpack_generated_files: %w[manifest.json],
32
34
  rendering_extension: nil,
33
35
  server_render_method: nil,
34
- symlink_non_digested_assets_regex: nil,
35
36
  build_test_command: "",
36
37
  build_production_command: "",
37
- random_dom_id: DEFAULT_RANDOM_DOM_ID
38
+ random_dom_id: DEFAULT_RANDOM_DOM_ID,
39
+ same_bundle_for_client_and_server: false,
40
+ i18n_output_format: nil
38
41
  )
39
42
  end
40
43
 
@@ -46,8 +49,9 @@ module ReactOnRails
46
49
  :generated_assets_dirs, :generated_assets_dir,
47
50
  :webpack_generated_files, :rendering_extension, :build_test_command,
48
51
  :build_production_command,
49
- :i18n_dir, :i18n_yml_dir,
50
- :server_render_method, :symlink_non_digested_assets_regex, :random_dom_id
52
+ :i18n_dir, :i18n_yml_dir, :i18n_output_format,
53
+ :server_render_method, :random_dom_id,
54
+ :same_bundle_for_client_and_server
51
55
 
52
56
  def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
53
57
  replay_console: nil,
@@ -58,16 +62,17 @@ module ReactOnRails
58
62
  generated_assets_dir: nil, webpack_generated_files: nil,
59
63
  rendering_extension: nil, build_test_command: nil,
60
64
  build_production_command: nil,
61
- i18n_dir: nil, i18n_yml_dir: nil, random_dom_id: nil,
62
- server_render_method: nil, symlink_non_digested_assets_regex: nil)
65
+ same_bundle_for_client_and_server: nil,
66
+ i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
67
+ random_dom_id: nil, server_render_method: nil)
63
68
  self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
64
- self.server_bundle_js_file = server_bundle_js_file
65
69
  self.generated_assets_dirs = generated_assets_dirs
66
70
  self.generated_assets_dir = generated_assets_dir
67
71
  self.build_test_command = build_test_command
68
72
  self.build_production_command = build_production_command
69
73
  self.i18n_dir = i18n_dir
70
74
  self.i18n_yml_dir = i18n_yml_dir
75
+ self.i18n_output_format = i18n_output_format
71
76
 
72
77
  self.random_dom_id = random_dom_id
73
78
  self.prerender = prerender
@@ -83,6 +88,8 @@ module ReactOnRails
83
88
  self.skip_display_none = skip_display_none
84
89
 
85
90
  # Server rendering:
91
+ self.server_bundle_js_file = server_bundle_js_file
92
+ self.same_bundle_for_client_and_server = same_bundle_for_client_and_server
86
93
  self.server_renderer_pool_size = self.development_mode ? 1 : server_renderer_pool_size
87
94
  self.server_renderer_timeout = server_renderer_timeout # seconds
88
95
 
@@ -90,7 +97,6 @@ module ReactOnRails
90
97
  self.rendering_extension = rendering_extension
91
98
 
92
99
  self.server_render_method = server_render_method
93
- self.symlink_non_digested_assets_regex = symlink_non_digested_assets_regex
94
100
  end
95
101
 
96
102
  # on ReactOnRails
@@ -99,15 +105,50 @@ module ReactOnRails
99
105
  configure_generated_assets_dirs_deprecation
100
106
  configure_skip_display_none_deprecation
101
107
  ensure_generated_assets_dir_present
102
- ensure_server_bundle_js_file_has_no_path
103
108
  check_i18n_directory_exists
104
109
  check_i18n_yml_directory_exists
105
110
  check_server_render_method_is_only_execjs
106
111
  error_if_using_webpacker_and_generated_assets_dir_not_match_public_output_path
112
+ check_deprecated_settings
107
113
  end
108
114
 
109
115
  private
110
116
 
117
+ def check_deprecated_settings
118
+ if build_production_command.present? &&
119
+ ReactOnRails::WebpackerUtils.webpacker_webpack_production_config_exists?
120
+ msg = <<~MSG
121
+ Setting ReactOnRails configuration for `build_production_command` is
122
+ not necessary if you have config/webpack/production.js. When that file
123
+ exists, React on Rails DOES NOT modify the standard assets:precompile.
124
+ If you want React on Rails to modify to the standard assets:precompile
125
+ to use your config/initializers/react_on_rails.rb config.build_production_command
126
+ then delete the config/webpack/production.js.
127
+ MSG
128
+ Rails.logger.warn(msg)
129
+ end
130
+ #
131
+ # msg = <<~MSG
132
+ # ReactOnRails configuration for `build_production_command` is removed.
133
+ # Move this command into `bin/webpack` converting the script to a shell script.
134
+ # MSG
135
+ # raise ReactOnRails::Error, msg
136
+ # Commenting out until v13 when
137
+ # https://github.com/rails/webpacker/issues/2640 gets resolved
138
+ # if node_modules_location.present?
139
+ # Rails.logger.warn("ReactOnRails configuration for `node_modules_location` is deprecated. "\
140
+ # "Instead, prepend a `cd client` (or whichever location) before your test command.")
141
+ # end
142
+ #
143
+ # return unless build_production_command.present?
144
+ #
145
+ # msg = <<~MSG
146
+ # ReactOnRails configuration for `build_production_command` is removed.
147
+ # Move this command into `bin/webpack` converting the script to a shell script.
148
+ # MSG
149
+ # raise ReactOnRails::Error, msg
150
+ end
151
+
111
152
  def error_if_using_webpacker_and_generated_assets_dir_not_match_public_output_path
112
153
  return unless ReactOnRails::WebpackerUtils.using_webpacker?
113
154
 
@@ -119,12 +160,12 @@ module ReactOnRails
119
160
  Rails.logger.warn("You specified generated_assets_dir in `config/initializers/react_on_rails.rb` "\
120
161
  "with Webpacker. Remove this line from your configuration file.")
121
162
  else
122
- msg = <<-MSG.strip_heredoc
123
- Error configuring /config/initializers/react_on_rails.rb: You are using webpacker
124
- and your specified value for generated_assets_dir = #{generated_assets_dir}
125
- that does not match the value for public_output_path specified in
126
- webpacker.yml = #{webpacker_public_output_path}. You should remove the configuration
127
- value for "generated_assets_dir" from your config/initializers/react_on_rails.rb file.
163
+ msg = <<~MSG
164
+ Error configuring /config/initializers/react_on_rails.rb: You are using webpacker
165
+ and your specified value for generated_assets_dir = #{generated_assets_dir}
166
+ that does not match the value for public_output_path specified in
167
+ webpacker.yml = #{webpacker_public_output_path}. You should remove the configuration
168
+ value for "generated_assets_dir" from your config/initializers/react_on_rails.rb file.
128
169
  MSG
129
170
  raise ReactOnRails::Error, msg
130
171
  end
@@ -198,24 +239,12 @@ module ReactOnRails
198
239
  def ensure_webpack_generated_files_exists
199
240
  return unless webpack_generated_files.empty?
200
241
 
201
- files = ["hello-world-bundle.js"]
242
+ files = ["manifest.json"]
202
243
  files << server_bundle_js_file if server_bundle_js_file.present?
203
244
 
204
245
  self.webpack_generated_files = files
205
246
  end
206
247
 
207
- def ensure_server_bundle_js_file_has_no_path
208
- return unless server_bundle_js_file.include?(File::SEPARATOR)
209
-
210
- assets_dir = ReactOnRails::Utils.generated_assets_full_path
211
- self.server_bundle_js_file = File.basename(server_bundle_js_file)
212
-
213
- Rails.logger.warn do
214
- "[DEPRECATION] ReactOnRails: remove path from server_bundle_js_file in configuration. "\
215
- "All generated files must go in #{assets_dir}. Using file basename #{server_bundle_js_file}"
216
- end
217
- end
218
-
219
248
  def configure_skip_display_none_deprecation
220
249
  return if skip_display_none.nil?
221
250
 
@@ -223,3 +252,4 @@ module ReactOnRails
223
252
  end
224
253
  end
225
254
  end
255
+ # rubocop:enable Metrics/ClassLength
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ReactOnRails
2
4
  class Error < StandardError
3
5
  end
@@ -15,68 +15,20 @@ module ReactOnRails
15
15
  module Helper
16
16
  include ReactOnRails::Utils::Required
17
17
 
18
- COMPONENT_HTML_KEY = "componentHtml".freeze
18
+ COMPONENT_HTML_KEY = "componentHtml"
19
19
 
20
- # The env_javascript_include_tag and env_stylesheet_link_tag support the usage of a webpack
21
- # dev server for providing the JS and CSS assets during development mode. See
22
- # https://github.com/shakacode/react-webpack-rails-tutorial/ for a working example.
20
+ # react_component_name: can be a React function or class component or a "render function".
21
+ # "render functions" differ from a React function in that they take two parameters, the
22
+ # props and the railsContext, like this:
23
23
  #
24
- # The key options are `static` and `hot` which specify what you want for static vs. hot. Both of
25
- # these params are optional, and support either a single value, or an array.
24
+ # let MyReactComponentApp = (props, railsContext) => <MyReactComponent {...props}/>;
26
25
  #
27
- # static vs. hot is picked based on whether
28
- # ENV["REACT_ON_RAILS_ENV"] == "HOT"
26
+ # Alternately, you can define the render function with an additional property
27
+ # `.renderFunction = true`:
29
28
  #
30
- # <%= env_stylesheet_link_tag(static: 'application_static',
31
- # hot: 'application_non_webpack',
32
- # media: 'all',
33
- # 'data-turbolinks-track' => "reload") %>
29
+ # let MyReactComponentApp = (props) => <MyReactComponent {...props}/>;
30
+ # MyReactComponent.renderFunction = true;
34
31
  #
35
- # <!-- These do not use turbolinks, so no data-turbolinks-track -->
36
- # <!-- This is to load the hot assets. -->
37
- # <%= env_javascript_include_tag(hot: ['http://localhost:3500/vendor-bundle.js',
38
- # 'http://localhost:3500/app-bundle.js']) %>
39
- #
40
- # <!-- These do use turbolinks -->
41
- # <%= env_javascript_include_tag(static: 'application_static',
42
- # hot: 'application_non_webpack',
43
- # 'data-turbolinks-track' => "reload") %>
44
- #
45
- # NOTE: for Turbolinks 2.x, use 'data-turbolinks-track' => true
46
- # See application.html.erb for usage example
47
- # https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/app%2Fviews%2Flayouts%2Fapplication.html.erb
48
- def env_javascript_include_tag(args = {})
49
- send_tag_method(:javascript_include_tag, args)
50
- end
51
-
52
- # Helper to set CSS assets depending on if we want static or "hot", which means from the
53
- # Webpack dev server.
54
- #
55
- # In this example, application_non_webpack is simply a CSS asset pipeline file which includes
56
- # styles not placed in the webpack build.
57
- #
58
- # We don't need styles from the webpack build, as those will come via the JavaScript include
59
- # tags.
60
- #
61
- # The key options are `static` and `hot` which specify what you want for static vs. hot. Both of
62
- # these params are optional, and support either a single value, or an array.
63
- #
64
- # <%= env_stylesheet_link_tag(static: 'application_static',
65
- # hot: 'application_non_webpack',
66
- # media: 'all',
67
- # 'data-turbolinks-track' => true) %>
68
- #
69
- def env_stylesheet_link_tag(args = {})
70
- send_tag_method(:stylesheet_link_tag, args)
71
- end
72
-
73
- # react_component_name: can be a React component, created using a ES6 class, or
74
- # React.createClass, or a
75
- # `generator function` that returns a React component
76
- # using ES6
77
- # let MyReactComponentApp = (props, railsContext) => <MyReactComponent {...props}/>;
78
- # or using ES5
79
- # var MyReactComponentApp = function(props, railsContext) { return <YourReactComponent {...props}/>; }
80
32
  # Exposing the react_component_name is necessary to both a plain ReactComponent as well as
81
33
  # a generator:
82
34
  # See README.md for how to "register" your react components.
@@ -98,7 +50,8 @@ module ReactOnRails
98
50
  # raise_on_prerender_error: <true/false> Default to false. True will raise exception on server
99
51
  # if the JS code throws
100
52
  # Any other options are passed to the content tag, including the id.
101
- # random_dom_id can be set to override the global default.
53
+ # random_dom_id can be set to override the default from the config/initializers. That's only
54
+ # used if you have multiple instance of the same component on the Rails view.
102
55
  def react_component(component_name, options = {})
103
56
  internal_result = internal_react_component(component_name, options)
104
57
  server_rendered_html = internal_result[:result]["html"]
@@ -112,20 +65,24 @@ module ReactOnRails
112
65
  render_options: internal_result[:render_options]
113
66
  )
114
67
  elsif server_rendered_html.is_a?(Hash)
115
- msg = <<-MSG.strip_heredoc
116
- Use react_component_hash (not react_component) to return a Hash to your ruby view code. See
117
- https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
118
- for an example of the necessary javascript configuration."
68
+ msg = <<~MSG
69
+ Use react_component_hash (not react_component) to return a Hash to your ruby view code. See
70
+ https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
71
+ for an example of the necessary javascript configuration.
119
72
  MSG
120
73
  raise ReactOnRails::Error, msg
121
-
122
74
  else
123
- msg = <<-MSG.strip_heredoc
124
- ReactOnRails: server_rendered_html is expected to be a String for #{component_name}. If you're
125
- trying to use a generator function to return a Hash to your ruby view code, then use
126
- react_component_hash instead of react_component and see
127
- https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
128
- for an example of the JavaScript code."
75
+ class_name = server_rendered_html.class.name
76
+ msg = <<~MSG
77
+ ReactOnRails: server_rendered_html is expected to be a String or Hash for #{component_name}.
78
+ Type is #{class_name}
79
+ Value:
80
+ #{server_rendered_html}
81
+
82
+ If you're trying to use a render function to return a Hash to your ruby view code, then use
83
+ react_component_hash instead of react_component and see
84
+ https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
85
+ for an example of the JavaScript code.
129
86
  MSG
130
87
  raise ReactOnRails::Error, msg
131
88
  end
@@ -136,7 +93,7 @@ module ReactOnRails
136
93
  # It is exactly like react_component except for the following:
137
94
  # 1. prerender: true is automatically added, as this method doesn't make sense for client only
138
95
  # rendering.
139
- # 2. Your JavaScript generator function for server rendering must return an Object rather than a React component.
96
+ # 2. Your JavaScript render function for server rendering must return an Object rather than a React component.
140
97
  # 3. Your view code must expect an object and not a string.
141
98
  #
142
99
  # Here is an example of the view code:
@@ -166,10 +123,12 @@ module ReactOnRails
166
123
  render_options: internal_result[:render_options]
167
124
  )
168
125
  else
169
- msg = <<-MSG.strip_heredoc
170
- Generator function used by react_component_hash for #{component_name} is expected to return
126
+ msg = <<~MSG
127
+ render function used by react_component_hash for #{component_name} is expected to return
171
128
  an Object. See https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
172
- for an example of the JavaScript code."
129
+ for an example of the JavaScript code.
130
+ Note, your render function must either take 2 params or have the property
131
+ `.renderFunction = true` added to it to distinguish it from a React Function Component.
173
132
  MSG
174
133
  raise ReactOnRails::Error, msg
175
134
  end
@@ -178,6 +137,9 @@ module ReactOnRails
178
137
  # Separate initialization of store from react_component allows multiple react_component calls to
179
138
  # use the same Redux store.
180
139
  #
140
+ # NOTE: This technique not recommended as it prevents dynamic code splitting for performance.
141
+ # Instead, you should use the standard react_component view helper.
142
+ #
181
143
  # store_name: name of the store, corresponding to your call to ReactOnRails.registerStores in your
182
144
  # JavaScript code.
183
145
  # props: Ruby Hash or JSON string which contains the properties to pass to the redux store.
@@ -278,11 +240,12 @@ module ReactOnRails
278
240
  end
279
241
 
280
242
  # This is the definitive list of the default values used for the rails_context, which is the
281
- # second parameter passed to both component and store generator functions.
243
+ # second parameter passed to both component and store render functions.
282
244
  # This method can be called from views and from the controller, as `helpers.rails_context`
283
245
  #
284
246
  # rubocop:disable Metrics/AbcSize
285
247
  def rails_context(server_side: true)
248
+ # ALERT: Keep in sync with node_package/src/types/index.ts for the properties of RailsContext
286
249
  @rails_context ||= begin
287
250
  result = {
288
251
  railsEnv: Rails.env,
@@ -395,13 +358,11 @@ module ReactOnRails
395
358
 
396
359
  def compose_react_component_html_with_spec_and_console(component_specification_tag, rendered_output, console_script)
397
360
  # IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
398
- # rubocop:disable Layout/IndentHeredoc
399
- <<-HTML.html_safe
400
- #{rendered_output}
401
- #{component_specification_tag}
402
- #{console_script}
361
+ <<~HTML.html_safe
362
+ #{rendered_output}
363
+ #{component_specification_tag}
364
+ #{console_script}
403
365
  HTML
404
- # rubocop:enable Layout/IndentHeredoc
405
366
  end
406
367
 
407
368
  # prepend the rails_context if not yet applied
@@ -551,17 +512,6 @@ module ReactOnRails
551
512
  val.nil? ? ReactOnRails.configuration.replay_console : val
552
513
  end
553
514
 
554
- def use_hot_reloading?
555
- ENV["REACT_ON_RAILS_ENV"] == "HOT"
556
- end
557
-
558
- def send_tag_method(tag_method_name, args)
559
- asset_type = use_hot_reloading? ? :hot : :static
560
- assets = Array(args[asset_type])
561
- options = args.delete_if { |key, _value| %i[hot static].include?(key) }
562
- send(tag_method_name, *assets, options) unless assets.empty?
563
- end
564
-
565
515
  def in_mailer?
566
516
  return false unless defined?(controller)
567
517
  return false unless defined?(ActionMailer::Base)