react_on_rails 11.1.4 → 12.0.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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +320 -0
  3. data/.eslintignore +2 -1
  4. data/.eslintrc +30 -2
  5. data/.github/FUNDING.yml +1 -0
  6. data/.gitignore +3 -1
  7. data/.prettierignore +10 -0
  8. data/.prettierrc +23 -0
  9. data/.release-it.json +3 -0
  10. data/.rubocop.yml +37 -11
  11. data/.travis.yml +10 -20
  12. data/CHANGELOG.md +126 -4
  13. data/CONTRIBUTING.md +61 -80
  14. data/Gemfile +3 -5
  15. data/KUDOS.md +4 -1
  16. data/REACT-ON-RAILS-PRO-LICENSE +95 -0
  17. data/README.md +148 -89
  18. data/Rakefile +0 -7
  19. data/SUMMARY.md +12 -12
  20. data/book.json +5 -5
  21. data/docs/additional-reading/asset-pipeline.md +8 -16
  22. data/docs/additional-reading/images.md +1 -1
  23. data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
  24. data/docs/additional-reading/react-helmet.md +30 -10
  25. data/docs/additional-reading/react-router.md +52 -75
  26. data/docs/additional-reading/server-rendering-tips.md +12 -7
  27. data/docs/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
  28. data/docs/api/javascript-api.md +3 -3
  29. data/docs/api/redux-store-api.md +4 -2
  30. data/docs/api/view-helpers-api.md +17 -14
  31. data/docs/basics/client-vs-server-rendering.md +8 -2
  32. data/docs/basics/configuration.md +87 -73
  33. data/docs/basics/deployment.md +2 -4
  34. data/docs/basics/generator-details.md +1 -1
  35. data/docs/basics/heroku-deployment.md +24 -0
  36. data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
  37. data/docs/basics/i18n.md +45 -23
  38. data/docs/basics/installation-into-an-existing-rails-app.md +4 -9
  39. data/docs/basics/minitest-configuration.md +31 -0
  40. data/docs/basics/react-server-rendering.md +3 -1
  41. data/docs/basics/recommended-project-structure.md +21 -15
  42. data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
  43. data/docs/basics/rspec-configuration.md +29 -18
  44. data/docs/basics/upgrading-react-on-rails.md +74 -3
  45. data/docs/basics/webpack-configuration.md +29 -8
  46. data/docs/contributor-info/errors-with-hooks.md +45 -0
  47. data/docs/contributor-info/pull-requests.md +44 -0
  48. data/docs/misc/doctrine.md +1 -1
  49. data/docs/{misc-pending → outdated}/code-splitting.md +13 -9
  50. data/docs/{basics → outdated}/how-react-on-rails-works.md +8 -4
  51. data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
  52. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
  53. data/docs/{misc-pending → outdated}/rails-assets.md +2 -12
  54. data/docs/testimonials/hvmn.md +25 -0
  55. data/docs/testimonials/resortpass.md +13 -0
  56. data/docs/testimonials/testimonials.md +28 -0
  57. data/docs/tutorial.md +182 -44
  58. data/jest.config.js +4 -0
  59. data/lib/generators/react_on_rails/base_generator.rb +2 -2
  60. data/lib/generators/react_on_rails/dev_tests_generator.rb +2 -1
  61. data/lib/generators/react_on_rails/generator_helper.rb +4 -6
  62. data/lib/generators/react_on_rails/install_generator.rb +2 -0
  63. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -1
  64. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +26 -0
  65. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +20 -40
  66. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +4 -1
  67. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
  68. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  69. data/lib/react_on_rails/configuration.rb +60 -29
  70. data/lib/react_on_rails/error.rb +2 -0
  71. data/lib/react_on_rails/git_utils.rb +2 -0
  72. data/lib/react_on_rails/helper.rb +110 -159
  73. data/lib/react_on_rails/json_output.rb +1 -1
  74. data/lib/react_on_rails/json_parse_error.rb +2 -0
  75. data/lib/react_on_rails/locales/base.rb +150 -0
  76. data/lib/react_on_rails/locales/to_js.rb +37 -0
  77. data/lib/react_on_rails/locales/to_json.rb +27 -0
  78. data/lib/react_on_rails/prerender_error.rb +11 -15
  79. data/lib/react_on_rails/react_component/render_options.rb +4 -0
  80. data/lib/react_on_rails/server_rendering_js_code.rb +42 -0
  81. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +85 -60
  82. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
  83. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
  84. data/lib/react_on_rails/utils.rb +19 -20
  85. data/lib/react_on_rails/version.rb +1 -1
  86. data/lib/react_on_rails/version_checker.rb +5 -1
  87. data/lib/react_on_rails/webpacker_utils.rb +27 -2
  88. data/lib/react_on_rails.rb +4 -1
  89. data/lib/tasks/assets.rake +33 -46
  90. data/lib/tasks/locale.rake +4 -2
  91. data/package-scripts.yml +49 -0
  92. data/package.json +41 -31
  93. data/rakelib/dummy_apps.rake +1 -9
  94. data/rakelib/example_type.rb +3 -1
  95. data/rakelib/examples.rake +3 -0
  96. data/rakelib/lint.rake +2 -7
  97. data/rakelib/node_package.rake +2 -2
  98. data/rakelib/release.rake +3 -8
  99. data/rakelib/run_rspec.rake +5 -18
  100. data/react_on_rails.gemspec +4 -5
  101. data/tsconfig.json +14 -0
  102. data/webpackConfigLoader.js +5 -4
  103. data/yarn.lock +7177 -2311
  104. metadata +54 -55
  105. data/Gemfile.rails32 +0 -74
  106. data/docs/additional-reading/babel.md +0 -5
  107. data/docs/additional-reading/heroku-deployment.md +0 -92
  108. data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
  109. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  110. data/docs/testimonials.md +0 -11
  111. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
  112. data/lib/react_on_rails/assets_precompile.rb +0 -150
  113. data/lib/react_on_rails/locales_to_js.rb +0 -134
  114. /data/docs/{misc → outdated}/rails3.md +0 -0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module ReactOnRails
