react_on_rails 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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