react_on_rails 10.1.4 → 11.0.0.beta.1
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/.rubocop.yml +1 -1
- data/CHANGELOG.md +14 -2
- data/CONTRIBUTING.md +0 -7
- data/Gemfile +8 -13
- data/README.md +5 -4
- data/app/helpers/react_on_rails_helper.rb +1 -534
- data/docs/additional-reading/caching-and-performance.md +2 -29
- data/docs/additional-reading/server-rendering-tips.md +4 -4
- data/docs/basics/configuration.md +23 -9
- data/docs/basics/i18n.md +4 -0
- data/lib/generators/react_on_rails/base_generator.rb +2 -3
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
- data/lib/generators/react_on_rails/install_generator.rb +1 -1
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +1 -1
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +2 -1
- data/lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb +2 -2
- data/lib/react_on_rails.rb +3 -2
- data/lib/react_on_rails/configuration.rb +27 -8
- data/lib/react_on_rails/error.rb +4 -0
- data/lib/react_on_rails/prerender_error.rb +1 -1
- data/lib/react_on_rails/react_on_rails_helper.rb +546 -0
- data/lib/react_on_rails/server_rendering_pool.rb +21 -11
- data/lib/react_on_rails/server_rendering_pool/{exec.rb → ruby_embedded_java_script.rb} +35 -38
- data/lib/react_on_rails/test_helper.rb +1 -1
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +2 -2
- data/lib/react_on_rails/utils.rb +12 -73
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +4 -2
- data/lib/react_on_rails/webpacker_utils.rb +42 -0
- data/package.json +1 -1
- data/rakelib/example_type.rb +1 -1
- data/rakelib/examples.rake +1 -1
- data/rakelib/release.rake +0 -5
- data/rakelib/task_helpers.rb +1 -1
- data/react_on_rails.gemspec +12 -9
- metadata +30 -13
- data/lib/react_on_rails/server_rendering_pool/node.rb +0 -81
- data/lib/react_on_rails/test_helper/node_process_launcher.rb +0 -14
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "connection_pool"
|
4
|
-
require_relative "server_rendering_pool/
|
5
|
-
require_relative "server_rendering_pool/node"
|
4
|
+
require_relative "server_rendering_pool/ruby_embedded_java_script"
|
6
5
|
|
7
6
|
# Based on the react-rails gem.
|
8
7
|
# None of these methods should be called directly.
|
@@ -10,19 +9,30 @@ require_relative "server_rendering_pool/node"
|
|
10
9
|
module ReactOnRails
|
11
10
|
module ServerRenderingPool
|
12
11
|
class << self
|
12
|
+
def react_on_rails_pro?
|
13
|
+
@react_on_rails_pro ||= gem_available?("react_on_rails_pro")
|
14
|
+
end
|
15
|
+
|
13
16
|
def pool
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
@pool ||= if react_on_rails_pro?
|
18
|
+
ReactOnRailsPro::ServerRenderingPool::ProRendering
|
19
|
+
else
|
20
|
+
ReactOnRails::ServerRenderingPool::RubyEmbeddedJavaScript
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
delegate :server_render_js_with_console_logging, :reset_pool_if_server_bundle_was_modified,
|
25
|
+
:reset_pool, to: :pool
|
26
|
+
|
27
|
+
private
|
28
|
+
|
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)
|
24
35
|
end
|
25
|
-
# rubocop:enable Style/MethodMissing
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
@@ -4,8 +4,7 @@ require "open-uri"
|
|
4
4
|
|
5
5
|
module ReactOnRails
|
6
6
|
module ServerRenderingPool
|
7
|
-
|
8
|
-
class Exec
|
7
|
+
class RubyEmbeddedJavaScript
|
9
8
|
def self.reset_pool
|
10
9
|
options = {
|
11
10
|
size: ReactOnRails.configuration.server_renderer_pool_size,
|
@@ -17,18 +16,11 @@ module ReactOnRails
|
|
17
16
|
def self.reset_pool_if_server_bundle_was_modified
|
18
17
|
return unless ReactOnRails.configuration.development_mode
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
if
|
23
|
-
|
24
|
-
|
25
|
-
else
|
26
|
-
# we're not hashing the server name and we can use the mtime
|
27
|
-
file_mtime = File.mtime(server_bundle_js_file_path)
|
28
|
-
@server_bundle_timestamp ||= file_mtime
|
29
|
-
return if @server_bundle_timestamp == file_mtime
|
30
|
-
@server_bundle_timestamp = file_mtime
|
31
|
-
end
|
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
|
22
|
+
|
23
|
+
@server_bundle_timestamp = file_mtime
|
32
24
|
|
33
25
|
ReactOnRails::ServerRenderingPool.reset_pool
|
34
26
|
end
|
@@ -42,9 +34,10 @@ module ReactOnRails
|
|
42
34
|
# js_code MUST RETURN json stringify Object
|
43
35
|
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
44
36
|
def self.server_render_js_with_console_logging(js_code)
|
45
|
-
if
|
37
|
+
if ReactOnRails.configuration.trace
|
46
38
|
@file_index ||= 1
|
47
|
-
|
39
|
+
trace_js_code_used("Evaluating code to server render.", js_code,
|
40
|
+
"tmp/server-generated-#{@file_index % 10}.js")
|
48
41
|
@file_index += 1
|
49
42
|
end
|
50
43
|
json_string = eval_js(js_code)
|
@@ -68,18 +61,21 @@ module ReactOnRails
|
|
68
61
|
class << self
|
69
62
|
private
|
70
63
|
|
71
|
-
def
|
72
|
-
return unless
|
64
|
+
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
65
|
+
return unless ReactOnRails.configuration.trace || force
|
73
66
|
# Set to anything to print generated code.
|
74
|
-
puts "Z" * 80
|
75
|
-
puts "react_renderer.rb: 92"
|
76
|
-
puts "wrote file #{file_name}"
|
77
67
|
File.write(file_name, js_code)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
68
|
+
msg = <<-MSG.strip_heredoc
|
69
|
+
#{'Z' * 80}
|
70
|
+
[react_on_rails] #{msg}
|
71
|
+
JavaScript code used: #{file_name}
|
72
|
+
#{'Z' * 80}
|
73
|
+
MSG
|
74
|
+
if force
|
75
|
+
Rails.logger.error(msg)
|
76
|
+
else
|
77
|
+
Rails.logger.info(msg)
|
78
|
+
end
|
83
79
|
end
|
84
80
|
|
85
81
|
def eval_js(js_code)
|
@@ -95,34 +91,35 @@ module ReactOnRails
|
|
95
91
|
|
96
92
|
server_js_file = ReactOnRails::Utils.server_bundle_js_file_path
|
97
93
|
|
98
|
-
# bundle_js_code = File.read(server_js_file)
|
99
94
|
begin
|
100
|
-
bundle_js_code =
|
95
|
+
bundle_js_code = File.read(server_js_file)
|
101
96
|
rescue StandardError => e
|
102
97
|
msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
|
103
98
|
"read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
|
104
99
|
"avoid this warning.\nError is: #{e}"
|
105
|
-
raise msg
|
100
|
+
raise ReactOnRails::Error, msg
|
106
101
|
end
|
107
102
|
# rubocop:disable Layout/IndentHeredoc
|
108
103
|
base_js_code = <<-JS
|
109
104
|
#{console_polyfill}
|
110
|
-
|
111
|
-
|
105
|
+
#{execjs_timer_polyfills}
|
106
|
+
#{bundle_js_code};
|
112
107
|
JS
|
113
108
|
# rubocop:enable Layout/IndentHeredoc
|
114
109
|
file_name = "tmp/base_js_code.js"
|
115
110
|
begin
|
116
|
-
|
111
|
+
if ReactOnRails.configuration.trace
|
112
|
+
Rails.logger.info { "[react_on_rails] Created JavaScript context with file #{server_js_file}" }
|
113
|
+
end
|
117
114
|
ExecJS.compile(base_js_code)
|
118
115
|
rescue StandardError => e
|
119
116
|
msg = "ERROR when compiling base_js_code! "\
|
120
117
|
"See file #{file_name} to "\
|
121
118
|
"correlate line numbers of error. Error is\n\n#{e.message}"\
|
122
119
|
"\n\n#{e.backtrace.join("\n")}"
|
123
|
-
puts msg
|
124
120
|
Rails.logger.error(msg)
|
125
|
-
|
121
|
+
trace_js_code_used("Error when compiling JavaScript code for the context.", base_js_code,
|
122
|
+
file_name, force: true)
|
126
123
|
raise e
|
127
124
|
end
|
128
125
|
end
|
@@ -158,10 +155,10 @@ function clearTimeout() {
|
|
158
155
|
end
|
159
156
|
|
160
157
|
def undefined_for_exec_js_logging(function_name)
|
161
|
-
if
|
162
|
-
"console.error('#{function_name} is not defined for execJS. See "\
|
163
|
-
|
164
|
-
|
158
|
+
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"\
|
161
|
+
" console.error(getStackTrace().join('\\n'));"
|
165
162
|
else
|
166
163
|
""
|
167
164
|
end
|
@@ -57,7 +57,7 @@ module ReactOnRails
|
|
57
57
|
source_path: nil,
|
58
58
|
generated_assets_dir: nil,
|
59
59
|
webpack_generated_files: nil)
|
60
|
-
ReactOnRails::
|
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_dir ||= ReactOnRails::Utils.generated_assets_dir
|
@@ -26,8 +26,8 @@ module ReactOnRails
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def stale_generated_webpack_files
|
29
|
-
manifest_needed = ReactOnRails::
|
30
|
-
!ReactOnRails::
|
29
|
+
manifest_needed = ReactOnRails::WebpackerUtils.using_webpacker? &&
|
30
|
+
!ReactOnRails::WebpackerUtils.manifest_exists?
|
31
31
|
|
32
32
|
return ["manifest.json"] if manifest_needed
|
33
33
|
|
data/lib/react_on_rails/utils.rb
CHANGED
@@ -8,33 +8,6 @@ require "active_support/core_ext/string"
|
|
8
8
|
|
9
9
|
module ReactOnRails
|
10
10
|
module Utils
|
11
|
-
###########################################################
|
12
|
-
# PUBLIC API
|
13
|
-
###########################################################
|
14
|
-
|
15
|
-
# Returns the hashed file name when using webpacker. Useful for creating cache keys.
|
16
|
-
def self.bundle_file_name(bundle_name)
|
17
|
-
raise "Only call bundle_file_name if using webpacker" unless using_webpacker?
|
18
|
-
full_path = bundle_js_file_path_from_webpacker(bundle_name)
|
19
|
-
pathname = Pathname.new(full_path)
|
20
|
-
pathname.basename.to_s
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns the hashed file name of the server bundle when using webpacker.
|
24
|
-
# Nececessary fragment-caching keys.
|
25
|
-
def self.server_bundle_file_name
|
26
|
-
return @server_bundle_hash if @server_bundle_hash && !Rails.env.development?
|
27
|
-
|
28
|
-
@server_bundle_hash = begin
|
29
|
-
server_bundle_name = ReactOnRails.configuration.server_bundle_js_file
|
30
|
-
bundle_file_name(server_bundle_name)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
###########################################################
|
35
|
-
# PRIVATE API -- Subject to change
|
36
|
-
###########################################################
|
37
|
-
|
38
11
|
# https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901
|
39
12
|
# return object if truthy, else return nil
|
40
13
|
def self.truthy_presence(obj)
|
@@ -99,7 +72,7 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
99
72
|
return @server_bundle_path if @server_bundle_path && !Rails.env.development?
|
100
73
|
|
101
74
|
bundle_name = ReactOnRails.configuration.server_bundle_js_file
|
102
|
-
@server_bundle_path = if using_webpacker?
|
75
|
+
@server_bundle_path = if ReactOnRails::WebpackerUtils.using_webpacker?
|
103
76
|
begin
|
104
77
|
bundle_js_file_path(bundle_name)
|
105
78
|
rescue Webpacker::Manifest::MissingEntryError
|
@@ -112,8 +85,8 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
112
85
|
end
|
113
86
|
|
114
87
|
def self.bundle_js_file_path(bundle_name)
|
115
|
-
if using_webpacker? && bundle_name != "manifest.json"
|
116
|
-
bundle_js_file_path_from_webpacker(bundle_name)
|
88
|
+
if ReactOnRails::WebpackerUtils.using_webpacker? && bundle_name != "manifest.json"
|
89
|
+
ReactOnRails::WebpackerUtils.bundle_js_file_path_from_webpacker(bundle_name)
|
117
90
|
else
|
118
91
|
# Default to the non-hashed name in the specified output directory, which, for legacy
|
119
92
|
# React on Rails, this is the output directory picked up by the asset pipeline.
|
@@ -141,7 +114,7 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
141
114
|
|
142
115
|
module Required
|
143
116
|
def required(arg_name)
|
144
|
-
raise
|
117
|
+
raise ReactOnRailsPro::Error, "#{arg_name} is required"
|
145
118
|
end
|
146
119
|
end
|
147
120
|
|
@@ -150,53 +123,19 @@ exitstatus: #{status.exitstatus}#{stdout_msg}#{stderr_msg}
|
|
150
123
|
end
|
151
124
|
|
152
125
|
def self.source_path
|
153
|
-
|
126
|
+
if ReactOnRails::WebpackerUtils.using_webpacker?
|
127
|
+
ReactOnRails::WebpackerUtils.webpacker_source_path
|
128
|
+
else
|
129
|
+
ReactOnRails.configuration.node_modules_location
|
130
|
+
end
|
154
131
|
end
|
155
132
|
|
156
133
|
def self.generated_assets_dir
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
###########################################################################
|
161
|
-
# WEBPACKER WRAPPERS
|
162
|
-
###########################################################################
|
163
|
-
def self.using_webpacker?
|
164
|
-
ActionController::Base.helpers.respond_to?(:asset_pack_path)
|
165
|
-
end
|
166
|
-
|
167
|
-
def self.bundle_js_file_path_from_webpacker(bundle_name)
|
168
|
-
possible_result = Webpacker.manifest.lookup(bundle_name)
|
169
|
-
hashed_bundle_name = possible_result.nil? ? Webpacker.manifest.lookup!(bundle_name) : possible_result
|
170
|
-
if Webpacker.dev_server.running?
|
171
|
-
result = "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
|
172
|
-
result
|
134
|
+
if ReactOnRails::WebpackerUtils.using_webpacker?
|
135
|
+
ReactOnRails::WebpackerUtils.webpacker_public_output_path
|
173
136
|
else
|
174
|
-
|
175
|
-
Rails.root.join(File.join("public", hashed_bundle_name)).to_s
|
137
|
+
ReactOnRails.configuration.generated_assets_dir
|
176
138
|
end
|
177
139
|
end
|
178
|
-
|
179
|
-
def self.webpacker_source_path
|
180
|
-
Webpacker.config.source_path
|
181
|
-
end
|
182
|
-
|
183
|
-
def self.webpacker_public_output_path
|
184
|
-
Webpacker.config.public_output_path
|
185
|
-
end
|
186
|
-
|
187
|
-
def self.manifest_exists?
|
188
|
-
Webpacker.config.public_manifest_path.exist?
|
189
|
-
end
|
190
|
-
|
191
|
-
def self.check_manifest_not_cached
|
192
|
-
return unless using_webpacker? && Webpacker.config.cache_manifest?
|
193
|
-
msg = <<-MSG.strip_heredoc
|
194
|
-
ERROR: you have enabled cache_manifest in the #{Rails.env} env when using the
|
195
|
-
ReactOnRails::TestHelper.configure_rspec_to_compile_assets helper
|
196
|
-
To fix this: edit your config/webpacker.yml file and set cache_manifest to false for test.
|
197
|
-
MSG
|
198
|
-
puts wrap_message(msg)
|
199
|
-
exit!
|
200
|
-
end
|
201
140
|
end
|
202
141
|
end
|
@@ -71,7 +71,7 @@ module ReactOnRails
|
|
71
71
|
parsed_package_contents["dependencies"].key?("react-on-rails")
|
72
72
|
parsed_package_contents["dependencies"]["react-on-rails"]
|
73
73
|
else
|
74
|
-
raise "
|
74
|
+
raise ReactOnRails::Error, "No 'react-on-rails' entry in package.json dependencies"
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -82,7 +82,9 @@ module ReactOnRails
|
|
82
82
|
def major_minor_patch
|
83
83
|
return if relative_path?
|
84
84
|
match = raw.match(MAJOR_MINOR_PATCH_VERSION_REGEX)
|
85
|
-
|
85
|
+
unless match
|
86
|
+
raise ReactOnRails::Error, "Cannot parse version number '#{raw}' (wildcard versions are not supported)"
|
87
|
+
end
|
86
88
|
[match[1], match[2], match[3]]
|
87
89
|
end
|
88
90
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ReactOnRails
|
2
|
+
module WebpackerUtils
|
3
|
+
def self.using_webpacker?
|
4
|
+
ActionController::Base.helpers.respond_to?(:asset_pack_path)
|
5
|
+
end
|
6
|
+
|
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
|
10
|
+
if Webpacker.dev_server.running?
|
11
|
+
result = "#{Webpacker.dev_server.protocol}://#{Webpacker.dev_server.host_with_port}#{hashed_bundle_name}"
|
12
|
+
result
|
13
|
+
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
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.webpacker_source_path
|
20
|
+
Webpacker.config.source_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.webpacker_public_output_path
|
24
|
+
Webpacker.config.public_output_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.manifest_exists?
|
28
|
+
Webpacker.config.public_manifest_path.exist?
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.check_manifest_not_cached
|
32
|
+
return unless using_webpacker? && Webpacker.config.cache_manifest?
|
33
|
+
msg = <<-MSG.strip_heredoc
|
34
|
+
ERROR: you have enabled cache_manifest in the #{Rails.env} env when using the
|
35
|
+
ReactOnRails::TestHelper.configure_rspec_to_compile_assets helper
|
36
|
+
To fix this: edit your config/webpacker.yml file and set cache_manifest to false for test.
|
37
|
+
MSG
|
38
|
+
puts wrap_message(msg)
|
39
|
+
exit!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/package.json
CHANGED
data/rakelib/example_type.rb
CHANGED
data/rakelib/examples.rake
CHANGED
@@ -12,7 +12,7 @@ require_relative "task_helpers"
|
|
12
12
|
namespace :examples do # rubocop:disable Metrics/BlockLength
|
13
13
|
include ReactOnRails::TaskHelpers
|
14
14
|
# Loads data from examples_config.yml and instantiates corresponding ExampleType objects
|
15
|
-
examples_config_file = File.expand_path("
|
15
|
+
examples_config_file = File.expand_path("examples_config.yml", __dir__)
|
16
16
|
examples_config = symbolize_keys(YAML.safe_load(File.read(examples_config_file)))
|
17
17
|
examples_config[:example_type_data].each { |example_type_data| ExampleType.new(symbolize_keys(example_type_data)) }
|
18
18
|
|
data/rakelib/release.rake
CHANGED
@@ -4,9 +4,6 @@ require_relative "task_helpers"
|
|
4
4
|
require_relative File.join(gem_root, "lib", "react_on_rails", "version_syntax_converter")
|
5
5
|
require_relative File.join(gem_root, "lib", "react_on_rails", "git_utils")
|
6
6
|
require_relative File.join(gem_root, "lib", "react_on_rails", "utils")
|
7
|
-
|
8
|
-
# rubocop:disable Lint/UnneededDisable
|
9
|
-
# rubocop:disable Layout/EmptyLinesAroundArguments
|
10
7
|
desc("Releases both the gem and node package using the given version.
|
11
8
|
|
12
9
|
IMPORTANT: the gem version must be in valid rubygem format (no dashes).
|
@@ -22,8 +19,6 @@ which are installed via `bundle install` and `yarn`
|
|
22
19
|
2nd argument: Perform a dry run by passing 'true' as a second argument.
|
23
20
|
|
24
21
|
Example: `rake release[2.1.0,false]`")
|
25
|
-
# rubocop:enable Layout/EmptyLinesAroundArguments
|
26
|
-
# rubocop:enable Lint/UnneededDisable
|
27
22
|
|
28
23
|
# rubocop:disable Metrics/BlockLength
|
29
24
|
task :release, %i[gem_version dry_run tools_install] do |_t, args|
|