react_on_rails 0.1.2 → 0.1.3

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: 6ff4186feb1c1939c00dd049ef22d868aea660f6
4
- data.tar.gz: 0b5808c38aeb2a3092ec374e6fa8ff2871849f57
3
+ metadata.gz: 95c7eae480cfc52816e7f263bb1911e708a93687
4
+ data.tar.gz: a53501d57413eb474a1ee4015af8999849267402
5
5
  SHA512:
6
- metadata.gz: 1c3262b0bb0634626438299e5330e4bd4268a743ddb83f795adfbb2a8e29ed3dc9daf4c987dfca29113c68d66d1daf9e2d5b5277bf59b02cb391dfa28ab6f59e
7
- data.tar.gz: 0885111f10b06d283bbc39058492a1f5d6e9ff958cc61ba1a4b67ece33a7c78af6006232a1ef380be349d6d7ea8fa2021a022e749574ad9f649fea0107902536
6
+ metadata.gz: fe6a6b8a89721d0a65356538765129ad63049f70fa291a6785008fe20cc798390ddfc4f71bd1422efdcd7d7cfc0598e041cd6fa74cdbf1e0a5a831b1c07a58a4
7
+ data.tar.gz: ca064e881bef0e9758f32f165801d91176ee168e1cf887914185aeae36d690ca95554e6eb4331bc6d54d5b2ccf6488405ead090f5fd06b77e5d56617b1de58b5
data/.babelrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "stage": 0
3
+ }
data/.rubocop.yml CHANGED
@@ -24,3 +24,39 @@ Style/StringLiterals:
24
24
 
25
25
  Style/Documentation:
26
26
  Enabled: false
27
+
28
+ Lint/AssignmentInCondition:
29
+ Exclude:
30
+ - 'spec/dummy/bin/spring'
31
+
32
+ # Offense count: 2
33
+ Lint/HandleExceptions:
34
+ Exclude:
35
+ - 'spec/dummy/bin/rails'
36
+ - 'spec/dummy/bin/rake'
37
+
38
+ # Offense count: 1
39
+ Metrics/AbcSize:
40
+ Max: 18
41
+
42
+ # Offense count: 1
43
+ # Configuration parameters: CountComments.
44
+ Metrics/ClassLength:
45
+ Max: 114
46
+
47
+ # Offense count: 9
48
+ # Configuration parameters: CountComments.
49
+ Metrics/MethodLength:
50
+ Max: 38
51
+
52
+ # Offense count: 1
53
+ # Configuration parameters: CountComments.
54
+ Metrics/ModuleLength:
55
+ Max: 119
56
+
57
+ # Offense count: 3
58
+ # Configuration parameters: AllowedVariables.
59
+ Style/GlobalVars:
60
+ Exclude:
61
+ - 'spec/dummy/config/environments/development.rb'
62
+
data/README.md CHANGED
@@ -77,7 +77,7 @@ Params are:
77
77
  global.MyReactComponentApp = MyReactComponentApp;
78
78
  ```
79
79
  See `spec/dummy/client/app/startup/serverGlobals.jsx` and
80
- `spec/dummy/client/app/startup/ClientApp.jsx` for examples of this.
80
+ `spec/dummy/client/app/startup/ClientReduxApp.jsx` for examples of this.
81
81
 
82
82
  * **props**: Ruby Hash which contains the properties to pass to the react object
83
83
 
@@ -221,6 +221,11 @@ Start the sample app like this for some debug printing:
221
221
  TRACE_REACT_ON_RAILS=true && foreman start
222
222
  ```
223
223
 
224
+ ### Generated JavaScript
225
+
226
+ 1. See spec/dummy/spec/sample_generated_js/server-generated.js to see the JavaScript for typical server rendering.
227
+ 2. See spec/dummy/spec/sample_generated_js/client-generated.js to see the JavaScript for typical client rendering.
228
+
224
229
  ### Linting
225
230
  All linting is performed from the docker container. You will need docker and docker-compose installed
226
231
  locally to lint code changes via the lint container.
data/Rakefile CHANGED
@@ -3,12 +3,12 @@ require "fileutils"
3
3
  namespace :run_rspec do
4
4
  desc "Run RSpec for top level only"
5
5
  task :gem do
6
- sh %{ rspec --exclude-pattern "spec/dummy/**/*_spec.rb" spec }
6
+ sh %( rspec --exclude-pattern "spec/dummy/**/*_spec.rb" spec )
7
7
  end
8
8
 
9
9
  desc "Run RSpec for spec/dummy only"
10
10
  task :dummy do
