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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b19c93747fab84bdc395c8f9dc2d664581863fca
4
- data.tar.gz: 57488190d54beecdbc25296efd1d4ad0bc769cae
3
+ metadata.gz: 829e8c7c5f08f5a219d996d2356c0bc6a0125b42
4
+ data.tar.gz: 1d5bf7c969a5f182e2f81bee3626f4f2acd0ff85
5
5
  SHA512:
6
- metadata.gz: 480d293755f22424befb537760ccce6e3e148ce82adf015efa5a2fa3699486d615c7ab332e3b980bb22f423355c15027d706b6423824d24f3755e56bf605cf59
7
- data.tar.gz: 5eeecc42bbe0e439ad468b42b683632101608fa4b0fbba72e4c01fd6619c673ac3f18716d6aa39df121021a4fee4555ea2b4e1e5916c3433830848d11ac5582c
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.new(options).render_js(js_expression,
136
- options)
137
+ ReactOnRails::ReactRenderer.render_js(js_expression,
138
+ options)
137
139
  end
138
140
 
139
141
 
@@ -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
- #{console_replay_js_code}
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
- if js_context
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
- (@replay_console || ReactOnRails.configuration.logging_on_server) ? CONSOLE_REPLAY : ""
153
- end
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
@@ -1,3 +1,3 @@
1
1
  module ReactOnRails
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
@@ -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 |spec|
7
- spec.name = "react_on_rails"
8
- spec.version = ReactOnRails::VERSION
9
- spec.authors = ["Justin Gordon"]
10
- spec.email = ["justin@shakacode.com"]
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
- spec.summary = %q{Rails with react server rendering with webpack. }
13
- spec.description = %q{See README.md}
14
- spec.homepage = "https://github.com/shakacode/react_on_rails"
15
- spec.license = "MIT"
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
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = "exe"
19
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
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
- spec.add_dependency "rails", "~> 4.2"
23
- spec.add_dependency "execjs", "~> 2.5"
22
+ s.add_dependency "rails", ">= 4.0"
23
+ s.add_dependency "execjs", "~> 2.5"
24
+ s.add_dependency "connection_pool"
24
25
 
25
- spec.add_development_dependency "bundler", "~> 1.10"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec"
28
- spec.add_development_dependency "rubocop"
29
- spec.add_development_dependency "coveralls"
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.6
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-27 00:00:00.000000000 Z
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.2'
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.2'
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