react_on_rails 0.1.2 → 0.1.3

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: 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"