11
- sh %{ cd spec/dummy && rspec }
11
+ sh %( cd spec/dummy && rspec )
12
12
  end
13
13
 
14
14
  task run_rspec: [:gem, :dummy] do
@@ -21,7 +21,6 @@ task run_rspec: ["run_rspec:run_rspec"]
21
21
  task default: :run_rspec
22
22
 
23
23
  namespace :lint do
24
-
25
24
  desc "Run Rubocop as shell"
26
25
  task :rubocop do
27
26
  sh "rubocop ."
@@ -44,7 +43,7 @@ namespace :lint do
44
43
 
45
44
  desc "Run jscs from shell"
46
45
  task :jscs do
47
- sh "jscs ."
46
+ sh "jscs -e ."
48
47
  end
49
48
 
50
49
  task lint: [:eslint, :rubocop, :ruby, :jscs, :scss] do
@@ -67,7 +66,7 @@ namespace :docker do
67
66
 
68
67
  desc "Run scss-lint linter from docker"
69
68
  task :scss do
70
- sh"docker-compose run lint rake lint:scss"
69
+ sh "docker-compose run lint rake lint:scss"
71
70
  end
72
71
 
73
72
  desc "Run eslint linter from docker"
@@ -87,5 +86,3 @@ end
87
86
 
88
87
  desc "Runs all linters from docker. Run `rake -D docker` to see all available lint options"
89
88
  task docker: ["docker:lint"]
90
-
91
-
@@ -1,7 +1,11 @@
1
- require 'react_on_rails/react_renderer'
1
+ require "react_on_rails/react_renderer"
2
2
 
3
- module ReactOnRailsHelper
3
+ # NOTE:
4
+ # For any heredoc JS:
5
+ # 1. The white spacing in this file matters!
6
+ # 2. Keep all #{some_var} fully to the left so that all indentation is done evenly in that var
4
7
 
8
+ module ReactOnRailsHelper
5
9
  # react_component_name: can be a React component, created using a ES6 class, or
6
10
  # React.createClass, or a
7
11
  # `generator function` that returns a React component
@@ -47,8 +51,9 @@ module ReactOnRailsHelper
47
51
  page_loaded_js = <<-JS
48
52
  (function() {
49
53
  window.#{data_variable_name} = #{props.to_json};
50
- #{define_render_if_dom_node_present(react_component_name, data_variable_name, dom_id, trace(options), generator_function(options))}
51
- #{install_render_events}
54
+ #{define_render_if_dom_node_present(react_component_name, data_variable_name, dom_id,
55
+ trace(options), generator_function(options))}
56
+ #{install_render_events}
52
57
  })();
53
58
  JS
54
59
 
@@ -77,10 +82,10 @@ module ReactOnRailsHelper
77
82
  def server_rendered_react_component_html(options, props, react_component_name)
78
83
  if prerender(options)
79
84
  render_js_expression = <<-JS
80
- (function(React) {
81
- var reactElement = #{render_js_react_element(react_component_name, props.to_json, generator_function(options))};
82
- return React.renderToString(reactElement);
83
- })(this.React);
85
+ (function(React) {
86
+ var reactElement = #{render_js_react_element(react_component_name, props.to_json, generator_function(options))}
87
+ return React.renderToString(reactElement);
88
+ })(this.React);
84
89
  JS
85
90
  # create the server generated html of the react component with props
86
91
  options[:react_component_name] = react_component_name
@@ -97,6 +102,8 @@ module ReactOnRailsHelper
97
102
  # This method could be used by itself to render the output of any javascript that returns a
98
103
  # string of proper HTML.
99
104
  def render_js(js_expression, options = {})
105
+ # TODO: This should be changed so that we don't create a new context every time
106
+ # Example of doing this here: https://github.com/reactjs/react-rails/tree/master/lib/react/rails
100
107
  ReactOnRails::ReactRenderer.new(options).render_js(js_expression,
101
108
  options).html_safe
102
109
  end
@@ -117,9 +124,8 @@ module ReactOnRailsHelper
117
124
 
118
125
  def debug_js(react_component_name, data_variable, dom_id, trace)
119
126
  if trace
120
- <<-JS
121
- console.log("CLIENT SIDE RENDERED #{react_component_name} with data_variable #{data_variable} to dom node with id: #{dom_id}");
122
- JS
127
+ "console.log(\"CLIENT SIDE RENDERED #{react_component_name} with data_variable"\
128
+ " #{data_variable} to dom node with id: #{dom_id}\");"
123
129
  else
124
130
  ""
125
131
  end
