react_on_rails 0.1.8 → 1.0.0.pre

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: bc9e4d7fb4efbba5c82f8c056cdc4a25dfd66752
4
- data.tar.gz: 4a06b66bf0a5d1b7e88e3bc78d573aafab298994
3
+ metadata.gz: b275f388735a62982a5056840c44bf0779da6636
4
+ data.tar.gz: 27d0bfbe15a24476c55c9ba6fa8973213e875f1a
5
5
  SHA512:
6
- metadata.gz: 4deb110a525ad5bfd570a55ccdedf03807b1cd743126b479773d8d5431e9f4ce5e23204efa881af86b2fc38175c4e27164f98ff79c7489ca0c18b0cb3bf8b943
7
- data.tar.gz: 75de61e4804311370c9c86370b079a0456a74e0d638416bf7a65c1333d09a15d745513f090441725ae74d249b15b8b803b5c7692a96d7887729c1ad06b86c789
6
+ metadata.gz: 168fd64398f5d3e015401652ce81e60fca5a083500cee3bf4645898476fdbc7161f912fe59362e73f633f889f3976de8ff332809a375e9260526b568dd7f4b94
7
+ data.tar.gz: bccaeff6f9225a65e246c9eeef5a48d97dcb1e8d96acba82afcd8719690eb095d4d1f8a1a577cf896b4ef540150519adc2fe895e8c0cf71e07f95046b846c795
data/.gitignore CHANGED
@@ -11,8 +11,11 @@
11
11
 
12
12
  /spec/dummy/client/node_modules
13
13
  /spec/dummy/app/assets/javascripts/generated/
14
+ /spec/dummy-react-013/client/node_modules
15
+ /spec/dummy-react-013/app/assets/javascripts/generated/
14
16
 
15
17
  # RVM
16
18
  .ruby-version
17
19
  .ruby-gemset
18
20
 
21
+ node_modules
data/.jscsrc CHANGED
@@ -1,5 +1,7 @@
1
1
  {
2
2
  "preset": "airbnb",
3
3
  "fileExtensions": [".js", ".jsx"],
4
- "excludeFiles": ["build/**", "node_modules/**"]
4
+ "excludeFiles": ["**/build/**", "**/node_modules/**", "**/generated/**", "**/docs/**", "**/tmp/**", "**/sample_generated/**"],
5
+ "requireTrailingComma": { ignoreSingleValue: true, ignoreSingleLine: true },
6
+ "validateQuoteMarks": false
5
7
  }
@@ -37,13 +37,17 @@ Lint/HandleExceptions:
37
37
 
38
38
  # Offense count: 1
39
39
  Metrics/AbcSize:
40
- Max: 18
40
+ Max: 23
41
41
 
42
42
  # Offense count: 1
43
43
  # Configuration parameters: CountComments.
44
44
  Metrics/ClassLength:
45
45
  Max: 114
46
46
 
47
+ Metrics/ParameterLists:
48
+ Max: 5
49
+ CountKeywordArgs: false
50
+
47
51
  # Offense count: 9
48
52
  # Configuration parameters: CountComments.
49
53
  Metrics/MethodLength:
@@ -52,11 +56,12 @@ Metrics/MethodLength:
52
56
  # Offense count: 1
53
57
  # Configuration parameters: CountComments.
54
58
  Metrics/ModuleLength:
55
- Max: 119
59
+ Max: 110
56
60
 
57
61
  # Offense count: 3
58
62
  # Configuration parameters: AllowedVariables.
59
63
  Style/GlobalVars:
60
64
  Exclude:
61
65
  - 'spec/dummy/config/environments/development.rb'
66
+ - 'spec/dummy-react-013/config/environments/development.rb'
62
67
 
@@ -1,12 +1,34 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.2.2
4
+
4
5
  gemfile:
5
6
  - spec/dummy/Gemfile
6
- install: bundle install
7
+
8
+ env:
9
+ - export RAILS_ENV=test
10
+
11
+ install:
12
+ - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install 4.2.0
13
+ - npm install -g npm
14
+ - bundle install
15
+ - cd spec/dummy/client && npm install
16
+ - $(npm bin)/webpack --config webpack.server.js
17
+ - $(npm bin)/webpack --config webpack.client.js
18
+ - cd ../../dummy-react-013/client && npm install
19
+ - $(npm bin)/webpack --config webpack.server.js
20
+ - $(npm bin)/webpack --config webpack.client.js
21
+
22
+ before_script:
23
+ - cd ../../
24
+ - export DISPLAY=:99.0
25
+ - sh -e /etc/init.d/xvfb start
26
+
7
27
  script:
8
28
  - rake run_rspec:gem
9
- - rake run_rspec:dummy
29
+ - DRIVER=selenium_firefox rake run_rspec:dummy
30
+ - DRIVER=selenium_firefox rake run_rspec:dummy_react_013
31
+
10
32
  notifications:
11
33
  slack:
12
34
  secure: LfcUk4AJ4vAxWwRIyw4tFh8QNbYefMwfG/oLfsN3CdRMWMOtCOHR1GGsRhAOlfVVJ/FvHqVqWj5gK7z7CaO5Uvl7rD3/zJ8QzExKx/iH9yWj55iIPuKLzwFNnBwRpFW/cqyU2lFPPRxGD50BUn3c+qybkuSqtKZ6qtTowwqlxLa5iyM3N95aZp7MEIKCP7cPcnHfLbJyP8wBpotp/rtw62eXM2HIRJJwgjcp+n+My7VFR9DnBXNFf6R91aZHM4U4cHHDbu15HFtH8honVrzK1JQdyqMNHga+j04dFuaS7z9Q369/hsELMOBp/227+Pz7ZRfWZFK4UASguOvyeX7RmGTRpTuWLm1XJeUzfsPZVROecaSVQBve+U7F12yKqilt97QlvRXn2EGyBILqvxtFNNR4S9kgAf72/6EFgiM1TKq7i9zy6lVOnagU2+7amq7UeopX1uoFsUfNKMR7YbgV1WjF0IK95UP0b0/7ZOJlPYgi5zzkQi129qAFWSMmxGk+ZpsttHh/tjJtvAh0A3mHq/zb5w4ub/MbSyZqeDUNgGj72QArOWUFSAStQT1ybsVLeDoKPgOvVq7OV1D64rpcHjBXcqOCit8tDZ+TqkFhcYJo2cITSaqE4zJXn+4F5s7So5O8CyfKYQq+kFJCooYGmfgTUckJpGl7eIvKmL4TN9Q=
data/README.md CHANGED
@@ -5,56 +5,129 @@
5
5
 
6
6
  Gem Published: https://rubygems.org/gems/react_on_rails
7
7
 
