react_on_rails 5.2.0 → 6.0.0.beta.1

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +31 -0
  5. data/PROJECTS.md +11 -2
  6. data/README.md +33 -203
  7. data/app/helpers/react_on_rails_helper.rb +32 -49
  8. data/docs/additional-reading/heroku-deployment.md +2 -35
  9. data/docs/additional-reading/node-server-rendering.md +30 -0
  10. data/docs/additional-reading/rails-assets.md +19 -0
  11. data/docs/additional-reading/rspec-configuration.md +38 -4
  12. data/docs/additional-reading/webpack-dev-server.md +16 -0
  13. data/docs/additional-reading/webpack.md +0 -10
  14. data/docs/api/javascript-api.md +37 -0
  15. data/docs/api/ruby-api-hot-reload-view-helpers.md +42 -0
  16. data/docs/api/ruby-api.md +3 -0
  17. data/docs/basics/generator.md +49 -0
  18. data/docs/{additional-reading → basics}/installation-overview.md +0 -0
  19. data/docs/basics/migrating-from-react-rails.md +17 -0
  20. data/docs/contributor-info/contributing.md +11 -0
  21. data/docs/{coding-style → contributor-info}/linters.md +0 -0
  22. data/lib/generators/USAGE +3 -95
  23. data/lib/generators/react_on_rails/base_generator.rb +10 -43
  24. data/lib/generators/react_on_rails/dev_tests_generator.rb +17 -1
  25. data/lib/generators/react_on_rails/install_generator.rb +0 -6
  26. data/lib/generators/react_on_rails/react_no_redux_generator.rb +3 -17
  27. data/lib/generators/react_on_rails/react_with_redux_generator.rb +4 -21
  28. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +2 -2
  29. data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +3 -4
  30. data/lib/generators/react_on_rails/templates/base/base/client/app/bundles/HelloWorld/components/HelloWorldWidget.jsx.tt +1 -11
  31. data/lib/generators/react_on_rails/templates/base/base/client/node/package.json +10 -0
  32. data/lib/generators/react_on_rails/templates/base/base/client/node/server.js +82 -0
  33. data/lib/generators/react_on_rails/templates/base/base/client/package.json.tt +3 -20
  34. data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +58 -0
  35. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +60 -26
  36. data/lib/generators/react_on_rails/templates/base/base/lib/tasks/assets.rake.tt +1 -4
  37. data/lib/generators/react_on_rails/templates/base/base/lib/tasks/load_test.rake +8 -0
  38. data/lib/generators/react_on_rails/templates/base/base/package.json.tt +0 -12
  39. data/lib/generators/react_on_rails/templates/dev_tests/spec/features/hello_world_spec.rb +1 -1
  40. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +1 -0
  41. data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/containers/HelloWorld.jsx +1 -7
  42. data/lib/generators/react_on_rails/templates/{base/base/client/app/bundles/HelloWorld/startup/clientRegistration.jsx.tt → no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldApp.jsx.tt} +7 -1
  43. data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/startup/{HelloWorldAppClient.jsx.tt → HelloWorldApp.jsx.tt} +5 -1
  44. data/lib/generators/react_on_rails/templates/redux/base/client/app/bundles/HelloWorld/store/helloWorldStore.jsx +1 -5
  45. data/lib/react_on_rails.rb +2 -1
  46. data/lib/react_on_rails/configuration.rb +17 -5
  47. data/lib/react_on_rails/react_component/options.rb +76 -0
  48. data/lib/react_on_rails/server_rendering_pool.rb +9 -151
  49. data/lib/react_on_rails/server_rendering_pool/exec.rb +166 -0
  50. data/lib/react_on_rails/server_rendering_pool/node.rb +77 -0
  51. data/lib/react_on_rails/test_helper.rb +1 -6
  52. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +4 -77
  53. data/lib/react_on_rails/test_helper/node_process_launcher.rb +12 -0
  54. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +4 -28
  55. data/lib/react_on_rails/version.rb +1 -1
  56. data/lib/tasks/assets.rake +115 -0
  57. data/package.json +2 -1
  58. data/rakelib/example_type.rb +3 -10
  59. data/rakelib/examples_config.yml +2 -2
  60. data/react_on_rails.gemspec +1 -0
  61. metadata +41 -20
  62. data/lib/generators/react_on_rails/templates/base/base/REACT_ON_RAILS.md +0 -16
  63. data/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md +0 -3
  64. data/lib/generators/react_on_rails/templates/base/base/client/webpack.client.base.config.js +0 -65
  65. data/lib/generators/react_on_rails/templates/base/base/client/webpack.client.rails.config.js +0 -53
  66. data/lib/generators/react_on_rails/templates/base/server_rendering/client/app/bundles/HelloWorld/startup/serverRegistration.jsx +0 -4
  67. data/lib/generators/react_on_rails/templates/base/server_rendering/client/webpack.server.rails.config.js +0 -39
  68. data/lib/generators/react_on_rails/templates/no_redux/base/client/app/bundles/HelloWorld/startup/HelloWorldAppClient.jsx.tt +0 -6
  69. data/lib/generators/react_on_rails/templates/no_redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +0 -6
  70. data/lib/generators/react_on_rails/templates/redux/base/client/app/lib/middlewares/loggerMiddleware.js +0 -21
  71. data/lib/generators/react_on_rails/templates/redux/server_rendering/client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx +0 -19
  72. data/lib/react_on_rails/test_helper/webpack_process_checker.rb +0 -54
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "react_on_rails_node",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "start": "node ./server.js -s webpack-bundle.js"
7
+ },
8
+ "dependencies": {
9
+ }
10
+ }
@@ -0,0 +1,82 @@
1
+ var net = require('net');
2
+ var fs = require('fs');
3
+
4
+ var bundlePath = '../../app/assets/webpack/';
5
+ var bundleFileName = 'webpack-bundle.js';
6
+
7
+ var currentArg;
8
+
9
+ function Handler() {
10
+ this.queue = [];
11
+ this.initialized = false;
12
+ }
13
+
14
+ Handler.prototype.handle = function (connection) {
15
+ var callback = function () {
16
+ connection.setEncoding('utf8');
17
+ connection.on('data', (data)=> {
18
+ console.log('Processing request: ' + data);
19
+ var result = eval(data);
20
+ connection.write(result);
21
+ });
22
+ };
23
+
24
+ if (this.initialized) {
25
+ callback();
26
+ } else {
27
+ this.queue.push(callback);
28
+ }
29
+ };
30
+
31
+ Handler.prototype.initialize = function () {
32
+ console.log('Processing ' + this.queue.length + ' pending requests');
33
+ var callback;
34
+ while (callback = this.queue.pop()) {
35
+ callback();
36
+ }
37
+
38
+ this.initialized = true;
39
+ };
40
+
41
+ var handler = new Handler();
42
+
43
+ process.argv.forEach((val) => {
44
+ if (val[0] == '-') {
45
+ currentArg = val.slice(1);
46
+ return;
47
+ }
48
+
49
+ if (currentArg == 's') {
50
+ bundleFileName = val;
51
+ }
52
+ });
53
+
54
+ try {
55
+ fs.mkdirSync(bundlePath);
56
+ } catch (e) {
57
+ if (e.code != 'EEXIST') throw e;
58
+ }
59
+
60
+ fs.watchFile(bundlePath + bundleFileName, (curr) => {
61
+ if (curr && curr.blocks && curr.blocks > 0) {
62
+ if (handler.initialized) {
63
+ console.log('Reloading server bundle must be implemented by restarting the node process!');
64
+ return;
65
+ }
66
+
67
+ require(bundlePath + bundleFileName);
68
+ console.log('Loaded server bundle: ' + bundlePath + bundleFileName);
69
+ handler.initialize();
70
+ }
71
+ });
72
+
73
+ var unixServer = net.createServer(function (connection) {
74
+ handler.handle(connection);
75
+ });
76
+
77
+ unixServer.listen('node.sock');
78
+
79
+ process.on('SIGINT', () => {
80
+ unixServer.close();
81
+ process.exit();
82
+ });
@@ -7,23 +7,11 @@
7
7
  "npm": "3.5.0"