@@ -142,58 +148,58 @@ console.log("CLIENT SIDE RENDERED #{react_component_name} with data_variable #{d
142
148
 
143
149
  <<-JS
144
150
  (function(React) {
145
- var props = #{props_string};
146
- return #{js_create_element};
147
- })(this.React);
151
+ var props = #{props_string};
152
+ return #{js_create_element};
153
+ })(this.React);
148
154
  JS
149
155
  end
150
156
 
151
157
  def define_render_if_dom_node_present(react_component_name, data_variable, dom_id, trace, generator_function)
152
158
  inner_js_code = <<-JS_CODE
153
- var domNode = document.getElementById('#{dom_id}');
154
- if (domNode) {
155
- #{debug_js(react_component_name, data_variable, dom_id, trace)}
156
- var reactElement = #{render_js_react_element(react_component_name, data_variable, generator_function)};
157
- React.render(reactElement, domNode);
158
- }
159
- JS_CODE
159
+ var domNode = document.getElementById('#{dom_id}');
160
+ if (domNode) {
161
+ #{debug_js(react_component_name, data_variable, dom_id, trace)}
162
+ var reactElement = #{render_js_react_element(react_component_name, data_variable, generator_function)}
163
+ React.render(reactElement, domNode);
164
+ }
165
+ JS_CODE
160
166
 
161
167
  <<-JS
162
- var renderIfDomNodePresent = function() {
163
- #{ReactOnRails::ReactRenderer.wrap_code_with_exception_handler(inner_js_code, react_component_name)}
164
- }
168
+ var renderIfDomNodePresent = function() {
169
+ #{ReactOnRails::ReactRenderer.wrap_code_with_exception_handler(inner_js_code, react_component_name)}
170
+ }
165
171
  JS
166
172
  end
167
173
 
168
174
  def non_turbolinks_bootstrap
169
175
  <<-JS
170
- document.addEventListener("DOMContentLoaded", function(event) {
171
- console.log("DOMContentLoaded event fired");
172
- renderIfDomNodePresent();
173
- });
176
+ document.addEventListener("DOMContentLoaded", function(event) {
177
+ console.log("DOMContentLoaded event fired");
178
+ renderIfDomNodePresent();
179
+ });
174
180
  JS
175
181
  end
176
182
 
177
183
  def turbolinks_bootstrap(dom_id)
178
184
  <<-JS
179
- var turbolinksInstalled = typeof(Turbolinks) !== 'undefined';
180
- if (!turbolinksInstalled) {
181
- console.warn("WARNING: NO TurboLinks detected in JS, but it's in your Gemfile");
182
- #{non_turbolinks_bootstrap}
183
- } else {
184
- function onPageChange(event) {
185
- var removePageChangeListener = function() {
186
- document.removeEventListener("page:change", onPageChange);
187
- document.removeEventListener("page:before-unload", removePageChangeListener);
188
- var domNode = document.getElementById('#{dom_id}');
189
- React.unmountComponentAtNode(domNode);
190
- };
191
- document.addEventListener("page:before-unload", removePageChangeListener);
192
-
193
- renderIfDomNodePresent();
185
+ var turbolinksInstalled = typeof(Turbolinks) !== 'undefined';
186
+ if (!turbolinksInstalled) {
187
+ console.warn("WARNING: NO TurboLinks detected in JS, but it's in your Gemfile");
188
+ #{non_turbolinks_bootstrap}
189
+ } else {
190
+ function onPageChange(event) {
191
+ var removePageChangeListener = function() {
192
+ document.removeEventListener("page:change", onPageChange);
193
+ document.removeEventListener("page:before-unload", removePageChangeListener);
194
+ var domNode = document.getElementById('#{dom_id}');
195
+ React.unmountComponentAtNode(domNode);
196
+ };
197
+ document.addEventListener("page:before-unload", removePageChangeListener);
198
+
199
+ renderIfDomNodePresent();
200
+ }
201
+ document.addEventListener("page:change", onPageChange);
194
202
  }
195
- document.addEventListener("page:change", onPageChange);
196
- }
197
203
  JS
198
204
  end
199
205
  end
@@ -18,11 +18,16 @@ module ReactOnRails
18
18
 
19
19
  def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
20
20
  generator_function: nil, trace: nil)
21
- self.server_bundle_js_file = server_bundle_js_file
21
+ if File.exist?(server_bundle_js_file)
22
+ self.server_bundle_js_file = server_bundle_js_file
23
+ else
24
+ self.server_bundle_js_file = nil
25
+ end
26
+
22
27
  self.prerender = prerender
23
28
  self.replay_console = replay_console
24
29
  self.generator_function = generator_function