8
- See [Action Plan for v1.0](https://github.com/shakacode/react_on_rails/issues/1)
8
+ Live example, including server rendering + redux: http://www.reactrails.com/
9
+ Sponsored by [ShakaCode.com](http://www.shakacode.com/)
9
10
 
10
- Feedback and pull-requests encouraged! Thanks in advance!
11
+ See [Action Plan for v1.0](https://github.com/shakacode/react_on_rails/issues/1). We're ready v1.0.
12
+
13
+ Feedback and pull-requests encouraged! Thanks in advance! We've got a private slack channel to discuss react + webpack + rails. [Email us for an invite contact@shakacode.com](mailto: contact@shakacode.com).
11
14
 
12
15
  Supports:
13
16
 
14
17
  1. Rails
15
18
  2. Webpack
16
- 3. React
19
+ 3. React, both v0.14 and v0.13.
17
20
  4. Redux
18
21
  5. Turbolinks
19
22
  6. Server side rendering with fragment caching
20
- 7. react-router for client side rendering (and maybe server side eventually)
23
+ 7. react-router for client side rendering (and server side very soon)
21
24
 
22
25
  ## OPEN ISSUES
23
- 1. We've got many open issues. However, none of these should stop you from using this gem if you're using React + Webpack with Rails, especially if you are client rendering.
24
- 2. Almost all the open issues are nice to haves like more tests, or some things that would be nice to have for server rendering.
25
- 3. If you want to work on any of the open issues, please comment on the issue. My team is mentoring anybody that's trying to help with the issues. We've got a private slack room for discussing React + Webpack with Rails.
26
- 4. Longer term, we hope to put in many conveniences into this gem, in terms of Webpack + Rails integration.
26
+ 1. Almost all the open issues are nice to haves like more tests.
27
+ 2. If you want to work on any of the open issues, please comment on the issue. My team is mentoring anybody that's trying to help with the issues.
28
+ 3. Longer term, we hope to put in many conveniences into this gem, in terms of Webpack + Rails integration. We're open to suggestions.
27
29
 
28
30
  ## Links
29
- 1. https://github.com/justin808/react-webpack-rails-tutorial/ See https://github.com/shakacode/react-webpack-rails-tutorial/pull/84 for how we integrated it!
31
+ 1. See https://github.com/shakacode/react-webpack-rails-tutorial/ for how to integrate it!
30
32
  2. http://www.railsonmaui.com/blog/2014/10/03/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
31
- 3. http://forum.railsonmaui.com
32
- 4. Interested in consulting for implementing React with Rails, [email us! contact@shakacode.com](mailto: contact@shakacode.com).
33
- 5. If this project is interesting to you, [email us! contact@shakacode.com](mailto: contact@shakacode.com). We're looking for great
34
- developers that want to work with Rails + React with a distributed, worldwide team, for our own
35
- products, client work, and open source.
33
+ 3. http://forum.shakacode.com
34
+ 4. If you're looking for consulting on a project using React and Rails, [email us! contact@shakacode.com](mailto: contact@shakacode.com)? You can first join our slack room for some free advice.
35
+ 5. We're looking for great developers that want to work with Rails + React with a distributed, worldwide team, for our own
36
+ products, client work, and open source. [More info here](http://www.shakacode.com/about/index.html#work-with-us).
36
37
 
37
38
  ## How is different than the [react-rails gem](https://github.com/reactjs/react-rails)?
38
39
  1. `react_on_rails` depends on [webpack](http://webpack.github.io/). `react-rails` integrates closely with sprockets and
39
40
  helps you integrate JSX and the react code into a Rails project.
40
- 2. Likewise, using Webpack as show in the [react-webpack-rails-tutorial](https://github.com/justin808/react-webpack-rails-tutorial/)
41
+ 2. Likewise, using Webpack as shown in the [react-webpack-rails-tutorial](https://github.com/justin808/react-webpack-rails-tutorial/)
41
42
  does involve some extra setup. However, we feel that tight and simple integration with the node ecosystem is more than
42
43
  worth any minor setup costs.
43
44
  3. `react-rails` depends on `jquery-ujs` for client side rendering. `react_on_rails` has it's own JS code that does not
44
45
  depend on jquery.
45
46
 
46
- ## Application Installation
47
+ ## Installation Checklist
48
+ 1. Include the gems `react_on_rails` and `therubyracer` like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/361f4338ebb39a5d3934b00cb6d6fcf494773000/Gemfile#L42) and run `bundle`. Note, you can sustitute your preferable JavaScript engine.
49
+
50
+ ```ruby
51
+ gem "react_on_rails"
52
+ gem "therubyracer"
53
+ ```
54
+ 1. Globally expose React in your webpack config like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.client.base.config.js#L31):
55
+
56
+ ```javascript
57
+ module: {
58
+ loaders: [
59
+ // React is necessary for the client rendering:
60
+ {test: require.resolve('react'), loader: 'expose?React'},
61
+ ```
62
+ 1. Require `react_on_rails` in your `application.js` like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/361f4338ebb39a5d3934b00cb6d6fcf494773000/app/assets/javascripts/application.js#L15). It possibly should come after you require `turbolinks`:
63
+
64
+ ```
65
+ //= require react_on_rails
66
+ ```
67
+ 1. Expose your client globals like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/app/startup/clientGlobals.jsx#L3):
68
+
69
+ ```javascript
70
+ import App from './ClientApp';
71
+ window.App = App;
72
+ ```
73
+ 1. Put your client globals file as webpack entry points like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.client.rails.config.js#L22). Similar pattern for server rendering.
74
+
75
+ ```javascript
76
+ config.entry.app.push('./app/startup/clientGlobals');
77
+ ```
78
+ 1. See customization of configuration options below.
47
79
 
48
- Add these lines to your application's Gemfile, sustituting your preferable JavaScript engine.
80
+ ### Additional Steps For Server Rendering (option `prerender` shown below)
81
+ See the next section for a sample webpack.server.rails.config.js.
82
+ 1. Expose your server globals like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/app/startup/serverGlobals.jsx#L7)
83
+
84
+ ```javascript
85
+ import App from './ServerApp';
86
+ global.App = App;
87
+ ```
88
+ 2. Make the server globals file an entry point in your webpack config, like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.server.rails.config.js#L7)
49
89
 
50
- ```ruby
51
- gem "react_on_rails"
52
- gem "therubyracer"
53
- ```
90
+ ```javascript
91
+ entry: ['./app/startup/serverGlobals'],
92
+ ```
93
+ 3. Ensure the name of your ouput file (shown [here](https://github.com/shakacode/react-webpack-rails-tutorial/blob/537c985dc82faee333d80509343ca32a3965f9dd/client/webpack.server.rails.config.js#L9)) of your server bundle corresponds to the configuration of the gem. The default path is `app/assets/javascripts/generated`. See below for customization of configuration variables.
94
+ 4. Expose `React` in your webpack config, like [this](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/client/webpack.server.rails.config.js#L23)
54
95
 
55
- And then execute:
96
+ #### Sample webpack.server.rails.config.js (ONLY for server rendering)
97
+ Be sure to check out the latest example version of [client/webpack.server.rails.config.js](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/client/webpack.server.rails.config.js).
56
98
 
57
- $ bundle
99
+ ```javascript
100
+ // Common webpack configuration for server bundle
101
+
102
+ module.exports = {
103
+
104
+ // the project dir
105
+ context: __dirname,
106
+ entry: ['./app/startup/serverGlobals'],
107
+ output: {
108
+ filename: 'server-bundle.js',
109
+ path: '../app/assets/javascripts/generated',
110
+
111
+ // CRITICAL to set libraryTarget: 'this' for enabling Rails to find the exposed modules IF you
112
+ // use the "expose" webpackfunctionality. See startup/serverGlobals.jsx.
113
+ // NOTE: This is NOT necessary if you use the syntax of global.MyComponent = MyComponent syntax.
114
+ // See http://webpack.github.io/docs/configuration.html#externals for documentation of this option
115
+ //libraryTarget: 'this',
116
+ },
117
+ resolve: {
118
+ extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', 'config.js'],
119
+ },
120
+ module: {
121
+ loaders: [
122
+ {test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/},
123
+
124
+ // React is necessary for the client rendering:
125
+ { test: require.resolve('react'), loader: 'expose?React' },
126
+ { test: require.resolve('react-dom/server'), loader: 'expose?ReactDOMServer' },
127
+ ],
128
+ },
129
+ };
130
+ ```
58
131
 
59
132
  ## What Happens?
60
133
 
@@ -100,8 +173,12 @@ Params are:
100
173
  If you're curious as to what the gem generates for the server and client rendering, see [`spec/dummy/client/app/startup/serverGlobals.jsx`](https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/spec/sample_generated_js/server-generated.js)
101
174
  and [`spec/dummy/client/app/startup/ClientReduxApp.jsx`](https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/spec/sample_generated_js/client-generated.js) for examples of this. Note, this is not the code that you are providing. You can see the client code by viewing the page source.
102
175
 
103
- * **props**: [hash] Properties to pass to the react object
176
+ * **props**: [hash | string of json] Properties to pass to the react object. See this example if you're using Jbuilder: [react-webpack-rails-tutorial view rendering props using jBuilder](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/app/views/pages/index.html.erb#L20)
104
177
 
178
+ ```erb
179
+ <%= react_component('App', render(template: "/comments/index.json.jbuilder"),
180
+ generator_function: true, prerender: true) %>
181
+ ```
105
182
  * **options:** [hash]
106
183
  * **generator_function**: <true/false> default is false, set to true if you want to use a generator function rather than a React Component.
107
184
  * **prerender**: <true/false> set to false when debugging!
@@ -238,81 +315,24 @@ gem "therubyracer"
238
315
  * [Charlie Marsh's article "Rendering React Components on the Server"](http://www.crmarsh.com/react-ssr/)
239
316
  * [Node globals](https://nodejs.org/api/globals.html#globals_global)
240
317
 
241
-
242
- ## Development Setup for Gem Contributors
243
-
244
- ### Initial Setup
245
- After checking out the repo, making sure you have rvm and nvm setup (setup ruby and node),
246
- cd to `spec/dummy` and run `bin/setup` to install dependencies.
247
- You can also run `bin/console` for an interactive prompt that will allow you to experiment.
248
-
249
- ### Starting the Dummy App
250
- To run the test app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start`.
251
- If you don't do this, then `webpack` will not generate a new bundle,
252
- and you will be seriously confused when you change JavaScript and the app does not change.
253
-
254
- ### Install and Release
255
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
256
- update the version number in `version.rb`, and then run `bundle exec rake release`,
257
- which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
258
-
259
- ### RSpec Testing
260
- Run `rake` for testing the gem and `spec/dummy`. Otherwise, the `rspec` command only works for testing within `spec/dummy`.
261
-
262
- If you run `rspec` at the top level, you'll see this message: `require': cannot load such file -- rails_helper (LoadError)`
263
-
264
- ### Debugging
265
- Start the sample app like this for some debug printing:
266
- ```bash
267
- TRACE_REACT_ON_RAILS=true && foreman start
268
- ```
269
-
270
318
  ### Generated JavaScript
271
319
 
272
320
  1. See spec/dummy/spec/sample_generated_js/server-generated.js to see the JavaScript for typical server rendering.
273
321
  2. See spec/dummy/spec/sample_generated_js/client-generated.js to see the JavaScript for typical client rendering.
274
322
 
275
- ### Linting
276
- All linting is performed from the docker container. You will need docker and docker-compose installed
277
- locally to lint code changes via the lint container.
278
-
279
- * [Install Docker Toolbox for Mac](https://www.docker.com/toolbox)
280
- * [Install Docker Compose for Linux](https://docs.docker.com/compose/install/)
281
-
282
- Once you have docker and docker-compose running locally, run `docker-compose build lint`. This will build
283
- the `reactonrails_lint` docker image and docker-compose `lint` container. The inital build is slow,
284
- but after the install, startup is very quick.
285
-
286
- ### Linting Commands
287
- Run `rake -D docker` to see all docker linting commands for rake. `rake docker` will run all linters.
288
- For individual rake linting commands please refer to `rake -D docker` for the list.
289
- You can run specfic linting for directories or files by using `docker-compose run lint rubocop (file path or directory)`, etc.
290
- `docker-compose run lint /bin/bash` sets you up to run from the container command line.
291
-
292
323
  ## Contributing
293
324
 
294
325
  Bug reports and pull requests are welcome on GitHub at https://github.com/shakacode/react_on_rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
295
326
 
327
+ More [tips on contributing here](docs/Contributing.md)
328
+
296
329
  ## License
297
330
 
298
331
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
299
332
 
300
- ## Updating New Versions of the Gem
301
-
302
- See https://github.com/svenfuchs/gem-release
303
-
304
- ```bash
305
- gem bump
306
- cd spec/dummy
307
- bundle
308
- git commit -am "Updated Gemfile.lock"
309
- cd ../..
310
- gem tag
311
- gem release
312
- ```
313
-
314
333
  # Authors
315
- The Shaka Code team!
334
+
335
+ [The Shaka Code team!](http://www.shakacode.com/about/)
316
336
 
317
337
  1. [Justin Gordon](https://github.com/justin808/)
318
338
  2. [Samnang Chhun](https://github.com/samnang)
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ 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 spec/react_on_rails_spec.rb )
7
7
  end
8
8
 
9
9
  desc "Run RSpec for spec/dummy only"
@@ -11,7 +11,12 @@ namespace :run_rspec do
11
11
  sh %( cd spec/dummy && rspec )
12
12
  end
13
13
 
14
- task run_rspec: [:gem, :dummy] do
14
+ desc "Run RSpec for spec/dummy only"
15
+ task :dummy_react_013 do
16
+ sh %( cd spec/dummy-react-013 && rspec )
17
+ end
18
+
19
+ task run_rspec: [:gem, :dummy, :dummy_react_013] do
15
20
  puts "Completed all RSpec tests"
16
21
  end
17
22
  end
@@ -43,13 +48,15 @@ namespace :lint do
43
48
 
44
49
  desc "Run jscs from shell"
45
50
  task :jscs do
46
- sh "jscs -e ."
51
+ sh "jscs -e -v ."
47
52
  end
48
53
 
49
- task lint: [:eslint, :rubocop, :ruby, :jscs, :scss] do
54
+ desc "Run all eslint, jscs, rubocop linters. Skip ruby-lint and scss"
55
+ task lint: [:eslint, :jscs, :rubocop] do
50
56
  puts "Completed all linting"
51
57
  end
52
58
  end
59
+
53
60
  desc "Runs all linters. Run `rake -D lint` to see all available lint options"
54
61
  task lint: ["lint:lint"]
55
62
 
@@ -86,3 +93,6 @@ end
86
93
 
87
94
  desc "Runs all linters from docker. Run `rake -D docker` to see all available lint options"
88
95
  task docker: ["docker:lint"]
96
+
97
+ desc "Run all tests and linting"
98
+ task ci: %w(docker run_rspec)
@@ -18,36 +18,42 @@
18
18
  if (domNode) {
19
19
  var reactElement = createReactElement(componentName, propsVarName, props,
20
20
  domId, trace, generatorFunction);
21
- React.render(reactElement, domNode);
21
+ provideClientReact().render(reactElement, domNode);
22
22
  }
23
23
  }
24
24
  catch (e) {
25
- handleError(e, componentName);
25
+ ReactOnRails.handleError({
26
+ e: e,
27
+ componentName: componentName,
28
+ serverSide: false,
29
+ });
26
30
  }
27
31
  };
28
32
 
29
- var turbolinksInstalled = typeof(Turbolinks) !== 'undefined';
33
+ var turbolinksInstalled = (typeof Turbolinks !== 'undefined');
30
34
  if (!expectTurboLinks || (!turbolinksInstalled && expectTurboLinks)) {
31
35
  if (expectTurboLinks) {
32
- console.warn("WARNING: NO TurboLinks detected in JS, but it's in your Gemfile");
36
+ console.warn('WARNING: NO TurboLinks detected in JS, but it is in your Gemfile');
33
37
  }
34
- document.addEventListener("DOMContentLoaded", function(event) {
38
+
39
+ document.addEventListener('DOMContentLoaded', function(event) {
35
40
  renderIfDomNodePresent();
36
41
  });
37
42
  } else {
38
43
  function onPageChange(event) {
39
44
  var removePageChangeListener = function() {
40
- document.removeEventListener("page:change", onPageChange);
41
- document.removeEventListener("page:before-unload", removePageChangeListener);
45
+ document.removeEventListener('page:change', onPageChange);
46
+ document.removeEventListener('page:before-unload', removePageChangeListener);
42
47
  var domNode = document.getElementById(domId);
43
- React.unmountComponentAtNode(domNode);
48
+ provideClientReact().unmountComponentAtNode(domNode);
44
49
  };
45
- document.addEventListener("page:before-unload", removePageChangeListener);
50
+
51
+ document.addEventListener('page:before-unload', removePageChangeListener);
46
52
 
47
53
  renderIfDomNodePresent();
48
54
  }
49
55
 
50
- document.addEventListener("page:change", onPageChange);
56
+ document.addEventListener('page:change', onPageChange);
51
57
  }
52
58
  };
53
59
 
@@ -65,31 +71,27 @@
65
71
  try {
66
72
  var reactElement = createReactElement(componentName, propsVarName, props,
67
73
  domId, trace, generatorFunction);
68
- htmlResult = React.renderToString(reactElement);
74
+ htmlResult = provideServerReact().renderToString(reactElement);
69
75
  }
70
76
  catch (e) {
71
- htmlResult = handleError(e, componentName);
77
+ htmlResult = ReactOnRails.handleError({
78
+ e: e,
79
+ componentName: componentName,
80
+ serverSide: true,
81
+ });
72
82
  }
73
83
 
74
84
  consoleReplay = ReactOnRails.buildConsoleReplay();
75
85
  return JSON.stringify([htmlResult, consoleReplay]);
76
86
  };
77
87
 
78
- function createReactElement(componentName, propsVarName, props, domId, trace, generatorFunction) {
79
- if (trace) {
80
- console.log('RENDERED ' + componentName + ' with data_variable ' +
81
- propsVarName + ' to dom node with id: ' + domId);
82
- }
83
-
84
- if (generatorFunction) {
85
- return this[componentName](props);
86
- } else {
87
- return React.createElement(this[componentName], props);
88
- }
89
- }
90
-
91
88
  // Passing either componentName or jsCode
92
- function handleError(e, componentName, jsCode) {
89
+ ReactOnRails.handleError = function(options) {
90
+ var e = options.e;
91
+ var componentName = options.componentName;
92
+ var jsCode = options.jsCode;
93
+ var serverSide = options.serverSide;
94
+
93
95
  var lineOne =
94
96
  'ERROR: You specified the option generator_function (could be in your defaults) to be\n';
95
97
  var lastLine =
@@ -125,15 +127,17 @@
125
127
  if (e.fileName) {
126
128
  console.error('location: ' + e.fileName + ':' + e.lineNumber);
127
129
  }
130
+
128
131
  console.error('message: ' + e.message);
129
132
  console.error('stack: ' + e.stack);
130
- msg += 'Exception in rendering!\n' +
131
- (e.fileName ? '\nlocation: ' + e.fileName + ':' + e.lineNumber : '') +
132
- '\nMessage: ' + e.message + '\n\n' + e.stack;
133
-
134
- var reactElement = React.createElement('pre', null, msg);
135
- return React.renderToString(reactElement);
136
- }
133
+ if (serverSide) {
134
+ msg += 'Exception in rendering!\n' +
135
+ (e.fileName ? '\nlocation: ' + e.fileName + ':' + e.lineNumber : '') +
136
+ '\nMessage: ' + e.message + '\n\n' + e.stack;
137
+ var reactElement = React.createElement('pre', null, msg);
138
+ return provideServerReact().renderToString(reactElement);
139
+ }
140
+ };
137
141
 
138
142
  ReactOnRails.buildConsoleReplay = function() {
139
143
  var consoleReplay = '';
@@ -145,9 +149,39 @@
145
149
  consoleReplay += '\nconsole.' + msg.level + '.apply(console, ' +
146
150
  JSON.stringify(msg.arguments) + ');';
147
151
  });
152
+
148
153
  consoleReplay += '\n</script>';
149
154
  }
150
155
 
151
156
  return consoleReplay;
157
+ };
158
+
159
+ function createReactElement(componentName, propsVarName, props, domId, trace, generatorFunction) {
160
+ if (trace) {
161
+ console.log('RENDERED ' + componentName + ' with data_variable ' +
162
+ propsVarName + ' to dom node with id: ' + domId);
163
+ }
164
+
165
+ if (generatorFunction) {
166
+ return this[componentName](props);
167
+ } else {
168
+ return React.createElement(this[componentName], props);
169
+ }
170
+ }
171
+
172
+ function provideClientReact() {
173
+ if (typeof ReactDOM === 'undefined') {
174
+ return React;
175
+ }
176
+
177
+ return ReactDOM;
178
+ }
179
+
180
+ function provideServerReact() {
181
+ if (typeof ReactDOMServer === 'undefined') {
182
+ return React;
183
+ }
184
+
185
+ return ReactDOMServer;
152
186
  }
153
187
  }.call(this));
@@ -53,7 +53,7 @@ module ReactOnRailsHelper
53
53
  data_variable_name = "__#{component_name.camelize(:lower)}Data#{react_component_index}__"
54
54
  turbolinks_loaded = Object.const_defined?(:Turbolinks)
55
55
  # NOTE: props might include closing script tag that might cause XSS
56
- props_string = props.is_a?(String) ? props : props.to_json
56
+ props_string = sanitized_props_string(props)
57
57
  page_loaded_js = <<-JS
58
58
  (function() {
59
59
  window.#{data_variable_name} = #{props_string};
@@ -89,10 +89,14 @@ module ReactOnRailsHelper
89
89
  <<-HTML.html_safe
90
90
  #{data_from_server_script_tag}
91
91
  #{rendered_output}
92
- #{replay_console(options) ? console_script : ""}
92
+ #{replay_console(options) ? console_script : ''}
93
93
  HTML
94
94
  end
95
95
 
96
+ def sanitized_props_string(props)
97
+ props.is_a?(String) ? json_escape(props) : props.to_json
98
+ end
99
+
96
100
  # Helper method to take javascript expression and returns the output from evaluating it.
97
101
  # If you have more than one line that needs to be executed, wrap it in an IIFE.
98
102
  # JS exceptions are caught and console messages are handled properly.
@@ -108,7 +112,8 @@ module ReactOnRailsHelper
108
112
  return #{js_expression};
109
113
  })();
110
114
  } catch(e) {
111
- htmlResult = handleError(e, null, '#{escape_javascript(js_expression)}');
115
+ htmlResult = ReactOnRails.handleError({e: e, componentName: null,
116
+ jsCode: '#{escape_javascript(js_expression)}', serverSide: true});
112
117
  }
113
118
 
114
119
  consoleReplay = ReactOnRails.buildConsoleReplay();
@@ -117,7 +122,12 @@ module ReactOnRailsHelper
117
122
  JS
118
123
 
119
124
  result = ReactOnRails::ServerRenderingPool.server_render_js_with_console_logging(wrapper_js)
120
- "#{result[0]}\n#{result[1]}".html_safe
125
+
126
+ # IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
127
+ <<-HTML.html_safe
128
+ #{result[0]}
129
+ #{replay_console(options) ? result[1] : ''}
130
+ HTML
121
131
  end
122
132
 
123
133
  private
@@ -0,0 +1,66 @@
1
+ # Tips for Contributors
2
+
3
+ ## Development Setup for Gem Contributors
4
+
5
+ ### Checklist before Committing
6
+ 1. `rake ci`: runs all linters and specs (you need Docker setup, see below)
7
+ 2. Did you need any more tests for your change?
8
+ 3. Did you document your change? Update the README.md?
9
+
10
+ ### Initial Setup
11
+ After checking out the repo, making sure you have rvm and nvm setup (setup ruby and node),
12
+ cd to `spec/dummy` and run `bin/setup` to install dependencies.
13
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
14
+
15
+ ### Starting the Dummy App
16
+ To run the test app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start`.
17
+ If you don't do this, then `webpack` will not generate a new bundle,
18
+ and you will be seriously confused when you change JavaScript and the app does not change.
19
+
20
+ ### Install and Release
21
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
22
+ update the version number in `version.rb`, and then run `bundle exec rake release`,
23
+ which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
24
+
25
+ ### RSpec Testing
26
+ Run `rake` for testing the gem and `spec/dummy` and `spec/dummy-react-013`. Otherwise, the `rspec` command only works for testing within the sample apps, like `spec/dummy`.
27
+
28
+ If you run `rspec` at the top level, you'll see this message: `require': cannot load such file -- rails_helper (LoadError)`
29
+
30
+ ### Debugging
31
+ Start the sample app like this for some debug printing:
32
+ ```bash
33
+ TRACE_REACT_ON_RAILS=true && foreman start
34
+ ```
35
+
36
+
37
+ ## Updating New Versions of the Gem
38
+
39
+ See https://github.com/svenfuchs/gem-release
40
+
41
+ ```bash
42
+ gem bump
43
+ cd spec/dummy
44
+ bundle
45
+ git commit -am "Updated Gemfile.lock"
46
+ cd ../..
47
+ gem tag
48
+ gem release
49
+ ```
50
+
51
+ ### Linting
52
+ All linting is performed from the docker container. You will need docker and docker-compose installed
53
+ locally to lint code changes via the lint container.
54
+
55
+ * [Install Docker Toolbox for Mac](https://www.docker.com/toolbox)
56
+ * [Install Docker Compose for Linux](https://docs.docker.com/compose/install/)
57
+
58
+ Once you have docker and docker-compose running locally, run `docker-compose build lint`. This will build
59
+ the `reactonrails_lint` docker image and docker-compose `lint` container. The inital build is slow,
60
+ but after the install, startup is very quick.
61
+
62
+ ### Linting Commands
63
+ Run `rake -D docker` to see all docker linting commands for rake. `rake docker` will run all linters.
64
+ For individual rake linting commands please refer to `rake -D docker` for the list.
65
+ You can run specfic linting for directories or files by using `docker-compose run lint rubocop (file path or directory)`, etc.
66
+ `docker-compose run lint /bin/bash` sets you up to run from the container command line.
@@ -0,0 +1 @@
1
+ ## PENDING: ADD DOCS HERE
@@ -0,0 +1,12 @@
1
+ (function() {
2
+ window.__helloWorldData0__ = {"helloWorldData":{"name":"Mr. Server Side Rendering"}};
3
+ ReactOnRails.clientRenderReactComponent({
4
+ componentName: 'HelloWorld',
5
+ domId: 'HelloWorld-react-component-0',
6
+ propsVarName: '__helloWorldData0__',
7
+ props: window.__helloWorldData0__,
8
+ trace: true,
9
+ generatorFunction: false,
10
+ expectTurboLinks: true
11
+ });
12
+ })();
@@ -0,0 +1,11 @@
1
+ (function() {
2
+ var props = {"helloWorldData":{"name":"Mr. Server Side Rendering"}};
3
+ return ReactOnRails.serverRenderReactComponent({
4
+ componentName: 'HelloWorld',
5
+ domId: 'HelloWorld-react-component-0',
6
+ propsVarName: '__helloWorldData0__',
7
+ props: props,
8
+ trace: true,
9
+ generatorFunction: false
10
+ });
11
+ })();
@@ -1,62 +1,20 @@
1
- require 'connection_pool'
1
+ require "connection_pool"
2
2
 
3
- # Based on the react-rails gem
3
+ # Based on the react-rails gem.
4
+ # None of these methods should be called directly.
5
+ # See app/helpers/react_on_rails_helper.rb
4
6
  module ReactOnRails
5
7
  class ServerRenderingPool
6
8
  def self.reset_pool
7
9
  options = { size: ReactOnRails.configuration.server_renderer_pool_size,
8
10
  timeout: ReactOnRails.configuration.server_renderer_pool_size }
9
- @@js_context_pool = ConnectionPool.new(options) { create_js_context }
11
+ @js_context_pool = ConnectionPool.new(options) { create_js_context }
10
12
  end
11
13
 
12
- def self.eval_js(js_code)
13
- @@js_context_pool.with do |js_context|
14
- result = js_context.eval(js_code)
15
- js_context.eval(CLEAR_CONSOLE)
16
- result
17
- end
18
- end
19
-
20
- def self.create_js_context
21
- server_js_file = ReactOnRails.configuration.server_bundle_js_file
22
- if server_js_file.present? && File.exist?(server_js_file)
23
- bundle_js_code = File.read(server_js_file)
24
- base_js_code = <<-JS
25
- #{CONSOLE_POLYFILL}
26
- #{bundle_js_code};
27
- #{::Rails.application.assets['react_on_rails.js'].to_s};
28
- JS
29
- ExecJS.compile(base_js_code)
30
- else
31
- if server_js_file.present?
32
- Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
33
- end
34
- ExecJS.compile("")
35
- end
36
- end
37
-
38
- CLEAR_CONSOLE = <<-JS
39
- console.history = []
40
- JS
41
-
42
- # Reimplement console methods for replaying on the client
43
- CONSOLE_POLYFILL = <<-JS
44
- var console = { history: [] };
45
- ['error', 'log', 'info', 'warn'].forEach(function (level) {
46
- console[level] = function () {
47
- var argArray = Array.prototype.slice.call(arguments);
48
- if (argArray.length > 0) {
49
- argArray[0] = '[SERVER] ' + argArray[0];
50
- }
51
- console.history.push({level: level, arguments: argArray});
52
- };
53
- });
54
- JS
55
-
56
14
  class PrerenderError < RuntimeError
57
15
  def initialize(component_name, props, js_message)
58
16
  message = ["Encountered error \"#{js_message}\" when prerendering #{component_name} with #{props}",
59
- js_message.backtrace.join("\n")].join("\n")
17
+ js_message.backtrace.join("\n")].join("\n")
60
18
  super(message)
61
19
  end
62
20
  end
@@ -69,13 +27,7 @@ var console = { history: [] };
69
27
  # js_code MUST RETURN json stringify array of two elements
70
28
  # Calling code will probably call 'html_safe' on return value before rendering to the view.
71
29
  def self.server_render_js_with_console_logging(js_code)
72
- if ENV["TRACE_REACT_ON_RAILS"].present? # Set to anything to print generated code.
73
- puts "Z" * 80
74
- puts "react_renderer.rb: 92"
75
- puts "wrote file tmp/server-generated.js"
76
- File.write("tmp/server-generated.js", js_code)
77
- puts "Z" * 80
78
- end
30
+ trace_messsage(js_code)
79
31
 
80
32
  json_string = eval_js(js_code)
81
33
  # element 0 is the html, element 1 is the script tag for the server console output
@@ -89,13 +41,67 @@ var console = { history: [] };
89
41
  if console_script_lines
90
42
  console_script_lines.each do |line|
91
43
  match = re.match(line)
92
- if match
93
- Rails.logger.info { "[react_on_rails] #{match[:msg]}" }
94
- end
44
+ Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
95
45
  end
96
46
  end
97
47
  end
98
48
  result
99
49
  end
50
+
51
+ class << self
52
+ private
53
+
54
+ def trace_messsage(js_code)
55
+ return unless ENV["TRACE_REACT_ON_RAILS"].present?
56
+ # Set to anything to print generated code.
57
+ puts "Z" * 80
58
+ puts "react_renderer.rb: 92"
59
+ puts "wrote file tmp/server-generated.js"
60
+ File.write("tmp/server-generated.js", js_code)
61
+ puts "Z" * 80
62
+ end
63
+
64
+ def eval_js(js_code)
65
+ @js_context_pool.with do |js_context|
66
+ result = js_context.eval(js_code)
67
+ js_context.eval("console.history = []")
68
+ result
69
+ end
70
+ end
71
+
72
+ def create_js_context
73
+ server_js_file = ReactOnRails.configuration.server_bundle_js_file
74
+ if server_js_file.present? && File.exist?(server_js_file)
75
+ bundle_js_code = File.read(server_js_file)
76
+ base_js_code = <<-JS
77
+ #{console_polyfill}
78
+ #{bundle_js_code};
79
+ #{::Rails.application.assets['react_on_rails.js']};
80
+ JS
81
+ ExecJS.compile(base_js_code)
82
+ else
83
+ if server_js_file.present?
84
+ Rails.logger.warn("You specified server rendering JS file: #{server_js_file}, but it cannot be read.")
85
+ end
86
+ ExecJS.compile("")
87
+ end
88
+ end
89
+
90
+ # Reimplement console methods for replaying on the client
91
+ def console_polyfill
92
+ <<-JS
93
+ var console = { history: [] };
94
+ ['error', 'log', 'info', 'warn'].forEach(function (level) {
95
+ console[level] = function () {
96
+ var argArray = Array.prototype.slice.call(arguments);
97
+ if (argArray.length > 0) {
98
+ argArray[0] = '[SERVER] ' + argArray[0];
99
+ }
100
+ console.history.push({level: level, arguments: argArray});
101
+ };
102
+ });
103
+ JS
104
+ end
105
+ end
100
106
  end
101
107
  end
@@ -1,3 +1,3 @@
1
1
  module ReactOnRails
2
- VERSION = "0.1.8"
2
+ VERSION = "1.0.0.pre"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 1.0.0.pre
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-29 00:00:00.000000000 Z
11
+ date: 2015-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -148,6 +148,10 @@ files:
148
148
  - app/assets/javascripts/react_on_rails.js
149
149
  - app/helpers/react_on_rails_helper.rb
150
150
  - docker-compose.yml
151
+ - docs/Contributing.md
152
+ - docs/README.md
153
+ - docs/sample_generated_js/client-generated.js
154
+ - docs/sample_generated_js/server-generated.js
151
155
  - lib/react_on_rails.rb
152
156
  - lib/react_on_rails/configuration.rb
153
157
  - lib/react_on_rails/server_rendering_pool.rb
@@ -169,9 +173,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
173
  version: '0'
170
174
  required_rubygems_version: !ruby/object:Gem::Requirement
171
175
  requirements:
172
- - - ">="
176
+ - - ">"
173
177
  - !ruby/object:Gem::Version
174
- version: '0'
178
+ version: 1.3.1
175
179
  requirements: []
176
180
  rubyforge_project:
177
181
  rubygems_version: 2.4.8