react_on_rails 12.0.1 → 13.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +27 -13
- data/.eslintrc +2 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/lint-js-and-ruby.yml +53 -0
- data/.github/workflows/main.yml +178 -0
- data/.github/workflows/package-js-tests.yml +35 -0
- data/.github/workflows/rspec-package-specs.yml +45 -0
- data/.gitignore +0 -3
- data/.prettierignore +2 -0
- data/.prettierrc +0 -3
- data/.rubocop.yml +48 -39
- data/.travis.yml +3 -1
- data/CHANGELOG.md +112 -25
- data/CONTRIBUTING.md +4 -3
- data/Gemfile +1 -33
- data/Gemfile.development_dependencies +52 -0
- data/NEWS.md +14 -4
- data/REACT-ON-RAILS-PRO-LICENSE +1 -1
- data/README.md +42 -324
- data/Rakefile +1 -1
- data/SUMMARY.md +22 -13
- data/docs/{basics → additional-details}/generator-details.md +1 -6
- data/docs/{outdated → additional-details}/manual-installation-overview.md +6 -6
- data/docs/additional-details/recommended-project-structure.md +69 -0
- data/docs/additional-details/upgrade-webpacker-v3-to-v4.md +10 -0
- data/docs/api/javascript-api.md +2 -2
- data/docs/api/redux-store-api.md +3 -3
- data/docs/api/view-helpers-api.md +7 -8
- data/docs/contributor-info/linters.md +5 -6
- data/docs/contributor-info/pull-requests.md +2 -4
- data/docs/contributor-info/releasing.md +1 -1
- data/docs/{basics → deployment}/heroku-deployment.md +16 -5
- data/docs/{basics → guides}/client-vs-server-rendering.md +4 -2
- data/docs/{basics → guides}/configuration.md +65 -31
- data/docs/guides/deployment.md +4 -0
- data/docs/guides/getting-started.md +183 -0
- data/docs/guides/hmr-and-hot-reloading-with-the-webpack-dev-server.md +104 -0
- data/docs/{outdated → guides}/how-react-on-rails-works.md +10 -10
- data/docs/guides/how-to-conditionally-server-render-based-on-device-type.md +39 -0
- data/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md +98 -0
- data/docs/{basics → guides}/installation-into-an-existing-rails-app.md +14 -7
- data/docs/guides/rails-webpacker-react-integration-options.md +182 -0
- data/docs/guides/react-on-rails-overview.md +30 -0
- data/docs/{basics → guides}/react-server-rendering.md +8 -5
- data/docs/{basics → guides}/rspec-configuration.md +11 -11
- data/docs/{tutorial.md → guides/tutorial.md} +46 -50
- data/docs/{basics → guides}/upgrading-react-on-rails.md +56 -18
- data/docs/guides/webpack-configuration.md +42 -0
- data/docs/home.md +23 -0
- data/docs/{outdated → javascript}/code-splitting.md +5 -5
- data/docs/{additional-reading → javascript}/converting-from-custom-webpack-config-to-rails-webpacker-config.md +4 -4
- data/docs/{additional-reading → javascript}/images.md +5 -6
- data/docs/{articles.md → misc/articles.md} +1 -1
- data/docs/misc/doctrine.md +5 -6
- data/docs/outdated/deferred-rendering.md +39 -0
- data/docs/outdated/rails-assets-relative-paths.md +3 -3
- data/docs/outdated/rails-assets.md +8 -8
- data/docs/outdated/rails3.md +2 -2
- data/docs/{additional-reading → rails}/convert-rails-5-api-only-app.md +1 -1
- data/docs/{additional-reading → rails}/rails-engine-integration.md +3 -12
- data/docs/{additional-reading → rails}/turbolinks.md +13 -1
- data/docs/react-on-rails-pro/react-on-rails-pro.md +43 -0
- data/docs/testimonials/testimonials.md +6 -6
- data/lib/generators/react_on_rails/base_generator.rb +64 -12
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
- data/lib/generators/react_on_rails/generator_helper.rb +4 -0
- data/lib/generators/react_on_rails/templates/.eslintrc +3 -1
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +4 -8
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static +9 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +2 -1
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js +5 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js +8 -0
- data/lib/generators/react_on_rails/templates/base/base/app/views/layouts/hello_world.html.erb +1 -0
- data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +32 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +3 -3
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt +17 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +15 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +25 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +9 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +117 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +6 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/webpack.config.js.tt +15 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js.tt +36 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpacker.yml +62 -0
- data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +8 -2
- data/lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb +1 -1
- data/lib/generators/react_on_rails/templates/dev_tests/spec/{features → system}/hello_world_spec.rb +2 -2
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +2 -1
- data/lib/react_on_rails/configuration.rb +42 -41
- data/lib/react_on_rails/git_utils.rb +3 -3
- data/lib/react_on_rails/helper.rb +54 -28
- data/lib/react_on_rails/json_parse_error.rb +1 -1
- data/lib/react_on_rails/locales/base.rb +11 -15
- data/lib/react_on_rails/locales/to_js.rb +0 -4
- data/lib/react_on_rails/locales/to_json.rb +0 -4
- data/lib/react_on_rails/prerender_error.rb +6 -3
- data/lib/react_on_rails/react_component/render_options.rb +30 -7
- data/lib/react_on_rails/server_rendering_js_code.rb +13 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +41 -13
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +1 -1
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +3 -3
- data/lib/react_on_rails/test_helper.rb +4 -2
- data/lib/react_on_rails/utils.rb +24 -4
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/webpacker_utils.rb +9 -10
- data/lib/tasks/assets.rake +19 -50
- data/lib/tasks/locale.rake +1 -2
- data/package.json +24 -29
- data/rakelib/docker.rake +0 -5
- data/rakelib/example_type.rb +10 -3
- data/rakelib/examples.rake +3 -5
- data/rakelib/lint.rake +3 -9
- data/rakelib/release.rake +35 -15
- data/rakelib/run_rspec.rake +10 -11
- data/rakelib/task_helpers.rb +16 -4
- data/react_on_rails.gemspec +5 -20
- data/yarn.lock +2616 -5190
- metadata +86 -256
- data/.release-it.json +0 -3
- data/docs/additional-reading/upgrade-webpacker-v3-to-v4.md +0 -10
- data/docs/additional-reading/webpack-dev-server.md +0 -15
- data/docs/basics/deployment.md +0 -4
- data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +0 -49
- data/docs/basics/recommended-project-structure.md +0 -77
- data/docs/basics/webpack-configuration.md +0 -50
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +0 -26
- data/ruby-lint.yml +0 -25
- /data/docs/{basics → additional-details}/migrating-from-react-rails.md +0 -0
- /data/docs/{additional-reading → additional-details}/updating-dependencies.md +0 -0
- /data/docs/{additional-reading → deployment}/elastic-beanstalk.md +0 -0
- /data/docs/{basics → guides}/i18n.md +0 -0
- /data/docs/{basics → guides}/minitest-configuration.md +0 -0
- /data/docs/{basics → guides}/render-functions-and-railscontext.md +0 -0
- /data/docs/{additional-reading → javascript}/angular-js-integration-migration.md +0 -0
- /data/docs/{additional-reading → javascript}/asset-pipeline.md +0 -0
- /data/docs/{additional-reading → javascript}/capistrano-deployment.md +0 -0
- /data/docs/{additional-reading → javascript}/credits.md +0 -0
- /data/docs/{additional-reading → javascript}/foreman-issues.md +0 -0
- /data/docs/{additional-reading → javascript}/node-dependencies-and-npm.md +0 -0
- /data/docs/{additional-reading → javascript}/react-and-redux.md +0 -0
- /data/docs/{additional-reading → javascript}/react-helmet.md +0 -0
- /data/docs/{additional-reading → javascript}/react-router.md +0 -0
- /data/docs/{additional-reading → javascript}/server-rendering-tips.md +0 -0
- /data/docs/{additional-reading → javascript}/troubleshooting-when-using-webpacker.md +0 -0
- /data/docs/{additional-reading → javascript}/webpack-v1-notes.md +0 -0
- /data/docs/{additional-reading → javascript}/webpack.md +0 -0
- /data/docs/{coding-style → misc}/style.md +0 -0
- /data/docs/{additional-reading → misc}/tips.md +0 -0
- /data/docs/{additional-reading → rails}/rails_view_rendering_from_inline_javascript.md +0 -0
|
@@ -10,10 +10,10 @@ module ReactOnRails
|
|
|
10
10
|
status = `git status --porcelain`
|
|
11
11
|
return false if $CHILD_STATUS.success? && status.empty?
|
|
12
12
|
|
|
13
|
-
error = if
|
|
14
|
-
"You do not have Git installed. Please install Git, and commit your changes before continuing"
|
|
15
|
-
else
|
|
13
|
+
error = if $CHILD_STATUS.success?
|
|
16
14
|
"You have uncommitted code. Please commit or stash your changes before continuing"
|
|
15
|
+
else
|
|
16
|
+
"You do not have Git installed. Please install Git, and commit your changes before continuing"
|
|
17
17
|
end
|
|
18
18
|
message_handler.add_error(error)
|
|
19
19
|
true
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# rubocop:disable Metrics/ModuleLength
|
|
4
|
+
# rubocop:disable Metrics/MethodLength
|
|
4
5
|
# NOTE:
|
|
5
6
|
# For any heredoc JS:
|
|
6
7
|
# 1. The white spacing in this file matters!
|
|
@@ -32,8 +33,8 @@ module ReactOnRails
|
|
|
32
33
|
# Exposing the react_component_name is necessary to both a plain ReactComponent as well as
|
|
33
34
|
# a generator:
|
|
34
35
|
# See README.md for how to "register" your react components.
|
|
35
|
-
# See spec/dummy/client/app/
|
|
36
|
-
# spec/dummy/client/app/
|
|
36
|
+
# See spec/dummy/client/app/packs/server-bundle.js and
|
|
37
|
+
# spec/dummy/client/app/packs/client-bundle.js for examples of this.
|
|
37
38
|
#
|
|
38
39
|
# options:
|
|
39
40
|
# props: Ruby Hash or JSON string which contains the properties to pass to the react object. Do
|
|
@@ -57,14 +58,15 @@ module ReactOnRails
|
|
|
57
58
|
server_rendered_html = internal_result[:result]["html"]
|
|
58
59
|
console_script = internal_result[:result]["consoleReplayScript"]
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
case server_rendered_html
|
|
62
|
+
when String
|
|
61
63
|
build_react_component_result_for_server_rendered_string(
|
|
62
64
|
server_rendered_html: server_rendered_html,
|
|
63
65
|
component_specification_tag: internal_result[:tag],
|
|
64
66
|
console_script: console_script,
|
|
65
67
|
render_options: internal_result[:render_options]
|
|
66
68
|
)
|
|
67
|
-
|
|
69
|
+
when Hash
|
|
68
70
|
msg = <<~MSG
|
|
69
71
|
Use react_component_hash (not react_component) to return a Hash to your ruby view code. See
|
|
70
72
|
https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
|
|
@@ -152,7 +154,7 @@ module ReactOnRails
|
|
|
152
154
|
@registered_stores_defer_render ||= []
|
|
153
155
|
@registered_stores_defer_render << redux_store_data
|
|
154
156
|
"YOU SHOULD NOT SEE THIS ON YOUR VIEW -- Uses as a code block, like <% redux_store %> "\
|
|
155
|
-
|
|
157
|
+
"and not <%= redux store %>"
|
|
156
158
|
else
|
|
157
159
|
@registered_stores ||= []
|
|
158
160
|
@registered_stores << redux_store_data
|
|
@@ -169,7 +171,7 @@ module ReactOnRails
|
|
|
169
171
|
def redux_store_hydration_data
|
|
170
172
|
return if @registered_stores_defer_render.blank?
|
|
171
173
|
|
|
172
|
-
@registered_stores_defer_render.reduce(""
|
|
174
|
+
@registered_stores_defer_render.reduce(+"") do |accum, redux_store_data|
|
|
173
175
|
accum << render_redux_store_data(redux_store_data)
|
|
174
176
|
end.html_safe
|
|
175
177
|
end
|
|
@@ -181,7 +183,7 @@ module ReactOnRails
|
|
|
181
183
|
# Helper method to take javascript expression and returns the output from evaluating it.
|
|
182
184
|
# If you have more than one line that needs to be executed, wrap it in an IIFE.
|
|
183
185
|
# JS exceptions are caught and console messages are handled properly.
|
|
184
|
-
# Options include:{ prerender:, trace:, raise_on_prerender_error: }
|
|
186
|
+
# Options include:{ prerender:, trace:, raise_on_prerender_error:, throw_js_errors: }
|
|
185
187
|
def server_render_js(js_expression, options = {})
|
|
186
188
|
render_options = ReactOnRails::ReactComponent::RenderOptions
|
|
187
189
|
.new(react_component_name: "generic-js", options: options)
|
|
@@ -191,6 +193,8 @@ module ReactOnRails
|
|
|
191
193
|
var htmlResult = '';
|
|
192
194
|
var consoleReplayScript = '';
|
|
193
195
|
var hasErrors = false;
|
|
196
|
+
var renderingError = null;
|
|
197
|
+
var renderingErrorObject = {};
|
|
194
198
|
|
|
195
199
|
try {
|
|
196
200
|
htmlResult =
|
|
@@ -198,9 +202,17 @@ module ReactOnRails
|
|
|
198
202
|
return #{js_expression};
|
|
199
203
|
})();
|
|
200
204
|
} catch(e) {
|
|
205
|
+
renderingError = e;
|
|
206
|
+
if (#{render_options.throw_js_errors}) {
|
|
207
|
+
throw e;
|
|
208
|
+
}
|
|
201
209
|
htmlResult = ReactOnRails.handleError({e: e, name: null,
|
|
202
210
|
jsCode: '#{escape_javascript(js_expression)}', serverSide: true});
|
|
203
211
|
hasErrors = true;
|
|
212
|
+
renderingErrorObject = {
|
|
213
|
+
message: renderingError.message,
|
|
214
|
+
stack: renderingError.stack,
|
|
215
|
+
}
|
|
204
216
|
}
|
|
205
217
|
|
|
206
218
|
consoleReplayScript = ReactOnRails.buildConsoleReplay();
|
|
@@ -208,7 +220,8 @@ module ReactOnRails
|
|
|
208
220
|
return JSON.stringify({
|
|
209
221
|
html: htmlResult,
|
|
210
222
|
consoleReplayScript: consoleReplayScript,
|
|
211
|
-
hasErrors: hasErrors
|
|
223
|
+
hasErrors: hasErrors,
|
|
224
|
+
renderingError: renderingErrorObject
|
|
212
225
|
});
|
|
213
226
|
|
|
214
227
|
})()
|
|
@@ -221,9 +234,9 @@ module ReactOnRails
|
|
|
221
234
|
console_log_script = result["consoleLogScript"]
|
|
222
235
|
raw("#{html}#{render_options.replay_console ? console_log_script : ''}")
|
|
223
236
|
rescue ExecJS::ProgramError => err
|
|
224
|
-
raise ReactOnRails::PrerenderError
|
|
225
|
-
|
|
226
|
-
|
|
237
|
+
raise ReactOnRails::PrerenderError.new(component_name: "N/A (server_render_js called)",
|
|
238
|
+
err: err,
|
|
239
|
+
js_code: js_code)
|
|
227
240
|
end
|
|
228
241
|
|
|
229
242
|
def json_safe_and_pretty(hash_or_string)
|
|
@@ -231,7 +244,7 @@ module ReactOnRails
|
|
|
231
244
|
|
|
232
245
|
unless hash_or_string.is_a?(String) || hash_or_string.is_a?(Hash)
|
|
233
246
|
raise ReactOnRails::Error, "#{__method__} only accepts String or Hash as argument "\
|
|
234
|
-
|
|
247
|
+
"(#{hash_or_string.class} given)."
|
|
235
248
|
end
|
|
236
249
|
|
|
237
250
|
json_value = hash_or_string.is_a?(String) ? hash_or_string : hash_or_string.to_json
|
|
@@ -243,7 +256,7 @@ module ReactOnRails
|
|
|
243
256
|
# second parameter passed to both component and store Render-Functions.
|
|
244
257
|
# This method can be called from views and from the controller, as `helpers.rails_context`
|
|
245
258
|
#
|
|
246
|
-
# rubocop:disable Metrics/AbcSize
|
|
259
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
247
260
|
def rails_context(server_side: true)
|
|
248
261
|
# ALERT: Keep in sync with node_package/src/types/index.ts for the properties of RailsContext
|
|
249
262
|
@rails_context ||= begin
|
|
@@ -254,8 +267,13 @@ module ReactOnRails
|
|
|
254
267
|
i18nLocale: I18n.locale,
|
|
255
268
|
i18nDefaultLocale: I18n.default_locale,
|
|
256
269
|
rorVersion: ReactOnRails::VERSION,
|
|
270
|
+
# TODO: v13 just use the version if existing
|
|
257
271
|
rorPro: ReactOnRails::Utils.react_on_rails_pro?
|
|
258
272
|
}
|
|
273
|
+
if ReactOnRails::Utils.react_on_rails_pro?
|
|
274
|
+
result[:rorProVersion] = ReactOnRails::Utils.react_on_rails_pro_version
|
|
275
|
+
end
|
|
276
|
+
|
|
259
277
|
if defined?(request) && request.present?
|
|
260
278
|
# Check for encoding of the request's original_url and try to force-encoding the
|
|
261
279
|
# URLs as UTF-8. This situation can occur in browsers that do not encode the
|
|
@@ -291,7 +309,8 @@ module ReactOnRails
|
|
|
291
309
|
|
|
292
310
|
@rails_context.merge(serverSide: server_side)
|
|
293
311
|
end
|
|
294
|
-
|
|
312
|
+
|
|
313
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
295
314
|
|
|
296
315
|
private
|
|
297
316
|
|
|
@@ -395,7 +414,7 @@ module ReactOnRails
|
|
|
395
414
|
# Setup the page_loaded_js, which is the same regardless of prerendering or not!
|
|
396
415
|
# The reason is that React is smart about not doing extra work if the server rendering did its job.
|
|
397
416
|
component_specification_tag = content_tag(:script,
|
|
398
|
-
json_safe_and_pretty(render_options.
|
|
417
|
+
json_safe_and_pretty(render_options.client_props).html_safe,
|
|
399
418
|
type: "application/json",
|
|
400
419
|
class: "js-react-on-rails-component",
|
|
401
420
|
"data-component-name" => render_options.react_component_name,
|
|
@@ -465,34 +484,34 @@ module ReactOnRails
|
|
|
465
484
|
result = ReactOnRails::ServerRenderingPool.server_render_js_with_console_logging(js_code, render_options)
|
|
466
485
|
rescue StandardError => err
|
|
467
486
|
# This error came from the renderer
|
|
468
|
-
raise ReactOnRails::PrerenderError
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
487
|
+
raise ReactOnRails::PrerenderError.new(component_name: react_component_name,
|
|
488
|
+
# Sanitize as this might be browser logged
|
|
489
|
+
props: sanitized_props_string(props),
|
|
490
|
+
err: err,
|
|
491
|
+
js_code: js_code)
|
|
473
492
|
end
|
|
474
493
|
|
|
475
494
|
if result["hasErrors"] && render_options.raise_on_prerender_error
|
|
476
495
|
# We caught this exception on our backtrace handler
|
|
477
|
-
raise ReactOnRails::PrerenderError
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
496
|
+
raise ReactOnRails::PrerenderError.new(component_name: react_component_name,
|
|
497
|
+
# Sanitize as this might be browser logged
|
|
498
|
+
props: sanitized_props_string(props),
|
|
499
|
+
err: nil,
|
|
500
|
+
js_code: js_code,
|
|
501
|
+
console_messages: result["consoleReplayScript"])
|
|
483
502
|
|
|
484
503
|
end
|
|
485
504
|
result
|
|
486
505
|
end
|
|
487
506
|
|
|
488
507
|
def initialize_redux_stores
|
|
489
|
-
result =
|
|
508
|
+
result = +<<-JS
|
|
490
509
|
ReactOnRails.clearHydratedStores();
|
|
491
510
|
JS
|
|
492
511
|
|
|
493
512
|
return result unless @registered_stores.present? || @registered_stores_defer_render.present?
|
|
494
513
|
|
|
495
|
-
declarations = "var reduxProps, store, storeGenerator;\n"
|
|
514
|
+
declarations = +"var reduxProps, store, storeGenerator;\n"
|
|
496
515
|
all_stores = (@registered_stores || []) + (@registered_stores_defer_render || [])
|
|
497
516
|
|
|
498
517
|
result << all_stores.each_with_object(declarations) do |redux_store_data, memo|
|
|
@@ -518,6 +537,13 @@ module ReactOnRails
|
|
|
518
537
|
|
|
519
538
|
controller.is_a?(ActionMailer::Base)
|
|
520
539
|
end
|
|
540
|
+
|
|
541
|
+
if defined?(ScoutApm)
|
|
542
|
+
include ScoutApm::Tracer
|
|
543
|
+
instrument_method :react_component, type: "ReactOnRails", name: "react_component"
|
|
544
|
+
instrument_method :react_component_hash, type: "ReactOnRails", name: "react_component_hash"
|
|
545
|
+
end
|
|
521
546
|
end
|
|
522
547
|
end
|
|
523
548
|
# rubocop:enable Metrics/ModuleLength
|
|
549
|
+
# rubocop:enable Metrics/MethodLength
|
|
@@ -32,12 +32,12 @@ module ReactOnRails
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def exist_files
|
|
35
|
-
@exist_files ||= files.select
|
|
35
|
+
@exist_files ||= files.select { |file| File.exist?(file) }
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def files_are_outdated
|
|
39
|
-
latest_yml = locale_files.map
|
|
40
|
-
earliest = exist_files.map
|
|
39
|
+
latest_yml = locale_files.map { |file| File.mtime(file) }.max
|
|
40
|
+
earliest = exist_files.map { |file| File.mtime(file) }.min
|
|
41
41
|
latest_yml > earliest
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -54,15 +54,13 @@ module ReactOnRails
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def locale_files
|
|
57
|
-
@locale_files ||=
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
65
|
-
end
|
|
57
|
+
@locale_files ||= if i18n_yml_dir.present?
|
|
58
|
+
Dir["#{i18n_yml_dir}/**/*.yml"]
|
|
59
|
+
else
|
|
60
|
+
ReactOnRails::Utils.truthy_presence(
|
|
61
|
+
Rails.application && Rails.application.config.i18n.load_path
|
|
62
|
+
).presence
|
|
63
|
+
end
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
def i18n_dir
|
|
@@ -87,9 +85,7 @@ module ReactOnRails
|
|
|
87
85
|
|
|
88
86
|
def generate_file(template, path)
|
|
89
87
|
result = ERB.new(template).result()
|
|
90
|
-
File.
|
|
91
|
-
f.write(result)
|
|
92
|
-
end
|
|
88
|
+
File.write(path, result)
|
|
93
89
|
end
|
|
94
90
|
|
|
95
91
|
def generate_translations
|
|
@@ -46,13 +46,16 @@ module ReactOnRails
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
48
|
def calc_message(component_name, console_messages, err, js_code, props)
|
|
49
|
-
message = "ERROR in SERVER PRERENDERING\n"
|
|
49
|
+
message = +"ERROR in SERVER PRERENDERING\n"
|
|
50
50
|
if err
|
|
51
51
|
message << <<~MSG
|
|
52
|
-
Encountered error:
|
|
52
|
+
Encountered error:
|
|
53
|
+
|
|
54
|
+
#{err}
|
|
55
|
+
|
|
53
56
|
MSG
|
|
54
57
|
|
|
55
|
-
backtrace = err.backtrace.join("\n")
|
|
58
|
+
backtrace = err.backtrace.first(15).join("\n")
|
|
56
59
|
else
|
|
57
60
|
backtrace = nil
|
|
58
61
|
end
|
|
@@ -11,6 +11,7 @@ module ReactOnRails
|
|
|
11
11
|
|
|
12
12
|
NO_PROPS = {}.freeze
|
|
13
13
|
|
|
14
|
+
# TODO: remove the required for named params
|
|
14
15
|
def initialize(react_component_name: required("react_component_name"), options: required("options"))
|
|
15
16
|
@react_component_name = react_component_name.camelize
|
|
16
17
|
@options = options
|
|
@@ -18,12 +19,30 @@ module ReactOnRails
|
|
|
18
19
|
|
|
19
20
|
attr_reader :react_component_name
|
|
20
21
|
|
|
22
|
+
def throw_js_errors
|
|
23
|
+
options.fetch(:throw_js_errors, false)
|
|
24
|
+
end
|
|
25
|
+
|
|
21
26
|
def props
|
|
22
27
|
options.fetch(:props) { NO_PROPS }
|
|
23
28
|
end
|
|
24
29
|
|
|
30
|
+
def client_props
|
|
31
|
+
props_extension = ReactOnRails.configuration.rendering_props_extension
|
|
32
|
+
if props_extension.present?
|
|
33
|
+
if props_extension.respond_to?(:adjust_props_for_client_side_hydration)
|
|
34
|
+
return props_extension.adjust_props_for_client_side_hydration(react_component_name,
|
|
35
|
+
props.clone)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
raise ReactOnRails::Error, "ReactOnRails: your rendering_props_extension module is missing the "\
|
|
39
|
+
"required adjust_props_for_client_side_hydration method & can not be used"
|
|
40
|
+
end
|
|
41
|
+
props
|
|
42
|
+
end
|
|
43
|
+
|
|
25
44
|
def random_dom_id
|
|
26
|
-
|
|
45
|
+
retrieve_configuration_value_for(:random_dom_id)
|
|
27
46
|
end
|
|
28
47
|
|
|
29
48
|
def dom_id
|
|
@@ -49,23 +68,23 @@ module ReactOnRails
|
|
|
49
68
|
end
|
|
50
69
|
|
|
51
70
|
def prerender
|
|
52
|
-
|
|
71
|
+
retrieve_configuration_value_for(:prerender)
|
|
53
72
|
end
|
|
54
73
|
|
|
55
74
|
def trace
|
|
56
|
-
|
|
75
|
+
retrieve_configuration_value_for(:trace)
|
|
57
76
|
end
|
|
58
77
|
|
|
59
78
|
def replay_console
|
|
60
|
-
|
|
79
|
+
retrieve_configuration_value_for(:replay_console)
|
|
61
80
|
end
|
|
62
81
|
|
|
63
82
|
def raise_on_prerender_error
|
|
64
|
-
|
|
83
|
+
retrieve_configuration_value_for(:raise_on_prerender_error)
|
|
65
84
|
end
|
|
66
85
|
|
|
67
86
|
def logging_on_server
|
|
68
|
-
|
|
87
|
+
retrieve_configuration_value_for(:logging_on_server)
|
|
69
88
|
end
|
|
70
89
|
|
|
71
90
|
def to_s
|
|
@@ -76,6 +95,10 @@ module ReactOnRails
|
|
|
76
95
|
options[key]
|
|
77
96
|
end
|
|
78
97
|
|
|
98
|
+
def set_option(key, value)
|
|
99
|
+
options[key] = value
|
|
100
|
+
end
|
|
101
|
+
|
|
79
102
|
private
|
|
80
103
|
|
|
81
104
|
attr_reader :options
|
|
@@ -88,7 +111,7 @@ module ReactOnRails
|
|
|
88
111
|
"#{base_dom_id}-#{SecureRandom.uuid}"
|
|
89
112
|
end
|
|
90
113
|
|
|
91
|
-
def
|
|
114
|
+
def retrieve_configuration_value_for(key)
|
|
92
115
|
options.fetch(key) do
|
|
93
116
|
ReactOnRails.configuration.public_send(key)
|
|
94
117
|
end
|
|
@@ -18,6 +18,19 @@ module ReactOnRails
|
|
|
18
18
|
react_component_name: nil,
|
|
19
19
|
render_options: nil
|
|
20
20
|
)
|
|
21
|
+
|
|
22
|
+
config_server_bundle_js = ReactOnRails.configuration.server_bundle_js_file
|
|
23
|
+
|
|
24
|
+
if render_options.prerender == true && config_server_bundle_js.blank?
|
|
25
|
+
msg = <<~MSG
|
|
26
|
+
The `prerender` option to allow Server Side Rendering is marked as true but the ReactOnRails configuration
|
|
27
|
+
for `server_bundle_js_file` is nil or not present in `config/initializers/react_on_rails.rb`.
|
|
28
|
+
Set `config.server_bundle_js_file` to your javascript bundle to allow server side rendering.
|
|
29
|
+
Read more at https://www.shakacode.com/react-on-rails/docs/guides/react-server-rendering/
|
|
30
|
+
MSG
|
|
31
|
+
raise ReactOnRails::Error, msg
|
|
32
|
+
end
|
|
33
|
+
|
|
21
34
|
js_code_renderer.render(props_string, rails_context, redux_stores, react_component_name, render_options)
|
|
22
35
|
end
|
|
23
36
|
|
|
@@ -47,6 +47,7 @@ module ReactOnRails
|
|
|
47
47
|
# Note, js_code does not have to be based on React.
|
|
48
48
|
# js_code MUST RETURN json stringify Object
|
|
49
49
|
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
|
50
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
50
51
|
def exec_server_render_js(js_code, render_options, js_evaluator = nil)
|
|
51
52
|
js_evaluator ||= self
|
|
52
53
|
if render_options.trace
|
|
@@ -55,28 +56,42 @@ module ReactOnRails
|
|
|
55
56
|
"tmp/server-generated-#{@file_index % 10}.js")
|
|
56
57
|
@file_index += 1
|
|
57
58
|
end
|
|
58
|
-
|
|
59
|
+
begin
|
|
60
|
+
json_string = js_evaluator.eval_js(js_code, render_options)
|
|
61
|
+
rescue StandardError => err
|
|
62
|
+
msg = <<~MSG
|
|
63
|
+
Error evaluating server bundle. Check your webpack configuration.
|
|
64
|
+
===============================================================
|
|
65
|
+
Caught error:
|
|
66
|
+
#{err.message}
|
|
67
|
+
===============================================================
|
|
68
|
+
MSG
|
|
69
|
+
|
|
70
|
+
if err.message.include?("ReferenceError: self is not defined")
|
|
71
|
+
msg << "\nError indicates that you may have code-splitting incorrectly enabled.\n"
|
|
72
|
+
end
|
|
73
|
+
raise ReactOnRails::Error, msg, err.backtrace
|
|
74
|
+
end
|
|
59
75
|
result = nil
|
|
60
76
|
begin
|
|
61
77
|
result = JSON.parse(json_string)
|
|
62
78
|
rescue JSON::ParserError => e
|
|
63
|
-
raise ReactOnRails::JsonParseError.new(e, json_string)
|
|
79
|
+
raise ReactOnRails::JsonParseError.new(parse_error: e, json: json_string)
|
|
64
80
|
end
|
|
65
81
|
|
|
66
82
|
if render_options.logging_on_server
|
|
67
83
|
console_script = result["consoleReplayScript"]
|
|
68
84
|
console_script_lines = console_script.split("\n")
|
|
69
85
|
console_script_lines = console_script_lines[2..-2]
|
|
70
|
-
re = /console\.(log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
|
75
|
-
end
|
|
86
|
+
re = /console\.(?:log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
|
87
|
+
console_script_lines&.each do |line|
|
|
88
|
+
match = re.match(line)
|
|
89
|
+
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
|
76
90
|
end
|
|
77
91
|
end
|
|
78
92
|
result
|
|
79
93
|
end
|
|
94
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
80
95
|
|
|
81
96
|
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
|
82
97
|
return unless ReactOnRails.configuration.trace || force
|
|
@@ -133,15 +148,15 @@ module ReactOnRails
|
|
|
133
148
|
if ReactOnRails.configuration.trace
|
|
134
149
|
Rails.logger.info do
|
|
135
150
|
"[react_on_rails] Created JavaScript context with file "\
|
|
136
|
-
|
|
151
|
+
"#{ReactOnRails::Utils.server_bundle_js_file_path}"
|
|
137
152
|
end
|
|
138
153
|
end
|
|
139
154
|
ExecJS.compile(base_js_code)
|
|
140
155
|
rescue StandardError => e
|
|
141
156
|
msg = "ERROR when compiling base_js_code! "\
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
157
|
+
"See file #{file_name} to "\
|
|
158
|
+
"correlate line numbers of error. Error is\n\n#{e.message}"\
|
|
159
|
+
"\n\n#{e.backtrace.join("\n")}"
|
|
145
160
|
Rails.logger.error(msg)
|
|
146
161
|
trace_js_code_used("Error when compiling JavaScript code for the context.", base_js_code,
|
|
147
162
|
file_name, force: true)
|
|
@@ -150,6 +165,12 @@ module ReactOnRails
|
|
|
150
165
|
end
|
|
151
166
|
|
|
152
167
|
def execjs_timer_polyfills
|
|
168
|
+
if ReactOnRails::Utils.react_on_rails_pro? &&
|
|
169
|
+
ReactOnRailsPro.configuration.respond_to?(:include_execjs_polyfills) &&
|
|
170
|
+
ReactOnRailsPro.configuration.include_execjs_polyfills == false
|
|
171
|
+
return ""
|
|
172
|
+
end
|
|
173
|
+
|
|
153
174
|
<<~JS
|
|
154
175
|
function getStackTrace () {
|
|
155
176
|
var stack;
|
|
@@ -180,15 +201,17 @@ module ReactOnRails
|
|
|
180
201
|
def undefined_for_exec_js_logging(function_name)
|
|
181
202
|
if ReactOnRails.configuration.trace
|
|
182
203
|
"console.error('[React on Rails Rendering] #{function_name} is not defined for server rendering.');\n"\
|
|
183
|
-
|
|
204
|
+
" console.error(getStackTrace().join('\\n'));"
|
|
184
205
|
else
|
|
185
206
|
""
|
|
186
207
|
end
|
|
187
208
|
end
|
|
188
209
|
|
|
189
210
|
# Reimplement console methods for replaying on the client
|
|
211
|
+
# Save a handle to the original console if needed.
|
|
190
212
|
def console_polyfill
|
|
191
213
|
<<~JS
|
|
214
|
+
var debugConsole = console;
|
|
192
215
|
var console = { history: [] };
|
|
193
216
|
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
|
194
217
|
console[level] = function () {
|
|
@@ -202,6 +225,11 @@ module ReactOnRails
|
|
|
202
225
|
JS
|
|
203
226
|
end
|
|
204
227
|
|
|
228
|
+
if defined?(ScoutApm)
|
|
229
|
+
include ScoutApm::Tracer
|
|
230
|
+
instrument_method :exec_server_render_js, type: "ReactOnRails", name: "ExecJs React Server Rendering"
|
|
231
|
+
end
|
|
232
|
+
|
|
205
233
|
private
|
|
206
234
|
|
|
207
235
|
def file_url_to_string(url)
|
|
@@ -8,7 +8,7 @@ module ReactOnRails
|
|
|
8
8
|
def compile_assets
|
|
9
9
|
if ReactOnRails.configuration.build_test_command.blank?
|
|
10
10
|
msg = <<~MSG
|
|
11
|
-
You are using the React on Rails test helper.
|
|
11
|
+
You are using the React on Rails test helper.
|
|
12
12
|
Either you used:
|
|
13
13
|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets or
|
|
14
14
|
ReactOnRails::TestHelper.ensure_assets_compiled
|
|
@@ -66,10 +66,10 @@ module ReactOnRails
|
|
|
66
66
|
file_list = make_file_list(make_globs(generated_assets_full_path)).to_ary
|
|
67
67
|
puts "V" * 80
|
|
68
68
|
puts "Please define config.webpack_generated_files (array) so the test helper knows "\
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
"which files are required. If you are using webpacker, you typically need to only "\
|
|
70
|
+
"include 'manifest.json'."
|
|
71
71
|
puts "Detected the possible following files to check for webpack compilation in "\
|
|
72
|
-
|
|
72
|
+
"#{generated_assets_full_path}"
|
|
73
73
|
puts file_list.join("\n")
|
|
74
74
|
puts "^" * 80
|
|
75
75
|
file_list
|
|
@@ -52,6 +52,7 @@ module ReactOnRails
|
|
|
52
52
|
# don't provide one.
|
|
53
53
|
# webpack_generated_files List of files to check for up-to-date-status, defaulting to
|
|
54
54
|
# webpack_generated_files in your configuration
|
|
55
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
55
56
|
def self.ensure_assets_compiled(webpack_assets_status_checker: nil,
|
|
56
57
|
webpack_assets_compiler: nil,
|
|
57
58
|
source_path: nil,
|
|
@@ -71,8 +72,8 @@ module ReactOnRails
|
|
|
71
72
|
unless @printed_once
|
|
72
73
|
puts
|
|
73
74
|
puts "====> React On Rails: Checking files in "\
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
"#{webpack_assets_status_checker.generated_assets_full_path} for "\
|
|
76
|
+
"outdated/missing bundles based on source_path #{source_path}"
|
|
76
77
|
puts
|
|
77
78
|
@printed_once = true
|
|
78
79
|
|
|
@@ -96,4 +97,5 @@ module ReactOnRails
|
|
|
96
97
|
).call
|
|
97
98
|
end
|
|
98
99
|
end
|
|
100
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
99
101
|
end
|