25
- self.trace = Rails.env.development?
30
+ self.trace = trace.nil? ? Rails.env.development? : trace
26
31
  end
27
32
  end
28
33
  end
@@ -18,29 +18,21 @@ var console = { history: [] };
18
18
  # that we intend to write to the browser. Thus, the script tag will get executed right after
19
19
  # the HTML is rendered.
20
20
  CONSOLE_REPLAY = <<-JS
21
- var history = console.history;
22
- if (history && history.length > 0) {
23
- result += '\\n<script>';
24
- history.forEach(function (msg) {
25
- result += '\\nconsole.' + msg.level + '.apply(console, ' + JSON.stringify(msg.arguments) + ');';
26
- });
27
- result += '\\n</script>';
28
- }
21
+ var history = console.history;
22
+ if (history && history.length > 0) {
23
+ result += '\\n<script>';
24
+ history.forEach(function (msg) {
25
+ result += '\\nconsole.' + msg.level + '.apply(console, ' + JSON.stringify(msg.arguments) + ');';
26
+ });
27
+ result += '\\n</script>';
28
+ }
29
29
  JS
30
30
 
31
31
  DEBUGGER = <<-JS
32
32
  if (typeof window !== 'undefined') { debugger; }
33
33
  JS
34
34
 
35
- def base_js_code
36
- <<-JS
37
- #{CONSOLE_POLYFILL}
38
- #{bundle_js_code};
39
- JS
40
- end
41
-
42
35
  def initialize(options)
43
- @context = ExecJS.compile(base_js_code)
44
36
  @replay_console = options.fetch(:replay_console) { ReactOnRails.configuration.replay_console }
45
37
  end
46
38
 
