react_on_rails 0.1.6 → 0.1.7
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/README.md +10 -0
- data/app/helpers/react_on_rails_helper.rb +4 -2
- data/lib/react_on_rails.rb +4 -1
- data/lib/react_on_rails/configuration.rb +9 -3
- data/lib/react_on_rails/react_renderer.rb +9 -52
- data/lib/react_on_rails/server_rendering_pool.rb +57 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/react_on_rails.gemspec +21 -20
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 829e8c7c5f08f5a219d996d2356c0bc6a0125b42
|
4
|
+
data.tar.gz: 1d5bf7c969a5f182e2f81bee3626f4f2acd0ff85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa2ef614a94bba6bcda082f6398889732ade8cc7c8885ba305fdee9638a599ac3b0e85d77175c4c2a05875463c3a654b76037de58830276c9b144ccb2bec9e39
|
7
|
+
data.tar.gz: 468c2014a1132b53ee9de227a10a30a4f4a07f435b1caa4ee64311541d1bb8ce034c235aaa5b51497e60f7ed852bf7fec499eed7b2d90b72e4e3b5bb50751ff8
|
data/README.md
CHANGED
@@ -159,9 +159,19 @@ ReactOnRails.configure do |config|
|
|
159
159
|
# For server rendering. This can be set to false so that server side messages are discarded.
|
160
160
|
config.replay_console = true # Default is true. Be cautious about turning this off.
|
161
161
|
config.logging_on_server = true # Default is true. Logs server rendering messags to Rails.logger.info
|
162
|
+
|
163
|
+
# Settings for the pool of renderers:
|
164
|
+
config.server_renderer_pool_size ||= 1 # ExecJS doesn't allow more than one on MRI
|
165
|
+
config.server_renderer_timeout ||= 20 # seconds
|
162
166
|
end
|
163
167
|
```
|
164
168
|
|
169
|
+
You can configure your pool of JS virtual machines and specify where it should load code:
|
170
|
+
|
171
|
+
- On MRI, use `therubyracer` for the best performance (see [discussion](https://github.com/reactjs/react-rails/pull/290))
|
172
|
+
- On MRI, you'll get a deadlock with `pool_size` > 1
|
173
|
+
- If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
|
174
|
+
|
165
175
|
# Try it out in the simple sample app
|
166
176
|
Contributions and pull requests welcome!
|
167
177
|
|
@@ -112,6 +112,8 @@ module ReactOnRailsHelper
|
|
112
112
|
else
|
113
113
|
["",""]
|
114
114
|
end
|
115
|
+
rescue ExecJS::ProgramError => err
|
116
|
+
raise ReactOnRails::ServerRenderingPool::PrerenderError.new(react_component_name, props_string, err)
|
115
117
|
end
|
116
118
|
|
117
119
|
# Takes javascript code and returns the output from it. This is called by react_component, which
|
@@ -132,8 +134,8 @@ module ReactOnRailsHelper
|
|
132
134
|
def render_js_internal(js_expression, options = {})
|
133
135
|
# TODO: This should be changed so that we don't create a new context every time
|
134
136
|
# Example of doing this here: https://github.com/reactjs/react-rails/tree/master/lib/react/rails
|
135
|
-
ReactOnRails::ReactRenderer.
|
136
|
-
|
137
|
+
ReactOnRails::ReactRenderer.render_js(js_expression,
|
138
|
+
options)
|
137
139
|
end
|
138
140
|
|
139
141
|
|
data/lib/react_on_rails.rb
CHANGED
@@ -2,8 +2,11 @@ require "rails"
|
|
2
2
|
|
3
3
|
require "react_on_rails/version"
|
4
4
|
require "react_on_rails/configuration"
|
5
|
-
|
5
|
+
require "react_on_rails/server_rendering_pool"
|
6
6
|
module ReactOnRails
|
7
7
|
class Engine < ::Rails::Engine
|
8
|
+
config.to_prepare do
|
9
|
+
ReactOnRails::ServerRenderingPool.reset_pool
|
10
|
+
end
|
8
11
|
end
|
9
12
|
end
|
@@ -11,15 +11,17 @@ module ReactOnRails
|
|
11
11
|
logging_on_server: true,
|
12
12
|
generator_function: false,
|
13
13
|
trace: Rails.env.development?,
|
14
|
-
|
14
|
+
server_renderer_pool_size: 1,
|
15
|
+
server_renderer_timeout: 20)
|
15
16
|
end
|
16
17
|
|
17
18
|
class Configuration
|
18
19
|
attr_accessor :server_bundle_js_file, :prerender, :replay_console, :generator_function, :trace,
|
19
|
-
:logging_on_server
|
20
|
+
:logging_on_server, :server_renderer_pool_size, :server_renderer_timeout
|
20
21
|
|
21
22
|
def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
|
22
|
-
generator_function: nil, trace: nil, logging_on_server: nil
|
23
|
+
generator_function: nil, trace: nil, logging_on_server: nil,
|
24
|
+
server_renderer_pool_size: nil, server_renderer_timeout: nil)
|
23
25
|
if File.exist?(server_bundle_js_file)
|
24
26
|
self.server_bundle_js_file = server_bundle_js_file
|
25
27
|
else
|
@@ -31,6 +33,10 @@ module ReactOnRails
|
|
31
33
|
self.logging_on_server = logging_on_server
|
32
34
|
self.generator_function = generator_function
|
33
35
|
self.trace = trace.nil? ? Rails.env.development? : trace
|
36
|
+
|
37
|
+
# Server rendering:
|
38
|
+
self.server_renderer_pool_size = server_renderer_pool_size # increase if you're on JRuby
|
39
|
+
self.server_renderer_timeout = server_renderer_timeout # seconds
|
34
40
|
end
|
35
41
|
end
|
36
42
|
end
|
@@ -1,22 +1,10 @@
|
|
1
1
|
# Kudos to react-rails for how to do the polyfill of the console!
|
2
2
|
# https://github.com/reactjs/react-rails/blob/master/lib/react/server_rendering/sprockets_renderer.rb
|
3
3
|
|
4
|
+
# require 'react_on_rails/server_rendering_pool'
|
5
|
+
|
4
6
|
module ReactOnRails
|
5
7
|
class ReactRenderer
|
6
|
-
# Reimplement console methods for replaying on the client
|
7
|
-
CONSOLE_POLYFILL = <<-JS
|
8
|
-
var console = { history: [] };
|
9
|
-
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
10
|
-
console[level] = function () {
|
11
|
-
var argArray = Array.prototype.slice.call(arguments);
|
12
|
-
if (argArray.length > 0) {
|
13
|
-
argArray[0] = '[SERVER] ' + argArray[0];
|
14
|
-
}
|
15
|
-
console.history.push({level: level, arguments: argArray});
|
16
|
-
};
|
17
|
-
});
|
18
|
-
JS
|
19
|
-
|
20
8
|
# Script to write to the browser console.
|
21
9
|
# NOTE: result comes from enclosing closure and is the server generated HTML
|
22
10
|
# that we intend to write to the browser. Thus, the script tag will get executed right after
|
@@ -36,17 +24,13 @@ var console = { history: [] };
|
|
36
24
|
if (typeof window !== 'undefined') { debugger; }
|
37
25
|
JS
|
38
26
|
|
39
|
-
def initialize(options)
|
40
|
-
@replay_console = options.fetch(:replay_console) { ReactOnRails.configuration.replay_console }
|
41
|
-
end
|
42
|
-
|
43
27
|
# js_code: JavaScript expression that returns a string.
|
44
28
|
# Returns an Array:
|
45
29
|
# [0]: string of HTML for direct insertion on the page by evaluating js_code
|
46
30
|
# [1]: console messages
|
47
31
|
# Note, js_code does not have to be based on React.
|
48
32
|
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
49
|
-
def render_js(js_code, options = {})
|
33
|
+
def self.render_js(js_code, options = {})
|
50
34
|
component_name = options.fetch(:react_component_name, "")
|
51
35
|
server_side = options.fetch(:server_side, false)
|
52
36
|
|
@@ -57,7 +41,7 @@ var console = { history: [] };
|
|
57
41
|
var htmlResult = '';
|
58
42
|
var consoleReplay = '';
|
59
43
|
#{ReactOnRails::ReactRenderer.wrap_code_with_exception_handler(result_js_code, component_name)}
|
60
|
-
|
44
|
+
#{console_replay_js_code(options)}
|
61
45
|
return JSON.stringify([htmlResult, consoleReplay]);
|
62
46
|
})()
|
63
47
|
JS
|
@@ -70,13 +54,10 @@ var console = { history: [] };
|
|
70
54
|
puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
|
71
55
|
end
|
72
56
|
|
73
|
-
|
74
|
-
json_string = js_context.eval(js_code_wrapper)
|
75
|
-
else
|
76
|
-
json_string = ExecJS.eval(js_code_wrapper)
|
77
|
-
end
|
57
|
+
json_string = ReactOnRails::ServerRenderingPool.render(js_code_wrapper)
|
78
58
|
# element 0 is the html, element 1 is the script tag for the server console output
|
79
59
|
result = JSON.parse(json_string)
|
60
|
+
|
80
61
|
if ReactOnRails.configuration.logging_on_server
|
81
62
|
console_script = result[1]
|
82
63
|
console_script_lines = console_script.split("\n")
|
@@ -148,33 +129,9 @@ var console = { history: [] };
|
|
148
129
|
JS
|
149
130
|
end
|
150
131
|
|
151
|
-
def console_replay_js_code
|
152
|
-
(
|
153
|
-
|
154
|
-
|
155
|
-
def base_js_code(bundle_js_code)
|
156
|
-
<<-JS
|
157
|
-
#{CONSOLE_POLYFILL}
|
158
|
-
#{bundle_js_code};
|
159
|
-
JS
|
160
|
-
end
|
161
|
-
|
162
|
-
def js_context
|
163
|
-
if @js_context.nil?
|
164
|
-
@js_context = begin
|
165
|
-
server_js_file = ReactOnRails.configuration.server_bundle_js_file
|
166
|
-
if server_js_file.present? && File.exist?(server_js_file)
|
167
|
-
bundle_js_code = File.read(server_js_file)
|
168
|
-
ExecJS.compile(base_js_code(bundle_js_code))
|
169
|
-
else
|
170
|
-
if server_js_file.present?
|
171
|
-
Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
|
172
|
-
end
|
173
|
-
false # using false so we don't try every time if no server_js file
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
@js_context
|
132
|
+
def self.console_replay_js_code(options)
|
133
|
+
replay_console = options.fetch(:replay_console) { ReactOnRails.configuration.replay_console }
|
134
|
+
(replay_console || ReactOnRails.configuration.logging_on_server) ? CONSOLE_REPLAY : ""
|
178
135
|
end
|
179
136
|
end
|
180
137
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
|
3
|
+
# Based on the react-rails gem
|
4
|
+
module ReactOnRails
|
5
|
+
class ServerRenderingPool
|
6
|
+
def self.reset_pool
|
7
|
+
options = { size: ReactOnRails.configuration.server_renderer_pool_size,
|
8
|
+
timeout: ReactOnRails.configuration.server_renderer_pool_size }
|
9
|
+
@@js_context_pool = ConnectionPool.new(options) { create_js_context }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.render(js_code)
|
13
|
+
@@js_context_pool.with do |js_context|
|
14
|
+
js_context.eval(js_code)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create_js_context
|
19
|
+
server_js_file = ReactOnRails.configuration.server_bundle_js_file
|
20
|
+
if server_js_file.present? && File.exist?(server_js_file)
|
21
|
+
bundle_js_code = File.read(server_js_file)
|
22
|
+
base_js_code = <<-JS
|
23
|
+
#{CONSOLE_POLYFILL}
|
24
|
+
#{bundle_js_code};
|
25
|
+
JS
|
26
|
+
ExecJS.compile(base_js_code)
|
27
|
+
else
|
28
|
+
if server_js_file.present?
|
29
|
+
Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
|
30
|
+
end
|
31
|
+
ExecJS.compile("")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Reimplement console methods for replaying on the client
|
36
|
+
CONSOLE_POLYFILL = <<-JS
|
37
|
+
var console = { history: [] };
|
38
|
+
['error', 'log', 'info', 'warn'].forEach(function (level) {
|
39
|
+
console[level] = function () {
|
40
|
+
var argArray = Array.prototype.slice.call(arguments);
|
41
|
+
if (argArray.length > 0) {
|
42
|
+
argArray[0] = '[SERVER] ' + argArray[0];
|
43
|
+
}
|
44
|
+
console.history.push({level: level, arguments: argArray});
|
45
|
+
};
|
46
|
+
});
|
47
|
+
JS
|
48
|
+
|
49
|
+
class PrerenderError < RuntimeError
|
50
|
+
def initialize(component_name, props, js_message)
|
51
|
+
message = ["Encountered error \"#{js_message}\" when prerendering #{component_name} with #{props}",
|
52
|
+
js_message.backtrace.join("\n")].join("\n")
|
53
|
+
super(message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/react_on_rails.gemspec
CHANGED
@@ -3,28 +3,29 @@ lib = File.expand_path('../lib', __FILE__)
|
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
4
|
require 'react_on_rails/version'
|
5
5
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "react_on_rails"
|
8
|
+
s.version = ReactOnRails::VERSION
|
9
|
+
s.authors = ["Justin Gordon"]
|
10
|
+
s.email = ["justin@shakacode.com"]
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
s.summary = %q{Rails with react server rendering with webpack. }
|
13
|
+
s.description = %q{See README.md}
|
14
|
+
s.homepage = "https://github.com/shakacode/react_on_rails"
|
15
|
+
s.license = "MIT"
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
s.bindir = "exe"
|
19
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
s.add_dependency "rails", ">= 4.0"
|
23
|
+
s.add_dependency "execjs", "~> 2.5"
|
24
|
+
s.add_dependency "connection_pool"
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
s.add_development_dependency "bundler", "~> 1.10"
|
27
|
+
s.add_development_dependency "rake", "~> 10.0"
|
28
|
+
s.add_development_dependency "rspec"
|
29
|
+
s.add_development_dependency "rubocop"
|
30
|
+
s.add_development_dependency "coveralls"
|
30
31
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: react_on_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '4.
|
19
|
+
version: '4.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '4.
|
26
|
+
version: '4.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: execjs
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: connection_pool
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +150,7 @@ files:
|
|
136
150
|
- lib/react_on_rails.rb
|
137
151
|
- lib/react_on_rails/configuration.rb
|
138
152
|
- lib/react_on_rails/react_renderer.rb
|
153
|
+
- lib/react_on_rails/server_rendering_pool.rb
|
139
154
|
- lib/react_on_rails/version.rb
|
140
155
|
- react_on_rails.gemspec
|
141
156
|
- ruby-lint.yml
|