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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +2 -2
  4. data/CHANGELOG.md +80 -3
  5. data/CONTRIBUTING.md +7 -8
  6. data/{docs/LICENSE.md → LICENSE.md} +1 -1
  7. data/PROJECTS.md +7 -1
  8. data/README.md +175 -637
  9. data/Rakefile +4 -1
  10. data/SUMMARY.md +39 -26
  11. data/docs/additional-reading/convert-rails-5-api-only-app.md +19 -0
  12. data/docs/additional-reading/credits.md +10 -0
  13. data/docs/additional-reading/rails-assets-relative-paths.md +2 -2
  14. data/docs/additional-reading/rails-engine-integration.md +7 -0
  15. data/docs/additional-reading/server-rendering-tips.md +2 -4
  16. data/docs/additional-reading/webpack.md +2 -2
  17. data/docs/api/javascript-api.md +21 -1
  18. data/docs/api/redux-store-api.md +100 -0
  19. data/docs/api/view-helpers-api.md +130 -0
  20. data/docs/articles.md +20 -0
  21. data/docs/basics/client-vs-server-rendering.md +17 -0
  22. data/docs/basics/configuration.md +39 -5
  23. data/docs/basics/deployment.md +6 -0
  24. data/docs/basics/{generator.md → generator-details.md} +4 -7
  25. data/docs/basics/generator-functions-and-railscontext.md +157 -0
  26. data/docs/basics/how-react-on-rails-works.md +40 -0
  27. data/docs/basics/installation-into-an-existing-rails-app.md +64 -0
  28. data/docs/basics/react-server-rendering.md +27 -0
  29. data/docs/{additional-reading → basics}/recommended-project-structure.md +26 -4
  30. data/docs/{additional-reading → basics}/rspec-configuration.md +12 -6
  31. data/docs/basics/upgrading-react-on-rails.md +3 -3
  32. data/docs/basics/webpack-configuration.md +29 -0
  33. data/docs/misc/doctrine.md +1 -1
  34. data/docs/{additional-reading → misc-pending}/code-splitting.md +8 -2
  35. data/docs/{basics/installation-overview.md → misc-pending/manual-installation-overview.md} +3 -8
  36. data/docs/{additional-reading → misc-pending}/rails-assets.md +3 -1
  37. data/docs/testimonials.md +11 -0
  38. data/docs/tutorial.md +4 -4
  39. data/lib/generators/USAGE +1 -1
  40. data/lib/react_on_rails/configuration.rb +139 -97
  41. data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +104 -79
  42. data/lib/react_on_rails/json_parse_error.rb +26 -0
  43. data/lib/react_on_rails/prerender_error.rb +48 -6
  44. data/lib/react_on_rails/react_component/render_options.rb +94 -0
  45. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +58 -50
  46. data/lib/react_on_rails/server_rendering_pool.rb +4 -16
  47. data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +10 -6
  48. data/lib/react_on_rails/test_helper.rb +8 -7
  49. data/lib/react_on_rails/utils.rb +38 -6
  50. data/lib/react_on_rails/version.rb +1 -1
  51. data/lib/react_on_rails/version_syntax_converter.rb +14 -12
  52. data/lib/react_on_rails/webpacker_utils.rb +11 -8
  53. data/lib/react_on_rails.rb +4 -2
  54. data/package.json +3 -2
  55. data/rakelib/release.rake +1 -1
  56. data/react_on_rails.gemspec +2 -2
  57. metadata +32 -21
  58. data/docs/additional-reading/caching-and-performance.md +0 -4
  59. data/docs/additional-reading/node-server-rendering.md +0 -5
  60. data/docs/api/ruby-api.md +0 -8
  61. 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 < StandardError
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
- js_code was:
24
- #{js_code}
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
- def self.reset_pool
9
- options = {
10
- size: ReactOnRails.configuration.server_renderer_pool_size,
11
- timeout: ReactOnRails.configuration.server_renderer_timeout
12
- }
13
- @js_context_pool = ConnectionPool.new(options) { create_js_context }
14
- end
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
- def self.reset_pool_if_server_bundle_was_modified
17
- return unless ReactOnRails.configuration.development_mode
17
+ def reset_pool_if_server_bundle_was_modified
18
+ return unless ReactOnRails.configuration.development_mode
18
19
 