@@ -51,73 +43,76 @@ if (history && history.length > 0) {
51
43
  def render_js(js_code, options = {})
52
44
  component_name = options.fetch(:react_component_name, "")
53
45
 
54
- result_js_code = "result = #{js_code}"
46
+ result_js_code = " result = #{js_code}"
55
47
 
56
48
  js_code_wrapper = <<-JS
57
- (function () {
58
- var result = '';
59
- #{ReactOnRails::ReactRenderer.wrap_code_with_exception_handler(result_js_code, component_name)}
60
- #{after_render};
61
- return result;
62
- })()
49
+ (function () {
50
+ var result = '';
51
+ #{ReactOnRails::ReactRenderer.wrap_code_with_exception_handler(result_js_code, component_name)}
52
+ #{after_render}
53
+ return result;
54
+ })()
63
55
  JS
64
56
 
65
57
  trace_rails_on_maui = ENV["TRACE_REACT_ON_RAILS"].present? # Set to anything to print generated code.
66
58
  if trace_rails_on_maui
67
59
  puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
68
60
  puts "react_renderer.rb: 92"
69
- puts "js_code_wrapper = #{js_code_wrapper.ai}"
70
61
  puts "wrote file tmp/server-generated.js"
71
- File.write('tmp/server-generated.js', js_code_wrapper)
62
+ File.write("tmp/server-generated.js", js_code_wrapper)
72
63
  puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
73
64
  end
74
65
 
75
- @context.eval(js_code_wrapper)
66
+ if js_context
67
+ js_context.eval(js_code_wrapper)
68
+ else
69
+ ExecJS.eval(js_code_wrapper)
70
+ end
76
71
  end
77
72
 
78
73
  def self.wrap_code_with_exception_handler(js_code, component_name)
79
74
  <<-JS
80
- try {
81
- #{js_code}
82
- }
83
- catch(e) {
84
- var lineOne =
85
- 'ERROR: You specifed the option generator_function (could be in your defaults) to be\\n';
86
- var lastLine =
87
- 'A generator function takes a single arg of props and returns a ReactElement.';
88
-
89
- var msg = '';
90
- var shouldBeGeneratorError = lineOne +
91
- 'false, but the react component \\'#{component_name}\\' seems to be a generator function.\\n' +
92
- lastLine;
93
- var reMatchShouldBeGeneratorError = /Can't add property context, object is not extensible/;
94
- if (reMatchShouldBeGeneratorError.test(e.message)) {
95
- msg += shouldBeGeneratorError + '\\n\\n';
75
+ try {
76
+ #{js_code}
77
+ }
78
+ catch(e) {
79
+ var lineOne =
80
+ 'ERROR: You specifed the option generator_function (could be in your defaults) to be\\n';
81
+ var lastLine =
82
+ 'A generator function takes a single arg of props and returns a ReactElement.';
83
+
84
+ var msg = '';
85
+ var shouldBeGeneratorError = lineOne +
86
+ 'false, but the react component \\'#{component_name}\\' seems to be a generator function.\\n' +
87
+ lastLine;
88
+ var reMatchShouldBeGeneratorError = /Can't add property context, object is not extensible/;
89
+ if (reMatchShouldBeGeneratorError.test(e.message)) {
90
+ msg += shouldBeGeneratorError + '\\n\\n';
96
91
  console.error(shouldBeGeneratorError);
97
- }
98
-
99
- var shouldBeGeneratorError = lineOne +
100
- 'true, but the react component \\'#{component_name}\\' is not a generator function.\\n' +
101
- lastLine;
102
- var reMatchShouldNotBeGeneratorError = /Cannot call a class as a function/;
103
- if (reMatchShouldNotBeGeneratorError.test(e.message)) {
104
- msg += shouldBeGeneratorError + '\\n\\n';
92
+ }
93
+
94
+ var shouldBeGeneratorError = lineOne +
95
+ 'true, but the react component \\'#{component_name}\\' is not a generator function.\\n' +
96
+ lastLine;
97
+ var reMatchShouldNotBeGeneratorError = /Cannot call a class as a function/;
98
+ if (reMatchShouldNotBeGeneratorError.test(e.message)) {
99
+ msg += shouldBeGeneratorError + '\\n\\n';
105
100
  console.error(shouldBeGeneratorError);
106
- }
107
-
108
- console.error('SERVER SIDE: Exception in server side rendering!');
109
- if (e.fileName) {
110
- console.error('SERVER SIDE: location: ' + e.fileName + ':' + e.lineNumber);
111
- }
112
- console.error('SERVER SIDE: message: ' + e.message);
113
- console.error('SERVER SIDE: stack: ' + e.stack);
114
- msg += 'SERVER SIDE Exception in rendering!\\n' +
115
- (e.fileName ? '\\nlocation: ' + e.fileName + ':' + e.lineNumber : '') +
116
- '\\nMessage: ' + e.message + '\\n\\n' + e.stack;
117
-
118
- var reactElement = React.createElement('pre', null, msg);
119
- result = React.renderToString(reactElement);
120
101
  }
102
+
103
+ console.error('SERVER SIDE: Exception in server side rendering!');
104
+ if (e.fileName) {
105
+ console.error('SERVER SIDE: location: ' + e.fileName + ':' + e.lineNumber);
106
+ }
107
+ console.error('SERVER SIDE: message: ' + e.message);
108
+ console.error('SERVER SIDE: stack: ' + e.stack);
109
+ msg += 'SERVER SIDE Exception in rendering!\\n' +
110
+ (e.fileName ? '\\nlocation: ' + e.fileName + ':' + e.lineNumber : '') +
111
+ '\\nMessage: ' + e.message + '\\n\\n' + e.stack;
112
+
113
+ var reactElement = React.createElement('pre', null, msg);
114
+ result = React.renderToString(reactElement);
115
+ }
121
116
  JS
122
117
  end
123
118
 
@@ -127,9 +122,29 @@ if (history && history.length > 0) {
127
122
  @replay_console ? CONSOLE_REPLAY : ""
128
123
  end
129
124
 
130
- def bundle_js_code
131
- js_file = Rails.root.join(ReactOnRails.configuration.server_bundle_js_file)
132
- File.read(js_file)
125
+ def base_js_code(bundle_js_code)
126
+ <<-JS
127
+ #{CONSOLE_POLYFILL}
128
+ #{bundle_js_code};
129
+ JS
130
+ end
131
+
132
+ def js_context
133
+ if @js_context.nil?
134
+ @js_context = begin
135
+ server_js_file = ReactOnRails.configuration.server_bundle_js_file
136
+ if server_js_file.present? && File.exist?(server_js_file)
137
+ bundle_js_code = File.read(server_js_file)
138
+ ExecJS.compile(base_js_code(bundle_js_code))
139
+ else
140
+ if server_js_file.present?
141
+ Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
142
+ end
143
+ false # using false so we don't try every time if no server_js file
144
+ end
145
+ end
146
+ end
147
+ @js_context
133
148
  end
134
149
  end
135
150
  end
@@ -1,3 +1,3 @@
1
1
  module ReactOnRails
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -25,5 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "bundler", "~> 1.10"
26
26
  spec.add_development_dependency "rake", "~> 10.0"
27
27
  spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "rubocop"
28
29
  spec.add_development_dependency "coveralls"
29
30
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: coveralls
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +115,7 @@ executables: []
101
115
  extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
118
+ - ".babelrc"
104
119
  - ".coveralls.yml"
105
120
  - ".eslintignore"
106
121
  - ".eslintrc"