react_on_rails 11.0.5 → 13.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +338 -0
- data/.eslintignore +2 -1
- data/.eslintrc +32 -3
- data/.github/FUNDING.yml +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- data/.github/workflows/lint-js-and-ruby.yml +54 -0
- data/.github/workflows/main.yml +183 -0
- data/.github/workflows/package-js-tests.yml +35 -0
- data/.github/workflows/rspec-package-specs.yml +46 -0
- data/.gitignore +3 -4
- data/.prettierignore +14 -0
- data/.prettierrc +20 -0
- data/.rubocop.yml +76 -34
- data/.travis.yml +15 -22
- data/CHANGELOG.md +443 -55
- data/CONTRIBUTING.md +62 -80
- data/Gemfile +1 -35
- data/Gemfile.development_dependencies +50 -0
- data/KUDOS.md +4 -1
- data/{docs/LICENSE.md → LICENSE.md} +1 -1
- data/NEWS.md +14 -4
- data/REACT-ON-RAILS-PRO-LICENSE +95 -0
- data/README.md +107 -802
- data/Rakefile +1 -8
- data/SUMMARY.md +51 -29
- data/book.json +5 -5
- data/docs/{basics/generator.md → additional-details/generator-details.md} +5 -13
- data/docs/{basics/installation-overview.md → additional-details/manual-installation-overview.md} +9 -14
- data/docs/{basics → additional-details}/migrating-from-react-rails.md +1 -1
- data/docs/additional-details/recommended-project-structure.md +69 -0
- data/docs/additional-details/tips-for-usage-with-sp6.md +15 -0
- data/docs/additional-details/upgrade-webpacker-v3-to-v4.md +10 -0
- data/docs/api/javascript-api.md +35 -6
- data/docs/api/redux-store-api.md +102 -0
- data/docs/api/view-helpers-api.md +133 -0
- data/docs/contributor-info/errors-with-hooks.md +45 -0
- data/docs/contributor-info/linters.md +5 -6
- data/docs/contributor-info/pull-requests.md +42 -0
- data/docs/contributor-info/releasing.md +1 -1
- data/docs/deployment/heroku-deployment.md +39 -0
- data/docs/getting-started.md +196 -0
- data/docs/guides/client-vs-server-rendering.md +27 -0
- data/docs/guides/configuration.md +289 -0
- data/docs/guides/deployment.md +5 -0
- data/docs/guides/file-system-based-automated-bundle-generation.md +197 -0
- data/docs/guides/hmr-and-hot-reloading-with-the-webpack-dev-server.md +104 -0
- data/docs/guides/how-react-on-rails-works.md +44 -0
- data/docs/guides/how-to-conditionally-server-render-based-on-device-type.md +40 -0
- data/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md +98 -0
- data/docs/guides/i18n.md +87 -0
- data/docs/guides/installation-into-an-existing-rails-app.md +66 -0
- data/docs/guides/minitest-configuration.md +31 -0
- data/docs/guides/rails-webpacker-react-integration-options.md +213 -0
- data/docs/guides/react-on-rails-overview.md +29 -0
- data/docs/guides/react-server-rendering.md +32 -0
- data/docs/guides/render-functions-and-railscontext.md +205 -0
- data/docs/guides/rspec-configuration.md +73 -0
- data/docs/guides/tutorial.md +371 -0
- data/docs/{basics → guides}/upgrading-react-on-rails.md +126 -3
- data/docs/guides/webpack-configuration.md +42 -0
- data/docs/home.md +23 -0
- data/docs/javascript/asset-pipeline.md +12 -0
- data/docs/{additional-reading → javascript}/code-splitting.md +21 -11
- data/docs/javascript/converting-from-custom-webpack-config-to-rails-webpacker-config.md +10 -0
- data/docs/javascript/credits.md +10 -0
- data/docs/{additional-reading → javascript}/images.md +5 -6
- data/docs/javascript/react-helmet.md +100 -0
- data/docs/javascript/react-router.md +90 -0
- data/docs/{additional-reading → javascript}/server-rendering-tips.md +15 -12
- data/docs/javascript/troubleshooting-when-using-shakapacker.md +77 -0
- data/docs/{additional-reading → javascript}/webpack.md +2 -2
- data/docs/misc/articles.md +20 -0
- data/docs/misc/doctrine.md +5 -6
- data/docs/outdated/deferred-rendering.md +39 -0
- data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +4 -4
- data/docs/{additional-reading → outdated}/rails-assets.md +12 -20
- data/docs/{misc → outdated}/rails3.md +2 -2
- data/docs/rails/convert-rails-5-api-only-app.md +19 -0
- data/docs/rails/rails-engine-integration.md +32 -0
- data/docs/{additional-reading → rails}/rails_view_rendering_from_inline_javascript.md +2 -1
- 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/hvmn.md +25 -0
- data/docs/testimonials/resortpass.md +13 -0
- data/docs/testimonials/testimonials.md +28 -0
- data/jest.config.js +4 -0
- data/lib/generators/USAGE +1 -1
- data/lib/generators/react_on_rails/adapt_for_older_shakapacker_generator.rb +41 -0
- data/lib/generators/react_on_rails/base_generator.rb +55 -43
- data/lib/generators/react_on_rails/bin/dev +30 -0
- data/lib/generators/react_on_rails/bin/dev-static +30 -0
- data/lib/generators/react_on_rails/dev_tests_generator.rb +4 -3
- data/lib/generators/react_on_rails/generator_helper.rb +8 -6
- data/lib/generators/react_on_rails/generator_messages.rb +40 -0
- data/lib/generators/react_on_rails/install_generator.rb +37 -0
- data/lib/generators/react_on_rails/templates/.eslintrc +3 -1
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +4 -6
- 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 +21 -40
- 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 +2 -1
- 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 +20 -4
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +62 -0
- 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 +17 -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 +9 -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/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 +6 -9
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
- data/lib/react_on_rails/configuration.rb +198 -145
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/git_utils.rb +5 -3
- data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +201 -190
- data/lib/react_on_rails/json_output.rb +1 -1
- data/lib/react_on_rails/json_parse_error.rb +28 -0
- data/lib/react_on_rails/locales/base.rb +169 -0
- data/lib/react_on_rails/locales/to_js.rb +33 -0
- data/lib/react_on_rails/locales/to_json.rb +23 -0
- data/lib/react_on_rails/packs_generator.rb +234 -0
- data/lib/react_on_rails/prerender_error.rb +35 -27
- data/lib/react_on_rails/react_component/render_options.rb +64 -9
- data/lib/react_on_rails/server_rendering_js_code.rb +55 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +126 -76
- data/lib/react_on_rails/server_rendering_pool.rb +0 -1
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +9 -8
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +13 -12
- data/lib/react_on_rails/test_helper.rb +24 -3
- data/lib/react_on_rails/utils.rb +94 -25
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +5 -1
- data/lib/react_on_rails/version_syntax_converter.rb +14 -12
- data/lib/react_on_rails/webpacker_utils.rb +105 -5
- data/lib/react_on_rails.rb +8 -2
- data/lib/tasks/assets.rake +28 -60
- data/lib/tasks/generate_packs.rake +11 -0
- data/lib/tasks/locale.rake +5 -4
- data/package-scripts.yml +49 -0
- data/package.json +52 -47
- data/rakelib/docker.rake +0 -5
- data/rakelib/dummy_apps.rake +5 -8
- data/rakelib/example_type.rb +12 -3
- data/rakelib/examples.rake +5 -4
- data/rakelib/lint.rake +5 -16
- data/rakelib/node_package.rake +2 -2
- data/rakelib/release.rake +37 -23
- data/rakelib/run_rspec.rake +16 -44
- data/rakelib/task_helpers.rb +16 -4
- data/react_on_rails.gemspec +6 -22
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +5 -4
- data/yarn.lock +5935 -3106
- metadata +122 -272
- data/Gemfile.rails32 +0 -74
- data/docs/additional-reading/asset-pipeline.md +0 -20
- data/docs/additional-reading/babel.md +0 -5
- data/docs/additional-reading/caching-and-performance.md +0 -4
- data/docs/additional-reading/heroku-deployment.md +0 -92
- data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
- data/docs/additional-reading/node-server-rendering.md +0 -5
- data/docs/additional-reading/rails-engine-integration.md +0 -34
- data/docs/additional-reading/react-helmet.md +0 -80
- data/docs/additional-reading/react-router.md +0 -113
- data/docs/additional-reading/recommended-project-structure.md +0 -49
- data/docs/additional-reading/rspec-configuration.md +0 -56
- data/docs/additional-reading/webpack-dev-server.md +0 -15
- data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
- data/docs/api/ruby-api.md +0 -8
- data/docs/basics/configuration.md +0 -163
- data/docs/basics/i18n.md +0 -77
- data/docs/tutorial.md +0 -220
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
- data/lib/react_on_rails/assets_precompile.rb +0 -150
- data/lib/react_on_rails/locales_to_js.rb +0 -134
- data/ruby-lint.yml +0 -25
- /data/docs/{additional-reading → additional-details}/updating-dependencies.md +0 -0
- /data/docs/{additional-reading → deployment}/elastic-beanstalk.md +0 -0
- /data/docs/{additional-reading → javascript}/angular-js-integration-migration.md +0 -0
- /data/docs/{additional-reading → javascript}/capistrano-deployment.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}/troubleshooting-when-using-webpacker.md +0 -0
- /data/docs/{additional-reading → javascript}/webpack-v1-notes.md +0 -0
- /data/docs/{coding-style → misc}/style.md +0 -0
- /data/docs/{additional-reading → misc}/tips.md +0 -0
@@ -0,0 +1,55 @@
|
|
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
|
+
|
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
|
+
|
34
|
+
js_code_renderer.render(props_string, rails_context, redux_stores, react_component_name, render_options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def render(props_string, rails_context, redux_stores, react_component_name, render_options)
|
38
|
+
<<-JS
|
39
|
+
(function() {
|
40
|
+
var railsContext = #{rails_context};
|
41
|
+
#{redux_stores}
|
42
|
+
var props = #{props_string};
|
43
|
+
return ReactOnRails.serverRenderReactComponent({
|
44
|
+
name: '#{react_component_name}',
|
45
|
+
domNodeId: '#{render_options.dom_id}',
|
46
|
+
props: props,
|
47
|
+
trace: #{render_options.trace},
|
48
|
+
railsContext: railsContext
|
49
|
+
});
|
50
|
+
})()
|
51
|
+
JS
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
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
|
-
|
21
|
-
|
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
|
-
|
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
|
|
@@ -39,6 +47,7 @@ module ReactOnRails
|
|
39
47
|
# Note, js_code does not have to be based on React.
|
40
48
|
# js_code MUST RETURN json stringify Object
|
41
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
|
42
51
|
def exec_server_render_js(js_code, render_options, js_evaluator = nil)
|
43
52
|
js_evaluator ||= self
|
44
53
|
if render_options.trace
|
@@ -47,26 +56,46 @@ module ReactOnRails
|
|
47
56
|
"tmp/server-generated-#{@file_index % 10}.js")
|
48
57
|
@file_index += 1
|
49
58
|
end
|
50
|
-
|
51
|
-
|
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
|
75
|
+
result = nil
|
76
|
+
begin
|
77
|
+
result = JSON.parse(json_string)
|
78
|
+
rescue JSON::ParserError => e
|
79
|
+
raise ReactOnRails::JsonParseError.new(parse_error: e, json: json_string)
|
80
|
+
end
|
52
81
|
|
53
82
|
if render_options.logging_on_server
|
54
83
|
console_script = result["consoleReplayScript"]
|
55
84
|
console_script_lines = console_script.split("\n")
|
56
85
|
console_script_lines = console_script_lines[2..-2]
|
57
|
-
re = /console\.(log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
62
|
-
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
|
63
90
|
end
|
64
91
|
end
|
65
92
|
result
|
66
93
|
end
|
94
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
67
95
|
|
68
96
|
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
69
97
|
return unless ReactOnRails.configuration.trace || force
|
98
|
+
|
70
99
|
# Set to anything to print generated code.
|
71
100
|
File.write(file_name, js_code)
|
72
101
|
msg = <<-MSG.strip_heredoc
|
@@ -82,45 +111,50 @@ module ReactOnRails
|
|
82
111
|
end
|
83
112
|
end
|
84
113
|
|
85
|
-
def eval_js(js_code)
|
114
|
+
def eval_js(js_code, _render_options)
|
86
115
|
@js_context_pool.with do |js_context|
|
87
|
-
|
88
|
-
js_context.eval("console.history = []")
|
89
|
-
result
|
116
|
+
js_context.eval(js_code)
|
90
117
|
end
|
91
118
|
end
|
92
119
|
|
93
|
-
def
|
94
|
-
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
95
|
-
|
120
|
+
def read_bundle_js_code
|
96
121
|
server_js_file = ReactOnRails::Utils.server_bundle_js_file_path
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
122
|
+
if ReactOnRails::Utils.server_bundle_path_is_http?
|
123
|
+
file_url_to_string(server_js_file)
|
124
|
+
else
|
125
|
+
File.read(server_js_file)
|
126
|
+
end
|
127
|
+
rescue StandardError => e
|
128
|
+
msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
|
102
129
|
"read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
|
103
130
|
"avoid this warning.\nError is: #{e}"
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
131
|
+
raise ReactOnRails::Error, msg
|
132
|
+
end
|
133
|
+
|
134
|
+
def create_js_context
|
135
|
+
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
136
|
+
|
137
|
+
bundle_js_code = read_bundle_js_code
|
138
|
+
base_js_code = <<~JS
|
139
|
+
#{console_polyfill}
|
140
|
+
#{execjs_timer_polyfills}
|
141
|
+
#{bundle_js_code};
|
111
142
|
JS
|
112
|
-
|
143
|
+
|
113
144
|
file_name = "tmp/base_js_code.js"
|
114
145
|
begin
|
115
146
|
if ReactOnRails.configuration.trace
|
116
|
-
Rails.logger.info
|
147
|
+
Rails.logger.info do
|
148
|
+
"[react_on_rails] Created JavaScript context with file "\
|
149
|
+
"#{ReactOnRails::Utils.server_bundle_js_file_path}"
|
150
|
+
end
|
117
151
|
end
|
118
152
|
ExecJS.compile(base_js_code)
|
119
153
|
rescue StandardError => e
|
120
154
|
msg = "ERROR when compiling base_js_code! "\
|
121
|
-
|
122
|
-
|
123
|
-
|
155
|
+
"See file #{file_name} to "\
|
156
|
+
"correlate line numbers of error. Error is\n\n#{e.message}"\
|
157
|
+
"\n\n#{e.backtrace.join("\n")}"
|
124
158
|
Rails.logger.error(msg)
|
125
159
|
trace_js_code_used("Error when compiling JavaScript code for the context.", base_js_code,
|
126
160
|
file_name, force: true)
|
@@ -129,60 +163,76 @@ module ReactOnRails
|
|
129
163
|
end
|
130
164
|
|
131
165
|
def execjs_timer_polyfills
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
}
|
166
|
+
<<~JS
|
167
|
+
function getStackTrace () {
|
168
|
+
var stack;
|
169
|
+
try {
|
170
|
+
throw new Error('');
|
171
|
+
}
|
172
|
+
catch (error) {
|
173
|
+
stack = error.stack || '';
|
174
|
+
}
|
175
|
+
stack = stack.split('\\n').map(function (line) { return line.trim(); });
|
176
|
+
return stack.splice(stack[0] == 'Error' ? 2 : 1);
|
177
|
+
}
|
178
|
+
|
179
|
+
function setInterval() {
|
180
|
+
#{undefined_for_exec_js_logging('setInterval')}
|
181
|
+
}
|
182
|
+
|
183
|
+
function setTimeout() {
|
184
|
+
#{undefined_for_exec_js_logging('setTimeout')}
|
185
|
+
}
|
186
|
+
|
187
|
+
function clearTimeout() {
|
188
|
+
#{undefined_for_exec_js_logging('clearTimeout')}
|
189
|
+
}
|
157
190
|
JS
|
158
|
-
# rubocop:enable Layout/IndentHeredoc
|
159
191
|
end
|
160
192
|
|
161
193
|
def undefined_for_exec_js_logging(function_name)
|
162
194
|
if ReactOnRails.configuration.trace
|
163
195
|
"console.error('[React on Rails Rendering] #{function_name} is not defined for server rendering.');\n"\
|
164
|
-
|
196
|
+
" console.error(getStackTrace().join('\\n'));"
|
165
197
|
else
|
166
198
|
""
|
167
199
|
end
|
168
200
|
end
|
169
201
|
|
170
202
|
# Reimplement console methods for replaying on the client
|
203
|
+
# Save a handle to the original console if needed.
|
171
204
|
def console_polyfill
|
172
|
-
|
173
|
-
|
174
|
-
var console = { history: [] };
|
175
|
-
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
});
|
205
|
+
<<~JS
|
206
|
+
var debugConsole = console;
|
207
|
+
var console = { history: [] };
|
208
|
+
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
209
|
+
console[level] = function () {
|
210
|
+
var argArray = Array.prototype.slice.call(arguments);
|
211
|
+
if (argArray.length > 0) {
|
212
|
+
argArray[0] = '[SERVER] ' + argArray[0];
|
213
|
+
}
|
214
|
+
console.history.push({level: level, arguments: argArray});
|
215
|
+
};
|
216
|
+
});
|
184
217
|
JS
|
185
|
-
|
218
|
+
end
|
219
|
+
|
220
|
+
if defined?(ScoutApm)
|
221
|
+
include ScoutApm::Tracer
|
222
|
+
instrument_method :exec_server_render_js, type: "ReactOnRails", name: "ExecJs React Server Rendering"
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def file_url_to_string(url)
|
228
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
229
|
+
content_type_header = response["content-type"]
|
230
|
+
match = content_type_header.match(/\A.*; charset=(?<encoding>.*)\z/)
|
231
|
+
encoding_type = match[:encoding]
|
232
|
+
response.body.force_encoding(encoding_type)
|
233
|
+
rescue StandardError => e
|
234
|
+
msg = "file_url_to_string #{url} failed\nError is: #{e}"
|
235
|
+
raise ReactOnRails::Error, msg
|
186
236
|
end
|
187
237
|
end
|
188
238
|
end
|
@@ -5,7 +5,6 @@ require_relative "server_rendering_pool/ruby_embedded_java_script"
|
|
5
5
|
|
6
6
|
# Based on the react-rails gem.
|
7
7
|
# None of these methods should be called directly.
|
8
|
-
# See app/helpers/react_on_rails_helper.rb
|
9
8
|
module ReactOnRails
|
10
9
|
module ServerRenderingPool
|
11
10
|
class << self
|
@@ -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,13 +30,15 @@ module ReactOnRails
|
|
29
30
|
# Be sure we don't do this again.
|
30
31
|
self.class.has_been_run = true
|
31
32
|
|
32
|
-
ReactOnRails::
|
33
|
+
ReactOnRails::Locales.compile
|
33
34
|
|
34
35
|
stale_gen_files = webpack_assets_status_checker.stale_generated_webpack_files
|
35
36
|
|
36
37
|
# All done if no stale files!
|
37
38
|
return if stale_gen_files.empty?
|
38
39
|
|
40
|
+
ReactOnRails::PacksGenerator.instance.generate_packs_if_stale if ReactOnRails.configuration.auto_load_bundle
|
41
|
+
|
39
42
|
# Inform the developer that we're ensuring gen assets are ready.
|
40
43
|
puts_start_compile_check_message(stale_gen_files)
|
41
44
|
|
@@ -43,17 +46,15 @@ module ReactOnRails
|
|
43
46
|
end
|
44
47
|
|
45
48
|
def puts_start_compile_check_message(stale_files)
|
46
|
-
|
47
|
-
puts <<-MSG
|
49
|
+
puts <<~MSG
|
48
50
|
|
49
|
-
Detected the following stale generated files:
|
50
|
-
|
51
|
+
Detected the following stale generated files:
|
52
|
+
#{stale_files.join("\n ")}
|
51
53
|
|
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
|
+
React on Rails will ensure your JavaScript generated files are up to date, using your
|
55
|
+
`#{ReactOnRails::Utils.prepend_cd_node_modules_directory(ReactOnRails.configuration.build_test_command)}` command.
|
54
56
|
|
55
57
|
MSG
|
56
|
-
# rubocop:enable Layout/IndentHeredoc
|
57
58
|
end
|
58
59
|
end
|
59
60
|
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(
|
@@ -26,12 +26,16 @@ module ReactOnRails
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def stale_generated_webpack_files
|
29
|
+
stale_generated_files(client_files)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stale_generated_files(files)
|
29
33
|
manifest_needed = ReactOnRails::WebpackerUtils.using_webpacker? &&
|
30
34
|
!ReactOnRails::WebpackerUtils.manifest_exists?
|
31
35
|
|
32
36
|
return ["manifest.json"] if manifest_needed
|
33
37
|
|
34
|
-
most_recent_mtime = find_most_recent_mtime
|
38
|
+
most_recent_mtime = Utils.find_most_recent_mtime(files)
|
35
39
|
all_compiled_assets.each_with_object([]) do |webpack_generated_file, stale_gen_list|
|
36
40
|
if !File.exist?(webpack_generated_file) ||
|
37
41
|
File.mtime(webpack_generated_file) < most_recent_mtime
|
@@ -43,17 +47,14 @@ module ReactOnRails
|
|
43
47
|
|
44
48
|
private
|
45
49
|
|
46
|
-
def find_most_recent_mtime
|
47
|
-
client_files.reduce(1.year.ago) do |newest_time, file|
|
48
|
-
mt = File.mtime(file)
|
49
|
-
mt > newest_time ? mt : newest_time
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
50
|
def all_compiled_assets
|
54
51
|
@all_compiled_assets ||= begin
|
55
52
|
webpack_generated_files = @webpack_generated_files.map do |bundle_name|
|
56
|
-
ReactOnRails
|
53
|
+
if bundle_name == ReactOnRails.configuration.server_bundle_js_file
|
54
|
+
ReactOnRails::Utils.server_bundle_js_file_path
|
55
|
+
else
|
56
|
+
ReactOnRails::Utils.bundle_js_file_path(bundle_name)
|
57
|
+
end
|
57
58
|
end
|
58
59
|
|
59
60
|
if webpack_generated_files.present?
|
@@ -62,10 +63,10 @@ module ReactOnRails
|
|
62
63
|
file_list = make_file_list(make_globs(generated_assets_full_path)).to_ary
|
63
64
|
puts "V" * 80
|
64
65
|
puts "Please define config.webpack_generated_files (array) so the test helper knows "\
|
65
|
-
|
66
|
-
|
66
|
+
"which files are required. If you are using webpacker, you typically need to only "\
|
67
|
+
"include 'manifest.json'."
|
67
68
|
puts "Detected the possible following files to check for webpack compilation in "\
|
68
|
-
|
69
|
+
"#{generated_assets_full_path}"
|
69
70
|
puts file_list.join("\n")
|
70
71
|
puts "^" * 80
|
71
72
|
file_list
|
@@ -35,8 +35,17 @@ module ReactOnRails
|
|
35
35
|
def self.configure_rspec_to_compile_assets(config, *metatags)
|
36
36
|
metatags = %i[js server_rendering controller] if metatags.empty?
|
37
37
|
|
38
|
+
# Supported since RSpec 3.5.0
|
39
|
+
supports_first_matching_example = config.respond_to?(:when_first_matching_example_defined)
|
40
|
+
|
38
41
|
metatags.each do |metatag|
|
39
|
-
|
42
|
+
if supports_first_matching_example
|
43
|
+
config.when_first_matching_example_defined(metatag) do
|
44
|
+
ReactOnRails::TestHelper.ensure_assets_compiled
|
45
|
+
end
|
46
|
+
else
|
47
|
+
config.before(:example, metatag) { ReactOnRails::TestHelper.ensure_assets_compiled }
|
48
|
+
end
|
40
49
|
end
|
41
50
|
end
|
42
51
|
|
@@ -52,6 +61,7 @@ module ReactOnRails
|
|
52
61
|
# don't provide one.
|
53
62
|
# webpack_generated_files List of files to check for up-to-date-status, defaulting to
|
54
63
|
# webpack_generated_files in your configuration
|
64
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
55
65
|
def self.ensure_assets_compiled(webpack_assets_status_checker: nil,
|
56
66
|
webpack_assets_compiler: nil,
|
57
67
|
source_path: nil,
|
@@ -71,10 +81,20 @@ module ReactOnRails
|
|
71
81
|
unless @printed_once
|
72
82
|
puts
|
73
83
|
puts "====> React On Rails: Checking files in "\
|
74
|
-
|
75
|
-
|
84
|
+
"#{webpack_assets_status_checker.generated_assets_full_path} for "\
|
85
|
+
"outdated/missing bundles based on source_path #{source_path}"
|
76
86
|
puts
|
77
87
|
@printed_once = true
|
88
|
+
|
89
|
+
if ReactOnRails::WebpackerUtils.using_webpacker? &&
|
90
|
+
ReactOnRails::Utils.using_webpacker_source_path_is_not_defined_and_custom_node_modules?
|
91
|
+
msg = <<-MSG.strip_heredoc
|
92
|
+
WARNING: Define config.webpacker.yml to include sourcePath to configure
|
93
|
+
the location of your JavaScript source for React on Rails.
|
94
|
+
Default location of #{source_path} is used.
|
95
|
+
MSG
|
96
|
+
puts ReactOnRails::Utils.wrap_message(msg, :orange)
|
97
|
+
end
|
78
98
|
end
|
79
99
|
end
|
80
100
|
|
@@ -86,4 +106,5 @@ module ReactOnRails
|
|
86
106
|
).call
|
87
107
|
end
|
88
108
|
end
|
109
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
89
110
|
end
|