react_on_rails 5.2.0 → 6.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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);