8
8
  },
9
9
  "scripts": {
10
- "build:client": "NODE_ENV=production webpack --config webpack.client.rails.config.js",
11
- <%- if options.server_rendering? -%>
12
- "build:server": "NODE_ENV=production webpack --config webpack.server.rails.config.js",
13
- <%- end -%>
14
- "build:dev:client": "webpack -w --config webpack.client.rails.config.js",
15
- <%- if options.server_rendering? -%>
16
- "build:dev:server": "webpack -w --config webpack.server.rails.config.js",
17
- <%- end -%>
18
- "build:production:client": "NODE_ENV=production webpack --config webpack.client.rails.build.config.js",
19
- <%- if options.server_rendering? -%>
20
- "build:production:server": "NODE_ENV=production webpack --config webpack.server.rails.build.config.js",
21
- <%- end -%>
22
- "test": "echo \"Error: no test specified\" && exit 1"
10
+ "build:test": "webpack --config webpack.config.js",
11
+ "build:production": "NODE_ENV=production webpack --config webpack.config.js",
12
+ "build:development": "webpack -w --config webpack.config.js"
23
13
  },
24
14
  "dependencies": {
25
- "autoprefixer": "^6.3.5",
26
- "axios": "^0.9.1",
27
15
  "babel": "^6.5.2",
28
16
  "babel-cli": "^6.6.5",
29
17
  "babel-core": "^6.7.4",
@@ -33,17 +21,12 @@
33
21
  "babel-preset-es2015": "^6.6.0",
34
22
  "babel-preset-react": "^6.5.0",
35
23
  "babel-preset-stage-0": "^6.5.0",
36
- "css-loader": "^0.23.1",
37
24
  "es5-shim": "^4.5.7",
38
25
  "expose-loader": "^0.7.1",
39
26
  <%- if options.redux? -%>
40
27
  "immutable": "^3.7.6",
41
28
  <%- end -%>
42
29
  "imports-loader": "^0.6.5",
43
- "jquery": "^2.2.2",
44
- "jquery-ujs": "^1.2.1",
45
- "loader-utils": "^0.2.13",
46
- "lodash": "^4.7.0",
47
30
  <%- if options.redux? -%>
48
31
  "mirror-creator": "1.1.0",
49
32
  <%- end -%>
@@ -0,0 +1,58 @@
1
+ const webpack = require('webpack');
2
+ const path = require('path');
3
+
4
+ const devBuild = process.env.NODE_ENV !== 'production';
5
+ const nodeEnv = devBuild ? 'development' : 'production';
6
+
7
+ config = {
8
+ entry: [
9
+ 'es5-shim/es5-shim',
10
+ 'es5-shim/es5-sham',
11
+ 'babel-polyfill',
12
+ './app/bundles/HelloWorld/startup/HelloWorldApp',
13
+ ],
14
+
15
+ output: {
16
+ filename: 'webpack-bundle.js',
17
+ path: '../app/assets/webpack',
18
+ },
19
+
20
+ resolve: {
21
+ extensions: ['', '.js', '.jsx'],
22
+ alias: {
23
+ react: path.resolve('./node_modules/react'),
24
+ 'react-dom': path.resolve('./node_modules/react-dom'),
25
+ },
26
+ },
27
+ plugins: [
28
+ new webpack.DefinePlugin({
29
+ 'process.env': {
30
+ NODE_ENV: JSON.stringify(nodeEnv),
31
+ },
32
+ }),
33
+ ],
34
+ module: {
35
+ loaders: [
36
+ {
37
+ test: require.resolve('react'),
38
+ loader: 'imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham',
39
+ },
40
+ {
41
+ test: /\.jsx?$/, loader: 'babel-loader',
42
+ exclude: /node_modules/,
43
+ },
44
+ ],
45
+ },
46
+ };
47
+
48
+ module.exports = config;
49
+
50
+ if (devBuild) {
51
+ console.log('Webpack dev build for Rails'); // eslint-disable-line no-console
52
+ module.exports.devtool = 'eval-source-map';
53
+ } else {
54
+ config.plugins.push(
55
+ new webpack.optimize.DedupePlugin()
56
+ );
57
+ console.log('Webpack production build for Rails'); // eslint-disable-line no-console
58
+ }
@@ -2,42 +2,76 @@
2
2
  ReactOnRails.configure do |config|
3
3
  # Client bundles are configured in application.js
4
4
 
5
- # Directory where your generated assets go
5
+ # Directory where your generated assets go. All generated assets must go to the same directory.
6
+ # Configure this in your webpack config files. This relative to your Rails root directory.
6
7
  config.generated_assets_dir = File.join(%w(app assets webpack))
7
8
 
8
- # Define the files for we need to check for webpack compilation when running tests
9
- <%- if options.server_rendering? %>
10
- config.webpack_generated_files = %w( client-bundle.js server-bundle.js )
11
- <% else %>
12
- config.webpack_generated_files = %w( client-bundle.js )
13
- <%- end %>
14
-
15
- # Server rendering:
16
- # Server bundle is a single file for all server rendering of components.
17
- # Set the server_bundle_js_file to "" if you know that you will not be server rendering.
18
- <%- if options.server_rendering? %>
19
- config.server_bundle_js_file = "server-bundle.js"
20
- <% else %>
21
- config.server_bundle_js_file = ""
22
- <%- end %>
23
- # increase if you're on JRuby
24
- config.server_renderer_pool_size = 1
25
- # seconds
26
- config.server_renderer_timeout = 20
9
+ # Define the files we need to check for webpack compilation when running tests.
10
+ config.webpack_generated_files = %w( webpack-bundle.js )
11
+
12
+ # This is the file used for server rendering of React when using `(prerender: true)`
13
+ # If you are never using server rendering, you may set this to "".
14
+ # If you are using the same file for client and server rendering, having this set probably does
15
+ # not affect performance.
16
+ config.server_bundle_js_file = "webpack-bundle.js"
17
+
18
+ # If you are using the ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
19
+ # with rspec then this controls what npm command is run
20
+ # to automatically refresh your webpack assets on every test run.
21
+ config.npm_build_test_command = "npm run build:test"
22
+
23
+ # This configures the script to run to build the production assets by webpack. Set this to nil
24
+ # if you don't want react_on_rails building this file for you.
25
+ config.npm_build_production_command = "npm run build:production"
26
+
27
+ ################################################################################
28
+ # CLIENT RENDERING OPTIONS
29
+ # Below options can be overriden by passing options to the react_on_rails
30
+ # `render_component` view helper method.
31
+ ################################################################################
32
+ # default is false
33
+ config.prerender = false
34
+
35
+ # default is true for development, off otherwise
36
+ config.trace = Rails.env.development?
37
+
38
+ ################################################################################
39
+ # SERVER RENDERING OPTIONS
40
+ ################################################################################
27
41
  # If set to true, this forces Rails to reload the server bundle if it is modified
28
42
  config.development_mode = Rails.env.development?
43
+
29
44
  # For server rendering. This can be set to false so that server side messages are discarded.
30
45
  # Default is true. Be cautious about turning this off.
31
46
  config.replay_console = true
32
- # Default is true. Logs server rendering messags to Rails.logger.info
47
+
48
+ # Default is true. Logs server rendering messages to Rails.logger.info
33
49
  config.logging_on_server = true
34
50
 
35
- # The following options can be overriden by passing to the helper method:
51
+ config.raise_on_prerender_error = false # change to true to raise exception on server if the JS code throws
52
+
53
+ # Server rendering only (not for render_component helper)
54
+ # You can configure your pool of JS virtual machines and specify where it should load code:
55
+ # On MRI, use `therubyracer` for the best performance
56
+ # (see [discussion](https://github.com/reactjs/react-rails/pull/290))
57
+ # On MRI, you'll get a deadlock with `pool_size` > 1
58
+ # If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
59
+ config.server_renderer_pool_size = 1 # increase if you're on JRuby
60
+ config.server_renderer_timeout = 20 # seconds
61
+
62
+ ################################################################################
63
+ # MISCELLANEOUS OPTIONS
64
+ ################################################################################
36
65
 
37
- # Default is false
38
- config.prerender = false
39
- # Default is true for development, off otherwise
40
- config.trace = Rails.env.development?
41
66
  # Default is false, enable if your content security policy doesn't include `style-src: 'unsafe-inline'`
42
67
  config.skip_display_none = false
68
+
69
+ # The server render method - either ExecJS or NodeJS
70
+ config.server_render_method = "ExecJS"
71
+
72
+ # Client js uses assets not digested by rails.
73
+ # For any asset matching this regex, non-digested symlink will be created
74
+ # To disable symlinks set this parameter to nil.
75
+ config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/
76
+
43
77
  end
@@ -14,10 +14,7 @@ namespace :assets do
14
14
 
15
15
  desc "Compile assets with webpack"
16
16
  task :webpack do
17
- sh "cd client && npm run build:client"
18
- <%- if options[:server_rendering] -%>
19
- sh "cd client && npm run build:server"
20
- <%- end -%>
17
+ sh "cd client && npm run build:production"
21
18
  end
22
19
 
23
20
  task :clobber do
@@ -0,0 +1,8 @@
1
+ namespace :load_test do
2
+ desc "Load test with apache benchmark"
3
+ task :run, [:url, :count] do |_, args|
4
+ url = args[:url] || "http://localhost:3000/hello_world"
5
+ count = args[:count] || 500
6
+ system("ab -c 10 -n #{count} #{url}")
7
+ end
8
+ end
@@ -8,18 +8,6 @@
8
8
  "scripts": {
9
9
  "postinstall": "cd client && npm install",
10
10
  "rails-server": "echo 'visit http://localhost:3000/hello_world' && foreman start -f Procfile.dev",
11
- "build:production:client": "(cd client && npm run build:production:client --silent)",
12
- <%- if options.server_rendering? -%>
13
- "build:production:server": "(cd client && npm run build:production:server --silent)",
14
- <%- end -%>
15
- "build:client": "(cd client && npm run build:client --silent",
16
- <%- if options.server_rendering? -%>
17
- "build:server": "(cd client && npm run build:server --silent)",
18
- <%- end -%>
19
- "build:dev:client": "(cd client && npm run build:dev:client --silent)",
20
- <%- if options.server_rendering? -%>
21
- "build:dev:server": "(cd client && npm run build:dev:server --silent)",
22
- <%- end -%>
23
11
  "test": "rspec"
24
12
  }
25
13
  }