6
+ module Locales
7
+ def self.compile
8
+ if ReactOnRails.configuration.i18n_output_format&.downcase == "js"
9
+ ReactOnRails::Locales::ToJs.new
10
+ else
11
+ ReactOnRails::Locales::ToJson.new
12
+ end
13
+ end
14
+
15
+ class Base
16
+ def initialize
17
+ return if i18n_dir.nil?
18
+ return unless obsolete?
19
+
20
+ @translations, @defaults = generate_translations
21
+ convert
22
+ end
23
+
24
+ private
25
+
26
+ def file_format; end
27
+
28
+ def obsolete?
29
+ return true if exist_files.empty?
30
+
31
+ files_are_outdated
32
+ end
33
+
34
+ def exist_files
35
+ @exist_files ||= files.select(&File.method(:exist?))
36
+ end
37
+
38
+ def files_are_outdated
39
+ latest_yml = locale_files.map(&File.method(:mtime)).max
40
+ earliest = exist_files.map(&File.method(:mtime)).min
41
+ latest_yml > earliest
42
+ end
43
+
44
+ def file_names
45
+ %w[translations default]
46
+ end
47
+
48
+ def files
49
+ @files ||= file_names.map { |n| file(n) }
50
+ end
51
+
52
+ def file(name)
53
+ "#{i18n_dir}/#{name}.#{file_format}"
54
+ end
55
+
56
+ def locale_files
57
+ @locale_files ||= begin
58
+ if i18n_yml_dir.present?
59
+ Dir["#{i18n_yml_dir}/**/*.yml"]
60
+ else
61
+ ReactOnRails::Utils.truthy_presence(
62
+ Rails.application && Rails.application.config.i18n.load_path
63
+ ).presence
64
+ end
65
+ end
66
+ end
67
+
68
+ def i18n_dir
69
+ @i18n_dir ||= ReactOnRails.configuration.i18n_dir
70
+ end
71
+
72
+ def i18n_yml_dir
73
+ @i18n_yml_dir ||= ReactOnRails.configuration.i18n_yml_dir
74
+ end
75
+
76
+ def default_locale
77
+ @default_locale ||= I18n.default_locale.to_s || "en"
78
+ end
79
+
80
+ def convert
81
+ file_names.each do |name|
82
+ template = send("template_#{name}")
83
+ path = file(name)
84
+ generate_file(template, path)
85
+ end
86
+ end
87
+
88
+ def generate_file(template, path)
89
+ result = ERB.new(template).result()
90
+ File.open(path, "w") do |f|
91
+ f.write(result)
92
+ end
93
+ end
94
+
95
+ def generate_translations
96
+ translations = {}
97
+ defaults = {}
98
+ locale_files.each do |f|
99
+ translation = YAML.safe_load(File.open(f))
100
+ key = translation.keys[0]
101
+ val = flatten(translation[key])
102
+ translations = translations.deep_merge(key => val)
103
+ defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
104
+ end
105
+ [translations.to_json, defaults.to_json]
106
+ end
107
+
108
+ def format(input)
109
+ input.to_s.tr(".", "_").camelize(:lower).to_sym
110
+ end
111
+
112
+ def flatten_defaults(val)
113
+ flatten(val).each_with_object({}) do |(k, v), h|
114
+ key = format(k)
115
+ h[key] = { id: k, defaultMessage: v }
116
+ end
117
+ end
118
+
119
+ def flatten(translations)
120
+ translations.each_with_object({}) do |(k, v), h|
121
+ if v.is_a? Hash
122
+ flatten(v).map { |hk, hv| h["#{k}.#{hk}".to_sym] = hv }
123
+ elsif v.is_a?(String)
124
+ h[k] = v.gsub("%{", "{")
125
+ elsif !v.is_a?(Array)
126
+ h[k] = v
127
+ end
128
+ end
129
+ end
130
+
131
+ def template_translations
132
+ <<-JS.strip_heredoc
133
+ export const translations = #{@translations};
134
+ JS
135
+ end
136
+
137
+ def template_default
138
+ <<-JS.strip_heredoc
139
+ import { defineMessages } from 'react-intl';
140
+
141
+ const defaultLocale = \'#{default_locale}\';
142
+
143
+ const defaultMessages = defineMessages(#{@defaults});
144
+
145
+ export { defaultMessages, defaultLocale };
146
+ JS
147
+ end
148
+ end
149
+ end
150
+ end
@@ -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
@@ -72,6 +72,10 @@ module ReactOnRails
72
72
  "{ react_component_name = #{react_component_name}, options = #{options}, request_digest = #{request_digest}"
73
73
  end
74
74
 
75
+ def internal_option(key)
76
+ options[key]
77
+ end
78
+
75
79
  private
76
80
 
77
81
  attr_reader :options
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactOnRails
4
+ module ServerRenderingJsCode
5
+ class << self
6
+ def js_code_renderer
7
+ @js_code_renderer ||= if ReactOnRails::Utils.react_on_rails_pro?
8
+ ReactOnRailsPro::ServerRenderingJsCode
9
+ else
10
+ self
11
+ end
12
+ end
13
+
14
+ def server_rendering_component_js_code(
15
+ props_string: nil,
16
+ rails_context: nil,
17
+ redux_stores: nil,
18
+ react_component_name: nil,
19
+ render_options: nil
20
+ )
21
+ js_code_renderer.render(props_string, rails_context, redux_stores, react_component_name, render_options)
22
+ end
23
+
24
+ def render(props_string, rails_context, redux_stores, react_component_name, render_options)
25
+ <<-JS
26
+ (function() {
27
+ var railsContext = #{rails_context};
28
+ #{redux_stores}
29
+ var props = #{props_string};
30
+ return ReactOnRails.serverRenderReactComponent({
31
+ name: '#{react_component_name}',
32
+ domNodeId: '#{render_options.dom_id}',
33
+ props: props,
34
+ trace: #{render_options.trace},
35
+ railsContext: railsContext
36
+ });
37
+ })()
38
+ JS
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,10 +1,13 @@
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
8
+ # rubocop:disable Metrics/ClassLength
7
9
  class RubyEmbeddedJavaScript
10
+ # rubocop:enable Metrics/ClassLength
8
11
  class << self
9
12
  def reset_pool
10
13
  options = {
@@ -17,12 +20,17 @@ module ReactOnRails
17
20
  def reset_pool_if_server_bundle_was_modified
18
21
  return unless ReactOnRails.configuration.development_mode
19
22
 
20
- file_mtime = File.mtime(ReactOnRails::Utils.server_bundle_js_file_path)
21
- @server_bundle_timestamp ||= file_mtime
22
- return if @server_bundle_timestamp == file_mtime
23
+ if ReactOnRails::Utils.server_bundle_path_is_http?
24
+ return if @server_bundle_url == ReactOnRails::Utils.server_bundle_js_file_path
23
25
 
24
- @server_bundle_timestamp = file_mtime
26
+ @server_bundle_url = ReactOnRails::Utils.server_bundle_js_file_path
27
+ else
28
+ file_mtime = File.mtime(ReactOnRails::Utils.server_bundle_js_file_path)
29
+ @server_bundle_timestamp ||= file_mtime
30
+ return if @server_bundle_timestamp == file_mtime
25
31
 
32
+ @server_bundle_timestamp = file_mtime
33
+ end
26
34
  ReactOnRails::ServerRenderingPool.reset_pool
27
35
  end
28
36
 
@@ -72,6 +80,7 @@ module ReactOnRails
72
80
 
73
81
  def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
74
82
  return unless ReactOnRails.configuration.trace || force
83
+
75
84
  # Set to anything to print generated code.
76
85
  File.write(file_name, js_code)
77
86
  msg = <<-MSG.strip_heredoc
@@ -95,30 +104,37 @@ module ReactOnRails
95
104
  end
96
105
  end
97
106
 
98
- def create_js_context
99
- return if ReactOnRails.configuration.server_bundle_js_file.blank?
100
-
107
+ def read_bundle_js_code
101
108
  server_js_file = ReactOnRails::Utils.server_bundle_js_file_path
102
-
103
- begin
104
- bundle_js_code = File.read(server_js_file)
105
- rescue StandardError => e
106
- msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
109
+ if ReactOnRails::Utils.server_bundle_path_is_http?
110
+ file_url_to_string(server_js_file)
111
+ else
112
+ File.read(server_js_file)
113
+ end
114
+ rescue StandardError => e
115
+ msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
107
116
  "read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
108
117
  "avoid this warning.\nError is: #{e}"
109
- raise ReactOnRails::Error, msg
110
- end
111
- # rubocop:disable Layout/IndentHeredoc
112
- base_js_code = <<-JS
113
- #{console_polyfill}
114
- #{execjs_timer_polyfills}
115
- #{bundle_js_code};
118
+ raise ReactOnRails::Error, msg
119
+ end
120
+
121
+ def create_js_context
122
+ return if ReactOnRails.configuration.server_bundle_js_file.blank?
123
+
124
+ bundle_js_code = read_bundle_js_code
125
+ base_js_code = <<~JS
126
+ #{console_polyfill}
127
+ #{execjs_timer_polyfills}
128
+ #{bundle_js_code};
116
129
  JS
117
- # rubocop:enable Layout/IndentHeredoc
130
+
118
131
  file_name = "tmp/base_js_code.js"
119
132
  begin
120
133
  if ReactOnRails.configuration.trace
121
- Rails.logger.info { "[react_on_rails] Created JavaScript context with file #{server_js_file}" }
134
+ Rails.logger.info do
135
+ "[react_on_rails] Created JavaScript context with file "\
136
+ "#{ReactOnRails::Utils.server_bundle_js_file_path}"
137
+ end
122
138
  end
123
139
  ExecJS.compile(base_js_code)
124
140
  rescue StandardError => e
@@ -134,33 +150,31 @@ module ReactOnRails
134
150
  end
135
151
 
136
152
  def execjs_timer_polyfills
137
- # rubocop:disable Layout/IndentHeredoc
138
- <<-JS
139
- function getStackTrace () {
140
- var stack;
141
- try {
142
- throw new Error('');
143
- }
144
- catch (error) {
145
- stack = error.stack || '';
146
- }
147
- stack = stack.split('\\n').map(function (line) { return line.trim(); });
148
- return stack.splice(stack[0] == 'Error' ? 2 : 1);
149
- }
150
-
151
- function setInterval() {
152
- #{undefined_for_exec_js_logging('setInterval')}
153
- }
154
-
155
- function setTimeout() {
156
- #{undefined_for_exec_js_logging('setTimeout')}
157
- }
158
-
159
- function clearTimeout() {
160
- #{undefined_for_exec_js_logging('clearTimeout')}
161
- }
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
+ }
162
177
  JS
163
- # rubocop:enable Layout/IndentHeredoc
164
178
  end
165
179
 
166
180
  def undefined_for_exec_js_logging(function_name)
@@ -174,20 +188,31 @@ function clearTimeout() {
174
188
 
175
189
  # Reimplement console methods for replaying on the client
176
190
  def console_polyfill
177
- # rubocop:disable Layout/IndentHeredoc
178
- <<-JS
179
- var console = { history: [] };
180
- ['error', 'log', 'info', 'warn'].forEach(function (level) {
181
- console[level] = function () {
182
- var argArray = Array.prototype.slice.call(arguments);
183
- if (argArray.length > 0) {
184
- argArray[0] = '[SERVER] ' + argArray[0];
185
- }
186
- console.history.push({level: level, arguments: argArray});
187
- };
188
- });
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
+ });
189
202
  JS
