react_on_rails 0.1.8 → 1.0.0.pre

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