react_on_rails 11.3.1 → 12.0.0.pre.beta.0

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 (87) 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 -20
  11. data/CHANGELOG.md +44 -19
  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 +102 -69
  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 +60 -57
  27. data/docs/basics/deployment.md +1 -2
  28. data/docs/basics/i18n.md +44 -22
  29. data/docs/basics/installation-into-an-existing-rails-app.md +2 -2
  30. data/docs/basics/react-server-rendering.md +1 -1
  31. data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
  32. data/docs/basics/upgrading-react-on-rails.md +50 -2
  33. data/docs/basics/webpack-configuration.md +15 -1
  34. data/docs/contributor-info/errors-with-hooks.md +45 -0
  35. data/docs/contributor-info/pull-requests.md +44 -0
  36. data/docs/misc/doctrine.md +1 -1
  37. data/docs/{misc-pending → outdated}/code-splitting.md +12 -8
  38. data/docs/{additional-reading → outdated}/heroku-deployment.md +0 -6
  39. data/docs/{basics → outdated}/how-react-on-rails-works.md +2 -2
  40. data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
  41. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
  42. data/docs/{misc-pending → outdated}/rails-assets.md +4 -7
  43. data/docs/{misc → outdated}/rails3.md +0 -0
  44. data/docs/tutorial.md +54 -34
  45. data/jest.config.js +4 -0
  46. data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
  47. data/lib/generators/react_on_rails/generator_helper.rb +4 -6
  48. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +9 -8
  49. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +1 -8
  50. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
  51. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  52. data/lib/react_on_rails.rb +3 -1
  53. data/lib/react_on_rails/configuration.rb +13 -22
  54. data/lib/react_on_rails/error.rb +2 -0
  55. data/lib/react_on_rails/helper.rb +41 -91
  56. data/lib/react_on_rails/json_parse_error.rb +2 -0
  57. data/lib/react_on_rails/locales/base.rb +142 -0
  58. data/lib/react_on_rails/locales/to_js.rb +37 -0
  59. data/lib/react_on_rails/locales/to_json.rb +27 -0
  60. data/lib/react_on_rails/prerender_error.rb +11 -15
  61. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +41 -46
  62. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
  63. data/lib/react_on_rails/utils.rb +14 -19
  64. data/lib/react_on_rails/version.rb +1 -1
  65. data/lib/react_on_rails/version_checker.rb +1 -0
  66. data/lib/react_on_rails/webpacker_utils.rb +13 -2
  67. data/lib/tasks/assets.rake +5 -45
  68. data/lib/tasks/locale.rake +8 -2
  69. data/package-scripts.yml +11 -8
  70. data/package.json +29 -28
  71. data/rakelib/dummy_apps.rake +1 -9
  72. data/rakelib/example_type.rb +3 -1
  73. data/rakelib/examples.rake +3 -0
  74. data/rakelib/lint.rake +2 -7
  75. data/rakelib/node_package.rake +2 -2
  76. data/rakelib/run_rspec.rake +5 -18
  77. data/react_on_rails.gemspec +3 -5
  78. data/tsconfig.json +14 -0
  79. data/webpackConfigLoader.js +3 -2
  80. data/yarn.lock +4170 -2197
  81. metadata +30 -55
  82. data/Gemfile.rails32 +0 -73
  83. data/docs/additional-reading/babel.md +0 -5
  84. data/docs/additional-reading/hot-reloading-rails-development-asset-pipeline.md +0 -47
  85. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  86. data/lib/react_on_rails/assets_precompile.rb +0 -153
  87. data/lib/react_on_rails/locales_to_js.rb +0 -138
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module ReactOnRails
6
+ module Locales
7
+ class ToJs < Base
8
+ def initialize
9
+ super
10
+ end
11
+
12
+ private
13
+
14
+ def file_format
15
+ "js"
16
+ end
17
+
18
+ def template_translations
19
+ <<-JS.strip_heredoc
20
+ export const translations = #{@translations};
21
+ JS
22
+ end
23
+
24
+ def template_default
25
+ <<-JS.strip_heredoc
26
+ import { defineMessages } from 'react-intl';
27
+
28
+ const defaultLocale = \'#{default_locale}\';
29
+
30
+ const defaultMessages = defineMessages(#{@defaults});
31
+
32
+ export { defaultMessages, defaultLocale };
33
+ JS
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module ReactOnRails
6
+ module Locales
7
+ class ToJson < Base
8
+ def initialize
9
+ super
10
+ end
11
+
12
+ private
13
+
14
+ def file_format
15
+ "json"
16
+ end
17
+
18
+ def template_translations
19
+ @translations
20
+ end
21
+
22
+ def template_default
23
+ @defaults
24
+ end
25
+ end
26
+ end
27
+ end
@@ -48,33 +48,29 @@ module ReactOnRails
48
48
  def calc_message(component_name, console_messages, err, js_code, props)
49
49
  message = "ERROR in SERVER PRERENDERING\n".dup
50
50
  if err
51
- # rubocop:disable Layout/IndentHeredoc
52
- message << <<-MSG
53
- Encountered error: \"#{err}\"
51
+ message << <<~MSG
52
+ Encountered error: \"#{err}\"
54
53
  MSG
55
- # rubocop:enable Layout/IndentHeredoc
54
+
56
55
  backtrace = err.backtrace.join("\n")
57
56
  else
58
57
  backtrace = nil
59
58
  end
60
- # rubocop:disable Layout/IndentHeredoc
61
- message << <<-MSG
62
- when prerendering #{component_name} with props: #{Utils.smart_trim(props, MAX_ERROR_SNIPPET_TO_LOG)}
59
+ message << <<~MSG
60
+ when prerendering #{component_name} with props: #{Utils.smart_trim(props, MAX_ERROR_SNIPPET_TO_LOG)}
63
61
 
64
- code:
62
+ code:
65
63
 
66
- #{Utils.smart_trim(js_code, MAX_ERROR_SNIPPET_TO_LOG)}
64
+ #{Utils.smart_trim(js_code, MAX_ERROR_SNIPPET_TO_LOG)}
67
65
 
68
66
  MSG
69
- # rubocop:enable Layout/IndentHeredoc
70
67
 
71
68
  if console_messages
72
- # rubocop:disable Layout/IndentHeredoc
73
- message << <<-MSG
74
- console messages:
75
- #{console_messages}
69
+ message << <<~MSG
70
+ console messages:
71
+ #{console_messages}
76
72
  MSG
77
- # rubocop:enable Layout/IndentHeredoc
73
+
78
74
  end
79
75
  [backtrace, message]
80
76
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open-uri"
4
+ require "execjs"
4
5
 
5
6
  module ReactOnRails
6
7
  module ServerRenderingPool
@@ -121,14 +122,12 @@ module ReactOnRails
121
122
  return if ReactOnRails.configuration.server_bundle_js_file.blank?
122
123
 
123
124
  bundle_js_code = read_bundle_js_code
124
-
125
- # rubocop:disable Layout/IndentHeredoc
126
- base_js_code = <<-JS
127
- #{console_polyfill}
128
- #{execjs_timer_polyfills}
129
- #{bundle_js_code};
125
+ base_js_code = <<~JS
126
+ #{console_polyfill}
127
+ #{execjs_timer_polyfills}
128
+ #{bundle_js_code};
130
129
  JS
131
- # rubocop:enable Layout/IndentHeredoc
130
+
132
131
  file_name = "tmp/base_js_code.js"
133
132
  begin
134
133
  if ReactOnRails.configuration.trace
@@ -151,33 +150,31 @@ module ReactOnRails
151
150
  end
152
151
 
153
152
  def execjs_timer_polyfills
154
- # rubocop:disable Layout/IndentHeredoc
155
- <<-JS
156
- function getStackTrace () {
157
- var stack;
158
- try {
159
- throw new Error('');
160
- }
161
- catch (error) {
162
- stack = error.stack || '';
163
- }
164
- stack = stack.split('\\n').map(function (line) { return line.trim(); });
165
- return stack.splice(stack[0] == 'Error' ? 2 : 1);
166
- }
167
-
168
- function setInterval() {
169
- #{undefined_for_exec_js_logging('setInterval')}
170
- }
171
-
172
- function setTimeout() {
173
- #{undefined_for_exec_js_logging('setTimeout')}
174
- }
175
-
176
- function clearTimeout() {
177
- #{undefined_for_exec_js_logging('clearTimeout')}
178
- }
153
+ <<~JS
154
+ function getStackTrace () {
155
+ var stack;
156
+ try {
157
+ throw new Error('');
158
+ }
159
+ catch (error) {
160
+ stack = error.stack || '';
161
+ }
162
+ stack = stack.split('\\n').map(function (line) { return line.trim(); });
163
+ return stack.splice(stack[0] == 'Error' ? 2 : 1);
164
+ }
165
+
166
+ function setInterval() {
167
+ #{undefined_for_exec_js_logging('setInterval')}
168
+ }
169
+
170
+ function setTimeout() {
171
+ #{undefined_for_exec_js_logging('setTimeout')}
172
+ }
173
+
174
+ function clearTimeout() {
175
+ #{undefined_for_exec_js_logging('clearTimeout')}
176
+ }
179
177
  JS
180
- # rubocop:enable Layout/IndentHeredoc
181
178
  end
182
179
 
183
180
  def undefined_for_exec_js_logging(function_name)
@@ -191,20 +188,18 @@ function clearTimeout() {
191
188
 
192
189
  # Reimplement console methods for replaying on the client
193
190
  def console_polyfill
194
- # rubocop:disable Layout/IndentHeredoc
195
- <<-JS
196
- var console = { history: [] };
197
- ['error', 'log', 'info', 'warn'].forEach(function (level) {
198
- console[level] = function () {
199
- var argArray = Array.prototype.slice.call(arguments);
200
- if (argArray.length > 0) {
201
- argArray[0] = '[SERVER] ' + argArray[0];
202
- }
203
- console.history.push({level: level, arguments: argArray});
204
- };
205
- });
191
+ <<~JS
192
+ var console = { history: [] };
193
+ ['error', 'log', 'info', 'warn'].forEach(function (level) {
194
+ console[level] = function () {
195
+ var argArray = Array.prototype.slice.call(arguments);
196
+ if (argArray.length > 0) {
197
+ argArray[0] = '[SERVER] ' + argArray[0];
198
+ }
199
+ console.history.push({level: level, arguments: argArray});
200
+ };
201
+ });
206
202
  JS
207
- # rubocop:enable Layout/IndentHeredoc
208
203
  end
209
204
 
210
205
  private
@@ -5,6 +5,7 @@ module ReactOnRails
5
5
  class EnsureAssetsCompiled
6
6
  class << self
7
7
  attr_accessor :has_been_run
8
+
8
9
  @has_been_run = false
9
10
  end
10
11
 
@@ -29,7 +30,7 @@ module ReactOnRails
29
30
  # Be sure we don't do this again.
30
31
  self.class.has_been_run = true
31
32
 
32
- ReactOnRails::LocalesToJs.new
33
+ ReactOnRails::Locales::ToJs.new
33
34
 
34
35
  stale_gen_files = webpack_assets_status_checker.stale_generated_webpack_files
35
36
 
@@ -43,17 +44,15 @@ module ReactOnRails
43
44
  end
44
45
 
45
46
  def puts_start_compile_check_message(stale_files)
46
- # rubocop:disable Layout/IndentHeredoc
47
- puts <<-MSG
47
+ puts <<~MSG
48
48
 
49
- Detected the following stale generated files:
50
- #{stale_files.join("\n ")}
49
+ Detected the following stale generated files:
50
+ #{stale_files.join("\n ")}
51
51
 
52
- React on Rails will ensure your JavaScript generated files are up to date, using your
53
- `#{ReactOnRails::Utils.prepend_cd_node_modules_directory(ReactOnRails.configuration.build_test_command)}` command.
52
+ React on Rails will ensure your JavaScript generated files are up to date, using your
53
+ `#{ReactOnRails::Utils.prepend_cd_node_modules_directory(ReactOnRails.configuration.build_test_command)}` command.
54
54
 
55
55
  MSG
56
- # rubocop:enable Layout/IndentHeredoc
57
56
  end
58
57
  end
59
58
  end
@@ -8,7 +8,7 @@ require "active_support/core_ext/string"
8
8
 
9
9
  module ReactOnRails
10
10
  module Utils
11
- TRUNCATION_FILLER = "\n... TRUNCATED ...\n".freeze
11
+ TRUNCATION_FILLER = "\n... TRUNCATED ...\n"
12
12
 
13
13
  # https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901
14
14
  # return object if truthy, else return nil
@@ -24,13 +24,12 @@ module ReactOnRails
24
24
  # Pass in the msg and color as a symbol.
25
25
  def self.wrap_message(msg, color = :red)
26
26
  wrapper_line = ("=" * 80).to_s
27
- # rubocop:disable Layout/IndentHeredoc
28
- fenced_msg = <<-MSG
29
- #{wrapper_line}
30
- #{msg.strip}
31
- #{wrapper_line}
27
+ fenced_msg = <<~MSG
28
+ #{wrapper_line}
29
+ #{msg.strip}
30
+ #{wrapper_line}
32
31
  MSG
33
- # rubocop:enable Layout/IndentHeredoc
32
+
34
33
  Rainbow(fenced_msg).color(color)
35
34
  end
36
35
 
@@ -48,14 +47,13 @@ module ReactOnRails
48
47
  unless status.success?
49
48
  stdout_msg = stdout.present? ? "\nstdout:\n#{stdout.strip}\n" : ""
50
49
  stderr_msg = stderr.present? ? "\nstderr:\n#{stderr.strip}\n" : ""
51
- # rubocop:disable Layout/IndentHeredoc
52
- msg = <<-MSG
53
- React on Rails FATAL ERROR!
54
- #{failure_message}
55
- cmd: #{cmd}
56
- exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
50
+ msg = <<~MSG
51
+ React on Rails FATAL ERROR!
52
+ #{failure_message}
53
+ cmd: #{cmd}
54
+ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
57
55
  MSG
58
- # rubocop:enable Layout/IndentHeredoc
56
+
59
57
  puts wrap_message(msg)
60
58
 
61
59
  # Rspec catches exit without! in the exit callbacks
@@ -72,11 +70,8 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
72
70
  # Either:
73
71
  # 1. Using same bundle for both server and client, so server bundle will be hashed in manifest
74
72
  # 2. Using a different bundle (different Webpack config), so file is not hashed, and
75
- # bundle_js_path will throw.
76
- # 3. Not using webpacker, and bundle_js_path always returns
77
-
78
- # Note, server bundle should not be in the manifest
79
- # If using webpacker gem per https://github.com/rails/webpacker/issues/571
73
+ # bundle_js_path will throw so the default path is used without a hash.
74
+ # 3. Not using webpacker, and this method returns the bundle_js_file_path
80
75
  return @server_bundle_path if @server_bundle_path && !Rails.env.development?
81
76
 
82
77
  bundle_name = ReactOnRails.configuration.server_bundle_js_file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "11.3.1".freeze
4
+ VERSION = "12.0.0-beta.0"
5
5
  end
@@ -5,6 +5,7 @@ module ReactOnRails
5
5
  # against each otherat runtime.
6
6
  class VersionChecker
7
7
  attr_reader :node_package_version
8
+
8
9
  MAJOR_MINOR_PATCH_VERSION_REGEX = /(\d+)\.(\d+)\.(\d+)/.freeze
9
10
 
10
11
  def self.build
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ReactOnRails
2
4
  module WebpackerUtils
3
5
  def self.using_webpacker?
@@ -10,7 +12,9 @@ module ReactOnRails
10
12
  Webpacker.dev_server.running?
11
13
  end
12
14
 
13
- # This returns either a URL for the webpack-dev-server or a file path
15
+ # This returns either a URL for the webpack-dev-server, non-server bundle or
16
+ # the hashed server bundle if using the same bundle for the client.
17
+ # Otherwise returns a file path.
14
18
  def self.bundle_js_uri_from_webpacker(bundle_name)
15
19
  # Note Webpacker 3.4.3 manifest lookup is inside of the public_output_path
16
20
  # [2] (pry) ReactOnRails::WebpackerUtils: 0> Webpacker.manifest.lookup("app-bundle.js")
@@ -18,7 +22,14 @@ module ReactOnRails
18
22
  # Next line will throw if the file or manifest does not exist
19
23
  hashed_bundle_name = Webpacker.manifest.lookup!(bundle_name)
20
24
 
21
- if Webpacker.dev_server.running?
25
+ # support for hashing the server-bundle and having that built
26
+ # by a webpack watch process and not served by the webpack-dev-server, then we
27
+ # need an extra config value "same_bundle_for_client_and_server" where a value of false
28
+ # would mean that the bundle is created by a separate webpack watch process.
29
+ is_server_bundle = bundle_name == ReactOnRails.configuration.server_bundle_js_file
30
+
31
+ if Webpacker.dev_server.running? && (!is_server_bundle ||
32
+ ReactOnRails.configuration.same_bundle_for_client_and_server)
22
33
  "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
23
34
  else
24
35
  File.expand_path(File.join("public", hashed_bundle_name)).to_s
@@ -1,48 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "react_on_rails/assets_precompile"
4
3
  require "active_support"
5
4
 
6
- if defined?(Sprockets)
7
- namespace :react_on_rails do
8
- namespace :assets do
9
- desc "Creates non-digested symlinks for the assets in the public asset dir"
10
- task symlink_non_digested_assets: :"assets:environment" do
11
- ReactOnRails::AssetsPrecompile.new.symlink_non_digested_assets
12
- end
13
-
14
- desc "Cleans all broken symlinks for the assets in the public asset dir"
15
- task delete_broken_symlinks: :"assets:environment" do
16
- ReactOnRails::AssetsPrecompile.new.delete_broken_symlinks
17
- end
18
-
19
- # In this task, set prerequisites for the assets:precompile task
20
- desc <<-DESC.strip_heredoc
21
- Create webpack assets before calling assets:environment
22
- The webpack task must run before assets:environment task.
23
- Otherwise Sprockets cannot find the files that webpack produces.
24
- This is the secret sauce for how a Heroku deployment knows to create the webpack generated JavaScript files.
25
- DESC
26
- task compile_environment: :webpack do
27
- Rake::Task["assets:environment"].invoke
28
- end
29
-
30
- desc "Delete assets created with webpack, in the generated assetst directory (/app/assets/webpack)"
31
- task clobber: :environment do
32
- ReactOnRails::AssetsPrecompile.new.clobber
33
- end
34
- end
5
+ if Rake::Task.task_defined?("assets:precompile")
6
+ Rake::Task["assets:precompile"].enhance do
7
+ Rake::Task["react_on_rails:assets:webpack"].invoke
35
8
  end
36
-
37
- # These tasks run as pre-requisites of assets:precompile.
38
- # Note, it's not possible to refer to ReactOnRails configuration values at this point.
39
- Rake::Task["assets:precompile"]
40
- .clear_prerequisites
41
- .enhance([:environment, "react_on_rails:assets:compile_environment"])
42
- .enhance do
43
- Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke
44
- Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke
45
- end
9
+ else
10
+ Rake::Task.define_task("assets:precompile" => ["react_on_rails:assets:webpack"])
46
11
  end
47
12
 
48
13
  # Sprockets independent tasks
@@ -55,11 +20,6 @@ namespace :react_on_rails do
55
20
  sh "#{ReactOnRails::Utils.prepend_cd_node_modules_directory('<ReactOnRails.configuration.build_production_command>')}"
56
21
  DESC
57
22
  task webpack: :locale do
58
- if Rake::Task.task_defined?("webpacker:compile")
59
- # TODO: Eventually, this will need reconsideration if we use any of the Webpacker compilation
60
- Rake::Task["webpacker:compile"].clear
61
- end
62
-
63
23
  if ReactOnRails.configuration.build_production_command.present?
64
24
  sh ReactOnRails::Utils.prepend_cd_node_modules_directory(
65
25
  ReactOnRails.configuration.build_production_command
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "react_on_rails/locales_to_js"
3
+ require "react_on_rails/locales/base"
4
+ require "react_on_rails/locales/to_js"
5
+ require "react_on_rails/locales/to_json"
4
6
  require "active_support"
5
7
 
6
8
  namespace :react_on_rails do
@@ -10,6 +12,10 @@ namespace :react_on_rails do
10
12
  the "ReactOnRails.configuration.i18n_dir".
11
13
  DESC
12
14
  task locale: :environment do
13
- ReactOnRails::LocalesToJs.new
15
+ if ReactOnRails.configuration.i18n_output_format&.downcase == "js"
16
+ ReactOnRails::Locales::ToJs.new
17
+ else
18
+ ReactOnRails::Locales::ToJson.new
19
+ end
14
20
  end
15
21
  end