react_on_rails 5.2.0 → 6.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/.gitignore +2 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +31 -0
- data/PROJECTS.md +11 -2
- data/README.md +33 -203
- data/app/helpers/react_on_rails_helper.rb +32 -49
- data/docs/additional-reading/heroku-deployment.md +2 -35
- data/docs/additional-reading/node-server-rendering.md +30 -0
- data/docs/additional-reading/rails-assets.md +19 -0
- data/docs/additional-reading/rspec-configuration.md +38 -4
- data/docs/additional-reading/webpack-dev-server.md +16 -0
- data/docs/additional-reading/webpack.md +0 -10
- data/docs/api/javascript-api.md +37 -0
- data/docs/api/ruby-api-hot-reload-view-helpers.md +42 -0
- data/docs/api/ruby-api.md +3 -0
- data/docs/basics/generator.md +49 -0
- data/docs/{additional-reading → basics}/installation-overview.md +0 -0
- data/docs/basics/migrating-from-react-rails.md +17 -0
- data/docs/contributor-info/contributing.md +11 -0
- data/docs/{coding-style → contributor-info}/linters.md +0 -0
- data/lib/generators/USAGE +3 -95
- data/lib/generators/react_on_rails/base_generator.rb +10 -43
- data/lib/generators/react_on_rails/dev_tests_generator.rb +17 -1
- data/lib/generators/react_on_rails/install_generator.rb +0 -6
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +3 -17
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +4 -21
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +2 -2
- data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +3 -4
- data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt +1 -11
- data/lib/generators/react_on_rails/templates/base/base/client/node/package.json +10 -0
- data/lib/generators/react_on_rails/templates/base/base/client/node/server.js +82 -0
- data/lib/generators/react_on_rails/templates/base/base/client/package.json.tt +3 -20
- data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +58 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +60 -26
- data/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt +1 -4
- data/lib/generators/react_on_rails/templates/base/base/lib/tasks/load_test.rake +8 -0
- data/lib/generators/react_on_rails/templates/base/base/package.json.tt +0 -12
- data/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb +1 -1
- data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +1 -0
- data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx +1 -7
- data/lib/generators/react_on_rails/templates/{base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt → no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt} +7 -1
- data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/{HelloWorldAppClient.jsx.tt → HelloWorldApp.jsx.tt} +5 -1
- data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx +1 -5
- data/lib/react_on_rails.rb +2 -1
- data/lib/react_on_rails/configuration.rb +17 -5
- data/lib/react_on_rails/react_component/options.rb +76 -0
- data/lib/react_on_rails/server_rendering_pool.rb +9 -151
- data/lib/react_on_rails/server_rendering_pool/exec.rb +166 -0
- data/lib/react_on_rails/server_rendering_pool/node.rb +77 -0
- data/lib/react_on_rails/test_helper.rb +1 -6
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +4 -77
- data/lib/react_on_rails/test_helper/node_process_launcher.rb +12 -0
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +4 -28
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/tasks/assets.rake +115 -0
- data/package.json +2 -1
- data/rakelib/example_type.rb +3 -10
- data/rakelib/examples_config.yml +2 -2
- data/react_on_rails.gemspec +1 -0
- metadata +41 -20
- data/lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md +0 -16
- data/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md +0 -3
- data/lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js +0 -65
- data/lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js +0 -53
- data/lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx +0 -4
- data/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js +0 -39
- data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt +0 -6
- data/lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +0 -6
- data/lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js +0 -21
- data/lib/generators/react_on_rails/templates/redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +0 -19
- data/lib/react_on_rails/test_helper/webpack_process_checker.rb +0 -54
data/lib/react_on_rails.rb
CHANGED
@@ -6,6 +6,7 @@ require "react_on_rails/version_checker"
|
|
6
6
|
require "react_on_rails/configuration"
|
7
7
|
require "react_on_rails/server_rendering_pool"
|
8
8
|
require "react_on_rails/engine"
|
9
|
+
require "react_on_rails/react_component/options"
|
9
10
|
require "react_on_rails/version_syntax_converter"
|
10
11
|
require "react_on_rails/test_helper"
|
11
12
|
require "react_on_rails/git_utils"
|
@@ -13,5 +14,5 @@ require "react_on_rails/utils"
|
|
13
14
|
require "react_on_rails/test_helper"
|
14
15
|
require "react_on_rails/test_helper/webpack_assets_compiler"
|
15
16
|
require "react_on_rails/test_helper/webpack_assets_status_checker"
|
16
|
-
require "react_on_rails/test_helper/webpack_process_checker"
|
17
17
|
require "react_on_rails/test_helper/ensure_assets_compiled"
|
18
|
+
require "react_on_rails/test_helper/node_process_launcher"
|
@@ -8,7 +8,7 @@ module ReactOnRails
|
|
8
8
|
|
9
9
|
def self.setup_config_values
|
10
10
|
if @configuration.webpack_generated_files.empty?
|
11
|
-
files = ["
|
11
|
+
files = ["webpack-bundle.js"]
|
12
12
|
if @configuration.server_bundle_js_file.present?
|
13
13
|
files << @configuration.server_bundle_js_file
|
14
14
|
end
|
@@ -44,7 +44,6 @@ module ReactOnRails
|
|
44
44
|
|
45
45
|
# generated_assets_dirs is deprecated
|
46
46
|
generated_assets_dir: "",
|
47
|
-
|
48
47
|
server_bundle_js_file: "",
|
49
48
|
prerender: false,
|
50
49
|
replay_console: true,
|
@@ -56,7 +55,11 @@ module ReactOnRails
|
|
56
55
|
server_renderer_timeout: 20,
|
57
56
|
skip_display_none: false,
|
58
57
|
webpack_generated_files: [],
|
59
|
-
rendering_extension: nil
|
58
|
+
rendering_extension: nil,
|
59
|
+
server_render_method: "",
|
60
|
+
symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/,
|
61
|
+
npm_build_test_command: "",
|
62
|
+
npm_build_production_command: ""
|
60
63
|
)
|
61
64
|
end
|
62
65
|
|
@@ -66,7 +69,9 @@ module ReactOnRails
|
|
66
69
|
:logging_on_server, :server_renderer_pool_size,
|
67
70
|
:server_renderer_timeout, :raise_on_prerender_error,
|
68
71
|
:skip_display_none, :generated_assets_dirs, :generated_assets_dir,
|
69
|
-
:webpack_generated_files, :rendering_extension
|
72
|
+
:webpack_generated_files, :rendering_extension, :npm_build_test_command,
|
73
|
+
:npm_build_production_command,
|
74
|
+
:server_render_method, :symlink_non_digested_assets_regex
|
70
75
|
|
71
76
|
def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
|
72
77
|
trace: nil, development_mode: nil,
|
@@ -74,10 +79,14 @@ module ReactOnRails
|
|
74
79
|
server_renderer_timeout: nil, raise_on_prerender_error: nil,
|
75
80
|
skip_display_none: nil, generated_assets_dirs: nil,
|
76
81
|
generated_assets_dir: nil, webpack_generated_files: nil,
|
77
|
-
rendering_extension: nil
|
82
|
+
rendering_extension: nil, npm_build_test_command: nil,
|
83
|
+
npm_build_production_command: nil,
|
84
|
+
server_render_method: nil, symlink_non_digested_assets_regex: nil)
|
78
85
|
self.server_bundle_js_file = server_bundle_js_file
|
79
86
|
self.generated_assets_dirs = generated_assets_dirs
|
80
87
|
self.generated_assets_dir = generated_assets_dir
|
88
|
+
self.npm_build_test_command = npm_build_test_command
|
89
|
+
self.npm_build_production_command = npm_build_production_command
|
81
90
|
|
82
91
|
self.prerender = prerender
|
83
92
|
self.replay_console = replay_console
|
@@ -97,6 +106,9 @@ module ReactOnRails
|
|
97
106
|
|
98
107
|
self.webpack_generated_files = webpack_generated_files
|
99
108
|
self.rendering_extension = rendering_extension
|
109
|
+
|
110
|
+
self.server_render_method = server_render_method
|
111
|
+
self.symlink_non_digested_assets_regex = symlink_non_digested_assets_regex
|
100
112
|
end
|
101
113
|
end
|
102
114
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ReactOnRails
|
2
|
+
module ReactComponent
|
3
|
+
class Options
|
4
|
+
NO_PROPS = {}.freeze
|
5
|
+
HIDDEN = "display:none".freeze
|
6
|
+
|
7
|
+
attr_reader :index
|
8
|
+
|
9
|
+
def initialize(name:, index:, options:)
|
10
|
+
@name = name
|
11
|
+
@index = index
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def props
|
16
|
+
options.fetch(:props) { NO_PROPS }
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@name.camelize
|
21
|
+
end
|
22
|
+
|
23
|
+
def dom_id
|
24
|
+
options.fetch(:id) { default_dom_id }
|
25
|
+
end
|
26
|
+
|
27
|
+
def html_options
|
28
|
+
options[:html_options].to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
def prerender
|
32
|
+
retrieve_key(:prerender)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trace
|
36
|
+
retrieve_key(:trace)
|
37
|
+
end
|
38
|
+
|
39
|
+
def replay_console
|
40
|
+
retrieve_key(:replay_console)
|
41
|
+
end
|
42
|
+
|
43
|
+
def raise_on_prerender_error
|
44
|
+
retrieve_key(:raise_on_prerender_error)
|
45
|
+
end
|
46
|
+
|
47
|
+
def data
|
48
|
+
{
|
49
|
+
component_name: name,
|
50
|
+
props: props,
|
51
|
+
trace: trace,
|
52
|
+
dom_id: dom_id
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def style
|
57
|
+
return nil if ReactOnRails.configuration.skip_display_none
|
58
|
+
HIDDEN
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
attr_reader :options
|
64
|
+
|
65
|
+
def default_dom_id
|
66
|
+
"#{@name}-react-component-#{@index}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def retrieve_key(key)
|
70
|
+
options.fetch(key) do
|
71
|
+
ReactOnRails.configuration.public_send(key)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -1,165 +1,23 @@
|
|
1
1
|
require "connection_pool"
|
2
|
+
require_relative "server_rendering_pool/exec"
|
3
|
+
require_relative "server_rendering_pool/node"
|
2
4
|
|
3
5
|
# Based on the react-rails gem.
|
4
6
|
# None of these methods should be called directly.
|
5
7
|
# See app/helpers/react_on_rails_helper.rb
|
6
8
|
module ReactOnRails
|
7
|
-
|
8
|
-
def self.reset_pool
|
9
|
-
options = { size: ReactOnRails.configuration.server_renderer_pool_size,
|
10
|
-
timeout: ReactOnRails.configuration.server_renderer_pool_size }
|
11
|
-
@js_context_pool = ConnectionPool.new(options) { create_js_context }
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.reset_pool_if_server_bundle_was_modified
|
15
|
-
return unless ReactOnRails.configuration.development_mode
|
16
|
-
file_mtime = File.mtime(ReactOnRails::Utils.default_server_bundle_js_file_path)
|
17
|
-
@server_bundle_timestamp ||= file_mtime
|
18
|
-
return if @server_bundle_timestamp == file_mtime
|
19
|
-
ReactOnRails::ServerRenderingPool.reset_pool
|
20
|
-
@server_bundle_timestamp = file_mtime
|
21
|
-
end
|
22
|
-
|
23
|
-
# js_code: JavaScript expression that returns a string.
|
24
|
-
# Returns a Hash:
|
25
|
-
# html: string of HTML for direct insertion on the page by evaluating js_code
|
26
|
-
# consoleReplayScript: script for replaying console
|
27
|
-
# hasErrors: true if server rendering errors
|
28
|
-
# Note, js_code does not have to be based on React.
|
29
|
-
# js_code MUST RETURN json stringify Object
|
30
|
-
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
31
|
-
def self.server_render_js_with_console_logging(js_code)
|
32
|
-
if trace_react_on_rails?
|
33
|
-
@file_index ||= 1
|
34
|
-
trace_messsage(js_code, "tmp/server-generated-#{@file_index % 10}.js")
|
35
|
-
@file_index += 1
|
36
|
-
end
|
37
|
-
json_string = eval_js(js_code)
|
38
|
-
result = JSON.parse(json_string)
|
39
|
-
|
40
|
-
if ReactOnRails.configuration.logging_on_server
|
41
|
-
console_script = result["consoleReplayScript"]
|
42
|
-
console_script_lines = console_script.split("\n")
|
43
|
-
console_script_lines = console_script_lines[2..-2]
|
44
|
-
re = /console\.log\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
45
|
-
if console_script_lines
|
46
|
-
console_script_lines.each do |line|
|
47
|
-
match = re.match(line)
|
48
|
-
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
result
|
53
|
-
end
|
54
|
-
|
9
|
+
module ServerRenderingPool
|
55
10
|
class << self
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
return unless trace_react_on_rails? || force
|
60
|
-
# Set to anything to print generated code.
|
61
|
-
puts "Z" * 80
|
62
|
-
puts "react_renderer.rb: 92"
|
63
|
-
puts "wrote file #{file_name}"
|
64
|
-
File.write(file_name, js_code)
|
65
|
-
puts "Z" * 80
|
66
|
-
end
|
67
|
-
|
68
|
-
def trace_react_on_rails?
|
69
|
-
ENV["TRACE_REACT_ON_RAILS"].present?
|
70
|
-
end
|
71
|
-
|
72
|
-
def eval_js(js_code)
|
73
|
-
@js_context_pool.with do |js_context|
|
74
|
-
result = js_context.eval(js_code)
|
75
|
-
js_context.eval("console.history = []")
|
76
|
-
result
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def create_js_context
|
81
|
-
server_js_file = ReactOnRails::Utils.default_server_bundle_js_file_path
|
82
|
-
if server_js_file.present? && File.exist?(server_js_file)
|
83
|
-
bundle_js_code = File.read(server_js_file)
|
84
|
-
base_js_code = <<-JS
|
85
|
-
#{console_polyfill}
|
86
|
-
#{execjs_timer_polyfills}
|
87
|
-
#{bundle_js_code};
|
88
|
-
JS
|
89
|
-
file_name = "tmp/base_js_code.js"
|
90
|
-
begin
|
91
|
-
trace_messsage(base_js_code, file_name)
|
92
|
-
ExecJS.compile(base_js_code)
|
93
|
-
rescue => e
|
94
|
-
msg = "ERROR when compiling base_js_code! "\
|
95
|
-
"See file #{file_name} to "\
|
96
|
-
"correlate line numbers of error. Error is\n\n#{e.message}"\
|
97
|
-
"\n\n#{e.backtrace.join("\n")}"
|
98
|
-
puts msg
|
99
|
-
Rails.logger.error(msg)
|
100
|
-
trace_messsage(base_js_code, file_name, true)
|
101
|
-
raise e
|
102
|
-
end
|
103
|
-
else
|
104
|
-
if server_js_file.present?
|
105
|
-
msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
|
106
|
-
"read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
|
107
|
-
"avoid this warning"
|
108
|
-
Rails.logger.warn msg
|
109
|
-
puts msg
|
110
|
-
end
|
111
|
-
ExecJS.compile("")
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def execjs_timer_polyfills
|
116
|
-
<<-JS
|
117
|
-
function getStackTrace () {
|
118
|
-
var stack;
|
119
|
-
try {
|
120
|
-
throw new Error('');
|
121
|
-
}
|
122
|
-
catch (error) {
|
123
|
-
stack = error.stack || '';
|
124
|
-
}
|
125
|
-
stack = stack.split('\\n').map(function (line) { return line.trim(); });
|
126
|
-
return stack.splice(stack[0] == 'Error' ? 2 : 1);
|
127
|
-
}
|
128
|
-
|
129
|
-
function setInterval() {
|
130
|
-
#{undefined_for_exec_js_logging('setInterval')}
|
131
|
-
}
|
132
|
-
|
133
|
-
function setTimeout() {
|
134
|
-
#{undefined_for_exec_js_logging('setTimeout')}
|
135
|
-
}
|
136
|
-
JS
|
137
|
-
end
|
138
|
-
|
139
|
-
def undefined_for_exec_js_logging(function_name)
|
140
|
-
if trace_react_on_rails?
|
141
|
-
"console.error('#{function_name} is not defined for execJS. See "\
|
142
|
-
"https://github.com/sstephenson/execjs#faq. Note babel-polyfill may call this.');\n"\
|
143
|
-
" console.error(getStackTrace().join('\\n'));"
|
11
|
+
def pool
|
12
|
+
if ReactOnRails.configuration.server_render_method == "NodeJS"
|
13
|
+
ServerRenderingPool::Node
|
144
14
|
else
|
145
|
-
|
15
|
+
ServerRenderingPool::Exec
|
146
16
|
end
|
147
17
|
end
|
148
18
|
|
149
|
-
|
150
|
-
|
151
|
-
<<-JS
|
152
|
-
var console = { history: [] };
|
153
|
-
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
154
|
-
console[level] = function () {
|
155
|
-
var argArray = Array.prototype.slice.call(arguments);
|
156
|
-
if (argArray.length > 0) {
|
157
|
-
argArray[0] = '[SERVER] ' + argArray[0];
|
158
|
-
}
|
159
|
-
console.history.push({level: level, arguments: argArray});
|
160
|
-
};
|
161
|
-
});
|
162
|
-
JS
|
19
|
+
def method_missing(sym, *args, &block)
|
20
|
+
pool.send sym, *args, &block
|
163
21
|
end
|
164
22
|
end
|
165
23
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module ReactOnRails
|
2
|
+
module ServerRenderingPool
|
3
|
+
# This implementation of the rendering pool uses ExecJS to execute javasript code
|
4
|
+
class Exec
|
5
|
+
def self.reset_pool
|
6
|
+
options = {
|
7
|
+
size: ReactOnRails.configuration.server_renderer_pool_size,
|
8
|
+
timeout: ReactOnRails.configuration.server_renderer_timeout
|
9
|
+
}
|
10
|
+
@js_context_pool = ConnectionPool.new(options) { create_js_context }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.reset_pool_if_server_bundle_was_modified
|
14
|
+
return unless ReactOnRails.configuration.development_mode
|
15
|
+
file_mtime = File.mtime(ReactOnRails::Utils.default_server_bundle_js_file_path)
|
16
|
+
@server_bundle_timestamp ||= file_mtime
|
17
|
+
return if @server_bundle_timestamp == file_mtime
|
18
|
+
ReactOnRails::ServerRenderingPool.reset_pool
|
19
|
+
@server_bundle_timestamp = file_mtime
|
20
|
+
end
|
21
|
+
|
22
|
+
# js_code: JavaScript expression that returns a string.
|
23
|
+
# Returns a Hash:
|
24
|
+
# html: string of HTML for direct insertion on the page by evaluating js_code
|
25
|
+
# consoleReplayScript: script for replaying console
|
26
|
+
# hasErrors: true if server rendering errors
|
27
|
+
# Note, js_code does not have to be based on React.
|
28
|
+
# js_code MUST RETURN json stringify Object
|
29
|
+
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
30
|
+
def self.server_render_js_with_console_logging(js_code)
|
31
|
+
if trace_react_on_rails?
|
32
|
+
@file_index ||= 1
|
33
|
+
trace_messsage(js_code, "tmp/server-generated-#{@file_index % 10}.js")
|
34
|
+
@file_index += 1
|
35
|
+
end
|
36
|
+
json_string = eval_js(js_code)
|
37
|
+
result = JSON.parse(json_string)
|
38
|
+
|
39
|
+
if ReactOnRails.configuration.logging_on_server
|
40
|
+
console_script = result["consoleReplayScript"]
|
41
|
+
console_script_lines = console_script.split("\n")
|
42
|
+
console_script_lines = console_script_lines[2..-2]
|
43
|
+
re = /console\.log\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
44
|
+
if console_script_lines
|
45
|
+
console_script_lines.each do |line|
|
46
|
+
match = re.match(line)
|
47
|
+
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
private
|
56
|
+
|
57
|
+
def trace_messsage(js_code, file_name = "tmp/server-generated.js", force = false)
|
58
|
+
return unless trace_react_on_rails? || force
|
59
|
+
# Set to anything to print generated code.
|
60
|
+
puts "Z" * 80
|
61
|
+
puts "react_renderer.rb: 92"
|
62
|
+
puts "wrote file #{file_name}"
|
63
|
+
File.write(file_name, js_code)
|
64
|
+
puts "Z" * 80
|
65
|
+
end
|
66
|
+
|
67
|
+
def trace_react_on_rails?
|
68
|
+
ENV["TRACE_REACT_ON_RAILS"].present?
|
69
|
+
end
|
70
|
+
|
71
|
+
def eval_js(js_code)
|
72
|
+
@js_context_pool.with do |js_context|
|
73
|
+
result = js_context.eval(js_code)
|
74
|
+
js_context.eval("console.history = []")
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_js_context
|
80
|
+
server_js_file = ReactOnRails::Utils.default_server_bundle_js_file_path
|
81
|
+
if server_js_file.present? && File.exist?(server_js_file)
|
82
|
+
bundle_js_code = File.read(server_js_file)
|
83
|
+
base_js_code = <<-JS
|
84
|
+
#{console_polyfill}
|
85
|
+
#{execjs_timer_polyfills}
|
86
|
+
#{bundle_js_code};
|
87
|
+
JS
|
88
|
+
file_name = "tmp/base_js_code.js"
|
89
|
+
begin
|
90
|
+
trace_messsage(base_js_code, file_name)
|
91
|
+
ExecJS.compile(base_js_code)
|
92
|
+
rescue => e
|
93
|
+
msg = "ERROR when compiling base_js_code! "\
|
94
|
+
"See file #{file_name} to "\
|
95
|
+
"correlate line numbers of error. Error is\n\n#{e.message}"\
|
96
|
+
"\n\n#{e.backtrace.join("\n")}"
|
97
|
+
puts msg
|
98
|
+
Rails.logger.error(msg)
|
99
|
+
trace_messsage(base_js_code, file_name, true)
|
100
|
+
raise e
|
101
|
+
end
|
102
|
+
else
|
103
|
+
if server_js_file.present?
|
104
|
+
msg = "You specified server rendering JS file: #{server_js_file}, but it cannot be "\
|
105
|
+
"read. You may set the server_bundle_js_file in your configuration to be \"\" to "\
|
106
|
+
"avoid this warning"
|
107
|
+
Rails.logger.warn msg
|
108
|
+
puts msg
|
109
|
+
end
|
110
|
+
ExecJS.compile("")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def execjs_timer_polyfills
|
115
|
+
<<-JS
|
116
|
+
function getStackTrace () {
|
117
|
+
var stack;
|
118
|
+
try {
|
119
|
+
throw new Error('');
|
120
|
+
}
|
121
|
+
catch (error) {
|
122
|
+
stack = error.stack || '';
|
123
|
+
}
|
124
|
+
stack = stack.split('\\n').map(function (line) { return line.trim(); });
|
125
|
+
return stack.splice(stack[0] == 'Error' ? 2 : 1);
|
126
|
+
}
|
127
|
+
|
128
|
+
function setInterval() {
|
129
|
+
#{undefined_for_exec_js_logging('setInterval')}
|
130
|
+
}
|
131
|
+
|
132
|
+
function setTimeout() {
|
133
|
+
#{undefined_for_exec_js_logging('setTimeout')}
|
134
|
+
}
|
135
|
+
JS
|
136
|
+
end
|
137
|
+
|
138
|
+
def undefined_for_exec_js_logging(function_name)
|
139
|
+
if trace_react_on_rails?
|
140
|
+
"console.error('#{function_name} is not defined for execJS. See "\
|
141
|
+
"https://github.com/sstephenson/execjs#faq. Note babel-polyfill may call this.');\n"\
|
142
|
+
" console.error(getStackTrace().join('\\n'));"
|
143
|
+
else
|
144
|
+
""
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Reimplement console methods for replaying on the client
|
149
|
+
def console_polyfill
|
150
|
+
<<-JS
|
151
|
+
var console = { history: [] };
|
152
|
+
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
153
|
+
console[level] = function () {
|
154
|
+
var argArray = Array.prototype.slice.call(arguments);
|
155
|
+
if (argArray.length > 0) {
|
156
|
+
argArray[0] = '[SERVER] ' + argArray[0];
|
157
|
+
}
|
158
|
+
console.history.push({level: level, arguments: argArray});
|
159
|
+
};
|
160
|
+
});
|
161
|
+
JS
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|