190
- # rubocop:enable Layout/IndentHeredoc
203
+ end
204
+
205
+ private
206
+
207
+ def file_url_to_string(url)
208
+ response = Net::HTTP.get_response(URI.parse(url))
209
+ content_type_header = response["content-type"]
210
+ match = content_type_header.match(/\A.*; charset=(?<encoding>.*)\z/)
211
+ encoding_type = match[:encoding]
212
+ response.body.force_encoding(encoding_type)
213
+ rescue StandardError => e
214
+ msg = "file_url_to_string #{url} failed\nError is: #{e}"
215
+ raise ReactOnRails::Error, msg
191
216
  end
192
217
  end
193
218
  end
@@ -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.compile
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
@@ -6,6 +6,23 @@ module ReactOnRails
6
6
  module TestHelper
7
7
  class WebpackAssetsCompiler
8
8
  def compile_assets
9
+ if ReactOnRails.configuration.build_test_command.blank?
10
+ msg = <<~MSG
11
+ You are using the React on Rails test helper.
12
+ Either you used:
13
+ ReactOnRails::TestHelper.configure_rspec_to_compile_assets or
14
+ ReactOnRails::TestHelper.ensure_assets_compiled
15
+ but you did not specify the config.build_test_command
16
+
17
+ React on Rails is aborting your test run
18
+
19
+ If you wish to use the config/webpacker.yml compile option for tests
20
+ them remove your call to the ReactOnRails test helper.
21
+ MSG
22
+ puts Rainbow(msg).red
23
+ exit!(1)
24
+ end
25
+
9
26
  puts "\nBuilding Webpack assets..."