19
- file_mtime = File.mtime(ReactOnRails::Utils.server_bundle_js_file_path)
20
- @server_bundle_timestamp ||= file_mtime
21
- return if @server_bundle_timestamp == file_mtime
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
- @server_bundle_timestamp = file_mtime
24
+ @server_bundle_timestamp = file_mtime
24
25
 
25
- ReactOnRails::ServerRenderingPool.reset_pool
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
- json_string = eval_js(js_code)
44
- result = JSON.parse(json_string)
45
-
46
- if ReactOnRails.configuration.logging_on_server
47
- console_script = result["consoleReplayScript"]
48
- console_script_lines = console_script.split("\n")
49
- console_script_lines = console_script_lines[2..-2]
50
- re = /console\.(log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
51
- if console_script_lines
52
- console_script_lines.each do |line|
53
- match = re.match(line)
54
- Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
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 execJS. See "\
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 :server_render_js_with_console_logging, :reset_pool_if_server_bundle_was_modified,
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 gem_available?(name)
30
- Gem::Specification.find_by_name(name)
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, :generated_assets_dir
16
+ attr_reader :source_path, :generated_assets_full_path
17
17
 
18
18
  def initialize(
19
- generated_assets_dir: required("generated_assets_dir"),
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
- @generated_assets_dir = generated_assets_dir
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::Utils.bundle_js_file_path(bundle_name)
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(generated_assets_dir)).to_ary
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
- "#{generated_assets_dir}"
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 generated_assets_dir are passed into the default webpack_assets_status_checker if you
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
- generated_assets_dir: nil,
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
- generated_assets_dir ||= ReactOnRails::Utils.generated_assets_dir
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
- generated_assets_dir: generated_assets_dir,
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 #{webpack_assets_status_checker.generated_assets_dir} for "\
74
- "outdated/missing bundles"
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
@@ -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
- Rails.root.join(File.join(Webpacker.config.public_output_path,
80
- bundle_name)).to_s
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
- File.join(ReactOnRails.configuration.generated_assets_dir, bundle_name)
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 ReactOnRailsPro::Error, "#{arg_name} is required"
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.generated_assets_dir
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "11.0.0".freeze
4
+ VERSION = "11.1.0".freeze
5
5
  end
@@ -2,19 +2,21 @@
2
2
 
3
3
  require_relative "version"
4
4
 
5
- class VersionSyntaxConverter
6
- def rubygem_to_npm(rubygem_version = ReactOnRails::VERSION)
7
- regex_match = rubygem_version.match(/(\d+\.\d+\.\d+)[.\-]?(.+)?/)
8
- return "#{regex_match[1]}-#{regex_match[2]}" if regex_match[2]
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
- regex_match[1].to_s
11
- end
11
+ regex_match[1].to_s
12
+ end
12
13
 
13
- def npm_to_rubygem(npm_version)
14
- match = npm_version
15
- .tr("-", ".")
16
- .strip
17
- .match(/(\d.*)/)
18
- match.present? ? match[0] : nil
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
- ActionController::Base.helpers.respond_to?(:asset_pack_path)
4
+ ReactOnRails::Utils.gem_available?("webpacker")
5
5
  end
6
6
 
7
7
  def self.bundle_js_file_path_from_webpacker(bundle_name)
8
- possible_result = Webpacker.manifest.lookup(bundle_name)
9
- hashed_bundle_name = possible_result.nil? ? Webpacker.manifest.lookup!(bundle_name) : possible_result
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
- result = "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
12
- result
15
+ "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
13
16
  else
14
- # Next line will throw if the file or manifest does not exist
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.config.public_output_path
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?
@@ -3,14 +3,16 @@
3
3
  require "rails"
4
4
 
5
5
  require "react_on_rails/error"
6
- require "react_on_rails/react_on_rails_helper"
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/options"
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.0.0",
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
- "prepublish": "yarn run build",
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
@@ -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", "~> 2.2"
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.55.0"
51
+ s.add_development_dependency "rubocop", "~> 0.58.1"
52
52
 
53
53
  s.post_install_message = '
54
54
  --------------------------------------------------------------------------------