@@ -3,7 +3,7 @@ require_relative "../rails_helper"
3
3
  feature "Hello World", js: true do
4
4
  scenario "the hello world example works" do
5
5
  visit "/hello_world"
6
- expect(heading).to have_text("Rendering")
6
+ expect(heading).to have_text("Hello World")
7
7
  expect(message).to have_text("Stranger")
8
8
  name_input.set("John Doe")
9
9
  expect(message).to have_text("John Doe")
@@ -36,6 +36,7 @@ Capybara.javascript_driver = :poltergeist
36
36
  RSpec.configure do |config|
37
37
  # Ensure that if we are running js tests, we are using latest webpack assets
38
38
  # This will use the defaults of :js and :server_rendering meta tags
39
+ ReactOnRails::TestHelper.launch_node if ReactOnRails.configuration.server_render_method == "NodeJS"
39
40
  ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
40
41
 
41
42
  # Remove this line if you"re not using ActiveRecord or ActiveRecord fixtures
@@ -1,6 +1,5 @@
1
1
  import React, { PropTypes } from 'react';
2
2
  import HelloWorldWidget from '../components/HelloWorldWidget';
3
- import _ from 'lodash';
4
3
 
5
4
  // Simple example of a React "smart" component
6
5
  export default class HelloWorld extends React.Component {
@@ -14,11 +13,6 @@ export default class HelloWorld extends React.Component {
14
13
  // How to set initial state in ES6 class syntax
15
14
  // https://facebook.github.io/react/docs/reusable-components.html#es6-classes
16
15
  this.state = { name: this.props.name };
17
-
18
- // Uses lodash to bind all methods to the context of the object instance, otherwise
19
- // the methods defined here would not refer to the component's class, not the component
20
- // instance itself.
21
- _.bindAll(this, 'updateName');
22
16
  }
23
17
 
24
18
  updateName(name) {
@@ -28,7 +22,7 @@ export default class HelloWorld extends React.Component {
28
22
  render() {
29
23
  return (
30
24
  <div>
31
- <HelloWorldWidget name={this.state.name} updateName={this.updateName} />
25
+ <HelloWorldWidget name={this.state.name} updateName={e => this.updateName(e)} />
32
26
  </div>
33
27
  );
34
28
  }
@@ -1,5 +1,11 @@
1
+ import React from 'react';
1
2
  import ReactOnRails from 'react-on-rails';
2
- import HelloWorldApp from './HelloWorldAppClient';
3
+
4
+ import HelloWorld from '../containers/HelloWorld';
5
+
6
+ const HelloWorldApp = (props) => (
7
+ <HelloWorld {...props} />
8
+ );
3
9
 
4
10
  // This is how react_on_rails can see the HelloWorldApp in the browser.
5
11
  ReactOnRails.register({ HelloWorldApp });
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import ReactOnRails from 'react-on-rails';
2
3
  import { Provider } from 'react-redux';
3
4
 
4
5
  import createStore from '../store/helloWorldStore';
@@ -7,7 +8,7 @@ import HelloWorld from '../containers/HelloWorld';
7
8
  // See documentation for https://github.com/reactjs/react-redux.
8
9
  // This is how you get props from the Rails view into the redux store.
9
10
  // This code here binds your smart component to the redux store.
10
- export default (props) => {
11
+ const HelloWorldApp = (props) => {
11
12
  const store = createStore(props);
12
13
  const reactComponent = (
13
14
  <Provider store={store}>
@@ -16,3 +17,6 @@ export default (props) => {
16
17
  );
17
18
  return reactComponent;
18
19
  };
20
+
21
+ // This is how react_on_rails can see the HelloWorldApp in the browser.
22
+ ReactOnRails.register({ HelloWorldApp });
@@ -6,10 +6,6 @@ import { compose, createStore, applyMiddleware, combineReducers } from 'redux';
6
6
  // once your app has asynchronous actions.
7
7
  import thunkMiddleware from 'redux-thunk';
8
8
 
9
- // This provides an example of logging redux actions to the console.
10
- // You'd want to disable this for production.
11
- import loggerMiddleware from 'lib/middlewares/loggerMiddleware';
12
-
13
9
  import reducers from '../reducers';
14
10
  import { initialStates } from '../reducers';
15
11
 
@@ -27,7 +23,7 @@ export default props => {
27
23
 
28
24
  const reducer = combineReducers(reducers);
29
25
  const composedStore = compose(
30
- applyMiddleware(thunkMiddleware, loggerMiddleware)
26
+ applyMiddleware(thunkMiddleware)
31
27
  );
32
28
  const storeCreator = composedStore(createStore);
33
29
  const store = storeCreator(reducer, initialState);