10
27
 
11
28
  cmd = ReactOnRails::Utils.prepend_cd_node_modules_directory(
@@ -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
@@ -64,15 +62,16 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
64
62
  [stdout, stderr, status]
65
63
  end
66
64
 
65
+ def self.server_bundle_path_is_http?
66
+ server_bundle_js_file_path =~ %r{https?://}
67
+ end
68
+
67
69
  def self.server_bundle_js_file_path
68
70
  # Either:
69
71
  # 1. Using same bundle for both server and client, so server bundle will be hashed in manifest
70
72
  # 2. Using a different bundle (different Webpack config), so file is not hashed, and
71
- # bundle_js_path will throw.
72
- # 3. Not using webpacker, and bundle_js_path always returns
73
-
74
- # Note, server bundle should not be in the manifest
75
- # 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
76
75
  return @server_bundle_path if @server_bundle_path && !Rails.env.development?
77
76
 
78
77
  bundle_name = ReactOnRails.configuration.server_bundle_js_file
@@ -92,7 +91,7 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
92
91
 
93
92
  def self.bundle_js_file_path(bundle_name)
94
93
  if ReactOnRails::WebpackerUtils.using_webpacker? && bundle_name != "manifest.json"
95
- ReactOnRails::WebpackerUtils.bundle_js_file_path_from_webpacker(bundle_name)
94
+ ReactOnRails::WebpackerUtils.bundle_js_uri_from_webpacker(bundle_name)
96
95
  else
97
96
  # Default to the non-hashed name in the specified output directory, which, for legacy
98
97
  # React on Rails, this is the output directory picked up by the asset pipeline.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "11.1.4".freeze
4
+ VERSION = "12.0.0"
5
5
  end