react_on_rails 11.0.0 → 11.1.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 +5 -5
- data/.rubocop.yml +1 -1
- data/.travis.yml +2 -2
- data/CHANGELOG.md +80 -3
- data/CONTRIBUTING.md +7 -8
- data/{docs/LICENSE.md → LICENSE.md} +1 -1
- data/PROJECTS.md +7 -1
- data/README.md +175 -637
- data/Rakefile +4 -1
- data/SUMMARY.md +39 -26
- data/docs/additional-reading/convert-rails-5-api-only-app.md +19 -0
- data/docs/additional-reading/credits.md +10 -0
- data/docs/additional-reading/rails-assets-relative-paths.md +2 -2
- data/docs/additional-reading/rails-engine-integration.md +7 -0
- data/docs/additional-reading/server-rendering-tips.md +2 -4
- data/docs/additional-reading/webpack.md +2 -2
- data/docs/api/javascript-api.md +21 -1
- data/docs/api/redux-store-api.md +100 -0
- data/docs/api/view-helpers-api.md +130 -0
- data/docs/articles.md +20 -0
- data/docs/basics/client-vs-server-rendering.md +17 -0
- data/docs/basics/configuration.md +39 -5
- data/docs/basics/deployment.md +6 -0
- data/docs/basics/{generator.md → generator-details.md} +4 -7
- data/docs/basics/generator-functions-and-railscontext.md +157 -0
- data/docs/basics/how-react-on-rails-works.md +40 -0
- data/docs/basics/installation-into-an-existing-rails-app.md +64 -0
- data/docs/basics/react-server-rendering.md +27 -0
- data/docs/{additional-reading → basics}/recommended-project-structure.md +26 -4
- data/docs/{additional-reading → basics}/rspec-configuration.md +12 -6
- data/docs/basics/upgrading-react-on-rails.md +3 -3
- data/docs/basics/webpack-configuration.md +29 -0
- data/docs/misc/doctrine.md +1 -1
- data/docs/{additional-reading → misc-pending}/code-splitting.md +8 -2
- data/docs/{basics/installation-overview.md → misc-pending/manual-installation-overview.md} +3 -8
- data/docs/{additional-reading → misc-pending}/rails-assets.md +3 -1
- data/docs/testimonials.md +11 -0
- data/docs/tutorial.md +4 -4
- data/lib/generators/USAGE +1 -1
- data/lib/react_on_rails/configuration.rb +139 -97
- data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +104 -79
- data/lib/react_on_rails/json_parse_error.rb +26 -0
- data/lib/react_on_rails/prerender_error.rb +48 -6
- data/lib/react_on_rails/react_component/render_options.rb +94 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +58 -50
- data/lib/react_on_rails/server_rendering_pool.rb +4 -16
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +10 -6
- data/lib/react_on_rails/test_helper.rb +8 -7
- data/lib/react_on_rails/utils.rb +38 -6
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_syntax_converter.rb +14 -12
- data/lib/react_on_rails/webpacker_utils.rb +11 -8
- data/lib/react_on_rails.rb +4 -2
- data/package.json +3 -2
- data/rakelib/release.rake +1 -1
- data/react_on_rails.gemspec +2 -2
- metadata +32 -21
- data/docs/additional-reading/caching-and-performance.md +0 -4
- data/docs/additional-reading/node-server-rendering.md +0 -5
- data/docs/api/ruby-api.md +0 -8
- data/lib/react_on_rails/react_component/options.rb +0 -64
|
@@ -2,10 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
# rubocop:disable: Layout/IndentHeredoc
|
|
4
4
|
module ReactOnRails
|
|
5
|
-
class PrerenderError <
|
|
5
|
+
class PrerenderError < ::ReactOnRails::Error
|
|
6
|
+
MAX_ERROR_SNIPPET_TO_LOG = 1000
|
|
7
|
+
# TODO: Consider remove providing original `err` as already have access to `self.cause`
|
|
8
|
+
# http://blog.honeybadger.io/nested-errors-in-ruby-with-exception-cause/
|
|
9
|
+
attr_reader :component_name, :err, :props, :js_code, :console_messages
|
|
10
|
+
|
|
6
11
|
# err might be nil if JS caught the error
|
|
7
12
|
def initialize(component_name: nil, err: nil, props: nil,
|
|
8
13
|
js_code: nil, console_messages: nil)
|
|
14
|
+
@component_name = component_name
|
|
15
|
+
@err = err
|
|
16
|
+
@props = props
|
|
17
|
+
@js_code = js_code
|
|
18
|
+
@console_messages = console_messages
|
|
19
|
+
|
|
20
|
+
backtrace, message = calc_message(component_name, console_messages, err, js_code, props)
|
|
21
|
+
|
|
22
|
+
super([message, backtrace].compact.join("\n"))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_honeybadger_context
|
|
26
|
+
to_error_context
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def raven_context
|
|
30
|
+
to_error_context
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_error_context
|
|
34
|
+
result = {
|
|
35
|
+
component_name: component_name,
|
|
36
|
+
err: err,
|
|
37
|
+
props: props,
|
|
38
|
+
js_code: js_code,
|
|
39
|
+
console_messages: console_messages
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
result.merge!(err.to_error_context) if err.respond_to?(:to_error_context)
|
|
43
|
+
result
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def calc_message(component_name, console_messages, err, js_code, props)
|
|
9
49
|
message = "ERROR in SERVER PRERENDERING\n".dup
|
|
10
50
|
if err
|
|
11
51
|
# rubocop:disable Layout/IndentHeredoc
|
|
@@ -19,9 +59,12 @@ Encountered error: \"#{err}\"
|
|
|
19
59
|
end
|
|
20
60
|
# rubocop:disable Layout/IndentHeredoc
|
|
21
61
|
message << <<-MSG
|
|
22
|
-
when prerendering #{component_name} with props: #{props}
|
|
23
|
-
|
|
24
|
-
|
|
62
|
+
when prerendering #{component_name} with props: #{Utils.smart_trim(props, MAX_ERROR_SNIPPET_TO_LOG)}
|
|
63
|
+
|
|
64
|
+
code:
|
|
65
|
+
|
|
66
|
+
#{Utils.smart_trim(js_code, MAX_ERROR_SNIPPET_TO_LOG)}
|
|
67
|
+
|
|
25
68
|
MSG
|
|
26
69
|
# rubocop:enable Layout/IndentHeredoc
|
|
27
70
|
|
|
@@ -33,8 +76,7 @@ console messages:
|
|
|
33
76
|
MSG
|
|
34
77
|
# rubocop:enable Layout/IndentHeredoc
|
|
35
78
|
end
|
|
36
|
-
|
|
37
|
-
super([message, backtrace].compact.join("\n"))
|
|
79
|
+
[backtrace, message]
|
|
38
80
|
end
|
|
39
81
|
end
|
|
40
82
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "react_on_rails/utils"
|
|
4
|
+
|
|
5
|
+
module ReactOnRails
|
|
6
|
+
module ReactComponent
|
|
7
|
+
class RenderOptions
|
|
8
|
+
include Utils::Required
|
|
9
|
+
|
|
10
|
+
attr_accessor :request_digest
|
|
11
|
+
|
|
12
|
+
NO_PROPS = {}.freeze
|
|
13
|
+
|
|
14
|
+
def initialize(react_component_name: required("react_component_name"), options: required("options"))
|
|
15
|
+
@react_component_name = react_component_name.camelize
|
|
16
|
+
@options = options
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :react_component_name
|
|
20
|
+
|
|
21
|
+
def props
|
|
22
|
+
options.fetch(:props) { NO_PROPS }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def random_dom_id
|
|
26
|
+
retrieve_key(:random_dom_id)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def dom_id
|
|
30
|
+
@dom_id ||= options.fetch(:id) do
|
|
31
|
+
if random_dom_id
|
|
32
|
+
generate_unique_dom_id
|
|
33
|
+
else
|
|
34
|
+
base_dom_id
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_random_dom_id?
|
|
40
|
+
return false if options[:id]
|
|
41
|
+
|
|
42
|
+
return false unless random_dom_id
|
|
43
|
+
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def html_options
|
|
48
|
+
options[:html_options].to_h
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def prerender
|
|
52
|
+
retrieve_key(:prerender)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def trace
|
|
56
|
+
retrieve_key(:trace)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def replay_console
|
|
60
|
+
retrieve_key(:replay_console)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def raise_on_prerender_error
|
|
64
|
+
retrieve_key(:raise_on_prerender_error)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def logging_on_server
|
|
68
|
+
retrieve_key(:logging_on_server)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_s
|
|
72
|
+
"{ react_component_name = #{react_component_name}, options = #{options}, request_digest = #{request_digest}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
attr_reader :options
|
|
78
|
+
|
|
79
|
+
def base_dom_id
|
|
80
|
+
"#{react_component_name}-react-component"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def generate_unique_dom_id
|
|
84
|
+
"#{base_dom_id}-#{SecureRandom.uuid}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def retrieve_key(key)
|
|
88
|
+
options.fetch(key) do
|
|
89
|
+
ReactOnRails.configuration.public_send(key)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -5,61 +5,70 @@ require "open-uri"
|
|
|
5
5
|
module ReactOnRails
|
|
6
6
|
module ServerRenderingPool
|
|
7
7
|
class RubyEmbeddedJavaScript
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
class << self
|
|
9
|
+
def reset_pool
|
|
10
|
+
options = {
|
|
11
|
+
size: ReactOnRails.configuration.server_renderer_pool_size,
|
|
12
|
+
timeout: ReactOnRails.configuration.server_renderer_timeout
|
|
13
|
+
}
|
|
14
|
+
@js_context_pool = ConnectionPool.new(options) { create_js_context }
|
|
15
|
+
end
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
def reset_pool_if_server_bundle_was_modified
|
|
18
|
+
return unless ReactOnRails.configuration.development_mode
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
@server_bundle_timestamp = file_mtime
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# js_code: JavaScript expression that returns a string.
|
|
29
|
-
# Returns a Hash:
|
|
30
|
-
# html: string of HTML for direct insertion on the page by evaluating js_code
|
|
31
|
-
# consoleReplayScript: script for replaying console
|
|
32
|
-
# hasErrors: true if server rendering errors
|
|
33
|
-
# Note, js_code does not have to be based on React.
|
|
34
|
-
# js_code MUST RETURN json stringify Object
|
|
35
|
-
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
|
36
|
-
def self.server_render_js_with_console_logging(js_code)
|
|
37
|
-
if ReactOnRails.configuration.trace
|
|
38
|
-
@file_index ||= 1
|
|
39
|
-
trace_js_code_used("Evaluating code to server render.", js_code,
|
|
40
|
-
"tmp/server-generated-#{@file_index % 10}.js")
|
|
41
|
-
@file_index += 1
|
|
26
|
+
ReactOnRails::ServerRenderingPool.reset_pool
|
|
42
27
|
end
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
28
|
+
|
|
29
|
+
# js_code: JavaScript expression that returns a string.
|
|
30
|
+
# render_options: lib/react_on_rails/react_component/render_options.rb
|
|
31
|
+
# Using these options:
|
|
32
|
+
# trace: saves the executed JS to a file, used in development
|
|
33
|
+
# logging_on_server: put on server logs, not just in browser console
|
|
34
|
+
#
|
|
35
|
+
# Returns a Hash:
|
|
36
|
+
# html: string of HTML for direct insertion on the page by evaluating js_code
|
|
37
|
+
# consoleReplayScript: script for replaying console
|
|
38
|
+
# hasErrors: true if server rendering errors
|
|
39
|
+
# Note, js_code does not have to be based on React.
|
|
40
|
+
# js_code MUST RETURN json stringify Object
|
|
41
|
+
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
|
42
|
+
def exec_server_render_js(js_code, render_options, js_evaluator = nil)
|
|
43
|
+
js_evaluator ||= self
|
|
44
|
+
if render_options.trace
|
|
45
|
+
@file_index ||= 1
|
|
46
|
+
trace_js_code_used("Evaluating code to server render.", js_code,
|
|
47
|
+
"tmp/server-generated-#{@file_index % 10}.js")
|
|
48
|
+
@file_index += 1
|
|
49
|
+
end
|
|
50
|
+
json_string = js_evaluator.eval_js(js_code, render_options)
|
|
51
|
+
result = nil
|
|
52
|
+
begin
|
|
53
|
+
result = JSON.parse(json_string)
|
|
54
|
+
rescue JSON::ParserError => e
|
|
55
|
+
raise ReactOnRails::JsonParseError.new(e, json_string)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if render_options.logging_on_server
|
|
59
|
+
console_script = result["consoleReplayScript"]
|
|
60
|
+
console_script_lines = console_script.split("\n")
|
|
61
|
+
console_script_lines = console_script_lines[2..-2]
|
|
62
|
+
re = /console\.(log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
|
63
|
+
if console_script_lines
|
|
64
|
+
console_script_lines.each do |line|
|
|
65
|
+
match = re.match(line)
|
|
66
|
+
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
|
67
|
+
end
|
|
55
68
|
end
|
|
56
69
|
end
|
|
70
|
+
result
|
|
57
71
|
end
|
|
58
|
-
result
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
class << self
|
|
62
|
-
private
|
|
63
72
|
|
|
64
73
|
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
|
65
74
|
return unless ReactOnRails.configuration.trace || force
|
|
@@ -78,7 +87,7 @@ module ReactOnRails
|
|
|
78
87
|
end
|
|
79
88
|
end
|
|
80
89
|
|
|
81
|
-
def eval_js(js_code)
|
|
90
|
+
def eval_js(js_code, _render_options)
|
|
82
91
|
@js_context_pool.with do |js_context|
|
|
83
92
|
result = js_context.eval(js_code)
|
|
84
93
|
js_context.eval("console.history = []")
|
|
@@ -156,8 +165,7 @@ function clearTimeout() {
|
|
|
156
165
|
|
|
157
166
|
def undefined_for_exec_js_logging(function_name)
|
|
158
167
|
if ReactOnRails.configuration.trace
|
|
159
|
-
"console.error('[React on Rails Rendering] #{function_name} is not defined for
|
|
160
|
-
"https://github.com/sstephenson/execjs#faq. Note babel-polyfill may call this.');\n"\
|
|
168
|
+
"console.error('[React on Rails Rendering] #{function_name} is not defined for server rendering.');\n"\
|
|
161
169
|
" console.error(getStackTrace().join('\\n'));"
|
|
162
170
|
else
|
|
163
171
|
""
|
|
@@ -5,33 +5,21 @@ 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
|
|
12
|
-
def react_on_rails_pro?
|
|
13
|
-
@react_on_rails_pro ||= gem_available?("react_on_rails_pro")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
11
|
def pool
|
|
17
|
-
@pool ||= if react_on_rails_pro?
|
|
12
|
+
@pool ||= if ReactOnRails::Utils.react_on_rails_pro?
|
|
18
13
|
ReactOnRailsPro::ServerRenderingPool::ProRendering
|
|
19
14
|
else
|
|
20
15
|
ReactOnRails::ServerRenderingPool::RubyEmbeddedJavaScript
|
|
21
16
|
end
|
|
22
17
|
end
|
|
23
18
|
|
|
24
|
-
delegate :
|
|
25
|
-
:reset_pool, to: :pool
|
|
26
|
-
|
|
27
|
-
private
|
|
19
|
+
delegate :reset_pool_if_server_bundle_was_modified, :reset_pool, to: :pool
|
|
28
20
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
rescue Gem::LoadError
|
|
32
|
-
false
|
|
33
|
-
rescue StandardError
|
|
34
|
-
Gem.available?(name)
|
|
21
|
+
def server_render_js_with_console_logging(js_code, render_options)
|
|
22
|
+
pool.exec_server_render_js(js_code, render_options)
|
|
35
23
|
end
|
|
36
24
|
end
|
|
37
25
|
end
|
|
@@ -13,14 +13,14 @@ module ReactOnRails
|
|
|
13
13
|
# source_path is typically configured in the webpacker.yml file
|
|
14
14
|
# for `source_path`
|
|
15
15
|
# or for legacy React on Rails, it's /client, where all client files go
|
|
16
|
-
attr_reader :source_path, :
|
|
16
|
+
attr_reader :source_path, :generated_assets_full_path
|
|
17
17
|
|
|
18
18
|
def initialize(
|
|
19
|
-
|
|
19
|
+
generated_assets_full_path: required("generated_assets_full_path"),
|
|
20
20
|
source_path: required("source_path"),
|
|
21
21
|
webpack_generated_files: required("webpack_generated_files")
|
|
22
22
|
)
|
|
23
|
-
@
|
|
23
|
+
@generated_assets_full_path = generated_assets_full_path
|
|
24
24
|
@source_path = source_path
|
|
25
25
|
@webpack_generated_files = webpack_generated_files
|
|
26
26
|
end
|
|
@@ -53,19 +53,23 @@ module ReactOnRails
|
|
|
53
53
|
def all_compiled_assets
|
|
54
54
|
@all_compiled_assets ||= begin
|
|
55
55
|
webpack_generated_files = @webpack_generated_files.map do |bundle_name|
|
|
56
|
-
ReactOnRails
|
|
56
|
+
if bundle_name == ReactOnRails.configuration.server_bundle_js_file
|
|
57
|
+
ReactOnRails::Utils.server_bundle_js_file_path
|
|
58
|
+
else
|
|
59
|
+
ReactOnRails::Utils.bundle_js_file_path(bundle_name)
|
|
60
|
+
end
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
if webpack_generated_files.present?
|
|
60
64
|
webpack_generated_files
|
|
61
65
|
else
|
|
62
|
-
file_list = make_file_list(make_globs(
|
|
66
|
+
file_list = make_file_list(make_globs(generated_assets_full_path)).to_ary
|
|
63
67
|
puts "V" * 80
|
|
64
68
|
puts "Please define config.webpack_generated_files (array) so the test helper knows "\
|
|
65
69
|
"which files are required. If you are using webpacker, you typically need to only "\
|
|
66
70
|
"include 'manifest.json'."
|
|
67
71
|
puts "Detected the possible following files to check for webpack compilation in "\
|
|
68
|
-
"#{
|
|
72
|
+
"#{generated_assets_full_path}"
|
|
69
73
|
puts file_list.join("\n")
|
|
70
74
|
puts "^" * 80
|
|
71
75
|
file_list
|
|
@@ -31,7 +31,7 @@ module ReactOnRails
|
|
|
31
31
|
# Params:
|
|
32
32
|
# config - config for rspec
|
|
33
33
|
# metatags - metatags to add the ensure_assets_compiled check.
|
|
34
|
-
# Default is :js, :server_rendering
|
|
34
|
+
# Default is :js, :server_rendering, :controller
|
|
35
35
|
def self.configure_rspec_to_compile_assets(config, *metatags)
|
|
36
36
|
metatags = %i[js server_rendering controller] if metatags.empty?
|
|
37
37
|
|
|
@@ -48,30 +48,31 @@ module ReactOnRails
|
|
|
48
48
|
# defaults to ReactOnRails::TestHelper::WebpackAssetsStatusChecker
|
|
49
49
|
# webpack_assets_compiler: provide one method: `def compile`
|
|
50
50
|
# defaults to ReactOnRails::TestHelper::WebpackAssetsCompiler
|
|
51
|
-
# source_path and
|
|
51
|
+
# source_path and generated_assets_full_path are passed into the default webpack_assets_status_checker if you
|
|
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
55
|
def self.ensure_assets_compiled(webpack_assets_status_checker: nil,
|
|
56
56
|
webpack_assets_compiler: nil,
|
|
57
57
|
source_path: nil,
|
|
58
|
-
|
|
58
|
+
generated_assets_full_path: nil,
|
|
59
59
|
webpack_generated_files: nil)
|
|
60
60
|
ReactOnRails::WebpackerUtils.check_manifest_not_cached
|
|
61
61
|
if webpack_assets_status_checker.nil?
|
|
62
62
|
source_path ||= ReactOnRails::Utils.source_path
|
|
63
|
-
|
|
63
|
+
generated_assets_full_path ||= ReactOnRails::Utils.generated_assets_full_path
|
|
64
64
|
webpack_generated_files ||= ReactOnRails.configuration.webpack_generated_files
|
|
65
65
|
|
|
66
66
|
webpack_assets_status_checker ||=
|
|
67
67
|
WebpackAssetsStatusChecker.new(source_path: source_path,
|
|
68
|
-
|
|
68
|
+
generated_assets_full_path: generated_assets_full_path,
|
|
69
69
|
webpack_generated_files: webpack_generated_files)
|
|
70
70
|
|
|
71
71
|
unless @printed_once
|
|
72
72
|
puts
|
|
73
|
-
puts "====> React On Rails: Checking
|
|
74
|
-
|
|
73
|
+
puts "====> React On Rails: Checking files in "\
|
|
74
|
+
"#{webpack_assets_status_checker.generated_assets_full_path} for "\
|
|
75
|
+
"outdated/missing bundles based on source_path #{source_path}"
|
|
75
76
|
puts
|
|
76
77
|
@printed_once = true
|
|
77
78
|
end
|
data/lib/react_on_rails/utils.rb
CHANGED
|
@@ -8,6 +8,8 @@ require "active_support/core_ext/string"
|
|
|
8
8
|
|
|
9
9
|
module ReactOnRails
|
|
10
10
|
module Utils
|
|
11
|
+
TRUNCATION_FILLER = "\n... TRUNCATED ...\n"
|
|
12
|
+
|
|
11
13
|
# https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901
|
|
12
14
|
# return object if truthy, else return nil
|
|
13
15
|
def self.truthy_presence(obj)
|
|
@@ -76,8 +78,10 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
76
78
|
begin
|
|
77
79
|
bundle_js_file_path(bundle_name)
|
|
78
80
|
rescue Webpacker::Manifest::MissingEntryError
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
File.expand_path(
|
|
82
|
+
File.join(ReactOnRails::WebpackerUtils.webpacker_public_output_path,
|
|
83
|
+
bundle_name)
|
|
84
|
+
)
|
|
81
85
|
end
|
|
82
86
|
else
|
|
83
87
|
bundle_js_file_path(bundle_name)
|
|
@@ -90,7 +94,8 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
90
94
|
else
|
|
91
95
|
# Default to the non-hashed name in the specified output directory, which, for legacy
|
|
92
96
|
# React on Rails, this is the output directory picked up by the asset pipeline.
|
|
93
|
-
|
|
97
|
+
# For Webpacker, this is the public output path defined in the webpacker.yml file.
|
|
98
|
+
File.join(generated_assets_full_path, bundle_name)
|
|
94
99
|
end
|
|
95
100
|
end
|
|
96
101
|
|
|
@@ -114,7 +119,7 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
114
119
|
|
|
115
120
|
module Required
|
|
116
121
|
def required(arg_name)
|
|
117
|
-
raise
|
|
122
|
+
raise ReactOnRails::Error, "#{arg_name} is required"
|
|
118
123
|
end
|
|
119
124
|
end
|
|
120
125
|
|
|
@@ -130,12 +135,39 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
|
130
135
|
end
|
|
131
136
|
end
|
|
132
137
|
|
|
133
|
-
def self.
|
|
138
|
+
def self.generated_assets_full_path
|
|
134
139
|
if ReactOnRails::WebpackerUtils.using_webpacker?
|
|
135
140
|
ReactOnRails::WebpackerUtils.webpacker_public_output_path
|
|
136
141
|
else
|
|
137
|
-
ReactOnRails.configuration.generated_assets_dir
|
|
142
|
+
File.expand_path(ReactOnRails.configuration.generated_assets_dir)
|
|
138
143
|
end
|
|
139
144
|
end
|
|
145
|
+
|
|
146
|
+
def self.gem_available?(name)
|
|
147
|
+
Gem::Specification.find_by_name(name).present?
|
|
148
|
+
rescue Gem::LoadError
|
|
149
|
+
false
|
|
150
|
+
rescue StandardError
|
|
151
|
+
Gem.available?(name).present?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.react_on_rails_pro?
|
|
155
|
+
@react_on_rails_pro ||= gem_available?("react_on_rails_pro")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def self.smart_trim(str, max_length = 1000)
|
|
159
|
+
# From https://stackoverflow.com/a/831583/1009332
|
|
160
|
+
str = str.to_s
|
|
161
|
+
return str unless str.present? && max_length >= 1
|
|
162
|
+
return str if str.length <= max_length
|
|
163
|
+
|
|
164
|
+
return str[0, 1] + TRUNCATION_FILLER if max_length == 1
|
|
165
|
+
|
|
166
|
+
midpoint = (str.length / 2.0).ceil;
|
|
167
|
+
to_remove = str.length - max_length;
|
|
168
|
+
lstrip = (to_remove / 2.0).ceil;
|
|
169
|
+
rstrip = to_remove - lstrip;
|
|
170
|
+
str[0..(midpoint - lstrip - 1)] + TRUNCATION_FILLER + str[(midpoint + rstrip)..-1]
|
|
171
|
+
end
|
|
140
172
|
end
|
|
141
173
|
end
|
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "version"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
module ReactOnRails
|
|
6
|
+
class VersionSyntaxConverter
|
|
7
|
+
def rubygem_to_npm(rubygem_version = ReactOnRails::VERSION)
|
|
8
|
+
regex_match = rubygem_version.match(/(\d+\.\d+\.\d+)[.\-]?(.+)?/)
|
|
9
|
+
return "#{regex_match[1]}-#{regex_match[2]}" if regex_match[2]
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
regex_match[1].to_s
|
|
12
|
+
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
def npm_to_rubygem(npm_version)
|
|
15
|
+
match = npm_version
|
|
16
|
+
.tr("-", ".")
|
|
17
|
+
.strip
|
|
18
|
+
.match(/(\d.*)/)
|
|
19
|
+
match.present? ? match[0] : nil
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
22
|
end
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
module ReactOnRails
|
|
2
2
|
module WebpackerUtils
|
|
3
3
|
def self.using_webpacker?
|
|
4
|
-
|
|
4
|
+
ReactOnRails::Utils.gem_available?("webpacker")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def self.bundle_js_file_path_from_webpacker(bundle_name)
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
# Note Webpacker 3.4.3 manifest lookup is inside of the public_output_path
|
|
9
|
+
# [2] (pry) ReactOnRails::WebpackerUtils: 0> Webpacker.manifest.lookup("app-bundle.js")
|
|
10
|
+
# "/webpack/development/app-bundle-c1d2b6ab73dffa7d9c0e.js"
|
|
11
|
+
# Next line will throw if the file or manifest does not exist
|
|
12
|
+
hashed_bundle_name = Webpacker.manifest.lookup!(bundle_name)
|
|
13
|
+
|
|
10
14
|
if Webpacker.dev_server.running?
|
|
11
|
-
|
|
12
|
-
result
|
|
15
|
+
"#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
|
|
13
16
|
else
|
|
14
|
-
|
|
15
|
-
Rails.root.join(File.join("public", hashed_bundle_name)).to_s
|
|
17
|
+
File.expand_path(File.join("public", hashed_bundle_name)).to_s
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
|
|
@@ -21,7 +23,8 @@ module ReactOnRails
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def self.webpacker_public_output_path
|
|
24
|
-
Webpacker
|
|
26
|
+
# Webpacker has the full absolute path of webpacker output files in a Pathname
|
|
27
|
+
Webpacker.config.public_output_path.to_s
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def self.manifest_exists?
|
data/lib/react_on_rails.rb
CHANGED
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
require "rails"
|
|
4
4
|
|
|
5
5
|
require "react_on_rails/error"
|
|
6
|
-
require "react_on_rails/
|
|
6
|
+
require "react_on_rails/prerender_error"
|
|
7
|
+
require "react_on_rails/json_parse_error"
|
|
8
|
+
require "react_on_rails/helper"
|
|
7
9
|
require "react_on_rails/controller"
|
|
8
10
|
require "react_on_rails/version"
|
|
9
11
|
require "react_on_rails/version_checker"
|
|
10
12
|
require "react_on_rails/configuration"
|
|
11
13
|
require "react_on_rails/server_rendering_pool"
|
|
12
14
|
require "react_on_rails/engine"
|
|
13
|
-
require "react_on_rails/react_component/
|
|
15
|
+
require "react_on_rails/react_component/render_options"
|
|
14
16
|
require "react_on_rails/version_syntax_converter"
|
|
15
17
|
require "react_on_rails/test_helper"
|
|
16
18
|
require "react_on_rails/git_utils"
|
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-on-rails",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "react-on-rails JavaScript for react_on_rails Ruby gem",
|
|
5
5
|
"main": "node_package/lib/ReactOnRails.js",
|
|
6
6
|
"directories": {
|
|
@@ -53,7 +53,8 @@
|
|
|
53
53
|
"scripts": {
|
|
54
54
|
"test": "babel-tape-runner -r node_package/tests/helpers/test_helper.js node_package/tests/*.js | tap-spec",
|
|
55
55
|
"clean": "rm -rf node_package/lib",
|
|
56
|
-
"
|
|
56
|
+
"prepare": "yarn run build",
|
|
57
|
+
"prepublish": "npm run prepare",
|
|
57
58
|
"babel": "babel --out-dir node_package/lib node_package/src",
|
|
58
59
|
"build": "yarn run clean && yarn run babel",
|
|
59
60
|
"build-watch": "babel --watch --out-dir node_package/lib node_package/src",
|
data/rakelib/release.rake
CHANGED
|
@@ -41,7 +41,7 @@ task :release, %i[gem_version dry_run tools_install] do |_t, args|
|
|
|
41
41
|
npm_version = if gem_version.strip.empty?
|
|
42
42
|
""
|
|
43
43
|
else
|
|
44
|
-
VersionSyntaxConverter.new.rubygem_to_npm(gem_version)
|
|
44
|
+
ReactOnRails::VersionSyntaxConverter.new.rubygem_to_npm(gem_version)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Having the examples prevents publishing
|
data/react_on_rails.gemspec
CHANGED
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
|
29
29
|
s.add_dependency "connection_pool"
|
|
30
30
|
s.add_dependency "execjs", "~> 2.5"
|
|
31
31
|
s.add_dependency "rails", ">= 3.2"
|
|
32
|
-
s.add_dependency "rainbow", "~>
|
|
32
|
+
s.add_dependency "rainbow", "~> 3.0"
|
|
33
33
|
|
|
34
34
|
s.add_development_dependency "awesome_print"
|
|
35
35
|
s.add_development_dependency "bundler", "~> 1"
|
|
@@ -48,7 +48,7 @@ Gem::Specification.new do |s|
|
|
|
48
48
|
|
|
49
49
|
s.add_development_dependency "rake", "~> 10.0"
|
|
50
50
|
s.add_development_dependency "rspec"
|
|
51
|
-
s.add_development_dependency "rubocop", "0.
|
|
51
|
+
s.add_development_dependency "rubocop", "~> 0.58.1"
|
|
52
52
|
|
|
53
53
|
s.post_install_message = '
|
|
54
54
|
--------------------------------------------------------------------------------
|