react_on_rails 4.0.3 → 5.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -7
  3. data/NEWS.md +1 -1
  4. data/README.md +186 -78
  5. data/app/helpers/react_on_rails_helper.rb +99 -74
  6. data/docs/{additional_reading → additional-reading}/babel.md +0 -0
  7. data/docs/{additional_reading/heroku_deployment.md → additional-reading/heroku-deployment.md} +0 -0
  8. data/docs/additional-reading/hot-reloading-rails-development.md +111 -0
  9. data/docs/additional-reading/installation-overview.md +32 -0
  10. data/docs/{additional_reading/node_dependencies_and_npm.md → additional-reading/node-dependencies-and-npm.md} +0 -0
  11. data/docs/{additional_reading → additional-reading}/rails_view_rendering_from_inline_javascript.md +0 -0
  12. data/docs/{additional_reading → additional-reading}/react-and-redux.md +0 -0
  13. data/docs/{additional_reading/react_router.md → additional-reading/react-router.md} +5 -3
  14. data/docs/{recommended-project-structure.md → additional-reading/recommended-project-structure.md} +22 -0
  15. data/docs/{additional_reading/rspec_configuration.md → additional-reading/rspec-configuration.md} +0 -0
  16. data/docs/{additional_reading/server_rendering_tips.md → additional-reading/server-rendering-tips.md} +0 -0
  17. data/docs/{additional_reading → additional-reading}/tips.md +0 -0
  18. data/docs/{additional_reading → additional-reading}/turbolinks.md +0 -0
  19. data/docs/{additional_reading → additional-reading}/updating-dependencies.md +0 -0
  20. data/docs/{additional_reading → additional-reading}/webpack.md +0 -0
  21. data/docs/{contributing.md → contributor-info/contributing.md} +0 -0
  22. data/docs/{generator_testing.md → contributor-info/generator-testing.md} +0 -0
  23. data/docs/{releasing.md → contributor-info/releasing.md} +0 -0
  24. data/docs/{code_of_conduct.md → misc/code_of_conduct.md} +0 -0
  25. data/docs/{doctrine.md → misc/doctrine.md} +1 -1
  26. data/docs/{rails3.md → misc/rails3.md} +0 -0
  27. data/docs/{tutorial-v2.md → tutorial.md} +4 -4
  28. data/lib/react_on_rails/configuration.rb +6 -3
  29. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +1 -1
  30. data/lib/react_on_rails/test_helper.rb +1 -1
  31. data/lib/react_on_rails/version.rb +1 -1
  32. data/package.json +1 -1
  33. metadata +26 -27
  34. data/docs/additional_reading/hot-reloading-rails-development.md +0 -32
  35. data/docs/additional_reading/manual_installation.md +0 -117
  36. data/docs/additional_reading/optional_configuration.md +0 -33
@@ -63,9 +63,9 @@ module ReactOnRailsHelper
63
63
  # React.createClass, or a
64
64
  # `generator function` that returns a React component
65
65
  # using ES6
66
- # let MyReactComponentApp = (props) => <MyReactComponent {...props}/>;
66
+ # let MyReactComponentApp = (props, railsContext) => <MyReactComponent {...props}/>;
67
67
  # or using ES5
68
- # var MyReactComponentApp = function(props) { return <YourReactComponent {...props}/>; }
68
+ # var MyReactComponentApp = function(props, railsContext) { return <YourReactComponent {...props}/>; }
69
69
  # Exposing the react_component_name is necessary to both a plain ReactComponent as well as
70
70
  # a generator:
71
71
  # See README.md for how to "register" your react components.
@@ -76,6 +76,8 @@ module ReactOnRailsHelper
76
76
  # props: Ruby Hash or JSON string which contains the properties to pass to the react object. Do
77
77
  # not pass any props if you are separately initializing the store by the `redux_store` helper.
78
78
  # prerender: <true/false> set to false when debugging!
79
+ # id: You can optionally set the id, or else a unique one is automatically generated.
80
+ # html_options: You can set other html attributes that will go on this component
79
81
  # trace: <true/false> set to true to print additional debugging information in the browser
80
82
  # default is true for development, off otherwise
81
83
  # replay_console: <true/false> Default is true. False will disable echoing server rendering
@@ -85,7 +87,14 @@ module ReactOnRailsHelper
85
87
  # raise_on_prerender_error: <true/false> Default to false. True will raise exception on server
86
88
  # if the JS code throws
87
89
  # Any other options are passed to the content tag, including the id.
88
- def react_component(component_name, options = {}, other_options = nil)
90
+ def react_component(component_name,
91
+ props: {},
92
+ prerender: nil,
93
+ trace: nil,
94
+ replay_console: nil,
95
+ raise_on_prerender_error: nil,
96
+ id: nil,
97
+ html_options: {})
89
98
  # Create the JavaScript and HTML to allow either client or server rendering of the
90
99
  # react_component.
91
100
  #
@@ -94,25 +103,24 @@ module ReactOnRailsHelper
94
103
  # server has already rendered the HTML.
95
104
  # We use this react_component_index in case we have the same component multiple times on the page.
96
105
 
97
- options, props = parse_options_props(component_name, options, other_options)
98
-
99
106
  react_component_index = next_react_component_index
100
107
  react_component_name = component_name.camelize # Not sure if we should be doing this (JG)
101
- dom_id = if options[:id].nil?
102
- "#{component_name}-react-component-#{react_component_index}"
103
- else
104
- options[:id]
105
- end
108
+ dom_id = id.presence || "#{component_name}-react-component-#{react_component_index}"
106
109
 
107
110
  # Setup the page_loaded_js, which is the same regardless of prerendering or not!
108
111
  # The reason is that React is smart about not doing extra work if the server rendering did its job.
109
112
 
110
113
  props = {} if props.nil?
111
114
 
115
+ prerender = prerender_option(prerender)
116
+ trace = trace_option(trace)
117
+ replay_console = replay_console_option(replay_console)
118
+ raise_on_prerender_error = raise_on_prerender_error_option(raise_on_prerender_error)
119
+
112
120
  data = {
113
121
  component_name: react_component_name,
114
122
  props: props,
115
- trace: trace(options),
123
+ trace: trace,
116
124
  dom_id: dom_id
117
125
  }
118
126
 
@@ -124,14 +132,15 @@ module ReactOnRailsHelper
124
132
  data: data)
125
133
 
126
134
  # Create the HTML rendering part
127
- result = server_rendered_react_component_html(options, props, react_component_name, dom_id)
135
+ result = server_rendered_react_component_html(props, react_component_name, dom_id,
136
+ prerender: prerender,
137
+ trace: trace,
138
+ raise_on_prerender_error: raise_on_prerender_error)
128
139
 
129
140
  server_rendered_html = result["html"]
130
141
  console_script = result["consoleReplayScript"]
131
142
 
132
- content_tag_options = options.except(:generator_function, :prerender, :trace,
133
- :replay_console, :id, :react_component_name,
134
- :server_side, :raise_on_prerender_error)
143
+ content_tag_options = html_options
135
144
  content_tag_options[:id] = dom_id
136
145
 
137
146
  rendered_output = content_tag(:div,
@@ -139,11 +148,13 @@ module ReactOnRailsHelper
139
148
  content_tag_options)
140
149
 
141
150
  # IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
142
- <<-HTML.html_safe
151
+ result = <<-HTML.html_safe
143
152
  #{component_specification_tag}
144
153
  #{rendered_output}
145
- #{replay_console(options) ? console_script : ''}
154
+ #{replay_console ? console_script : ''}
146
155
  HTML
156
+
157
+ prepend_render_rails_context(result)
147
158
  end
148
159
 
149
160
  # Separate initialization of store from react_component allows multiple react_component calls to
@@ -165,7 +176,8 @@ module ReactOnRailsHelper
165
176
  else
166
177
  @registered_stores ||= []
167
178
  @registered_stores << redux_store_data
168
- render_redux_store_data(redux_store_data)
179
+ result = render_redux_store_data(redux_store_data)
180
+ prepend_render_rails_context(result)
169
181
  end
170
182
  end
171
183
 
@@ -222,7 +234,7 @@ module ReactOnRailsHelper
222
234
  # IMPORTANT: To ensure that Rails doesn't auto-escape HTML tags, use the 'raw' method.
223
235
  html = result["html"]
224
236
  console_log_script = result["consoleLogScript"]
225
- raw("#{html}#{replay_console(options) ? console_log_script : ''}")
237
+ raw("#{html}#{replay_console_option(options[:replay_console_option]) ? console_log_script : ''}")
226
238
  rescue ExecJS::ProgramError => err
227
239
  # rubocop:disable Style/RaiseArgs
228
240
  raise ReactOnRails::PrerenderError.new(component_name: "N/A (server_render_js called)",
@@ -233,12 +245,31 @@ module ReactOnRailsHelper
233
245
 
234
246
  private
235
247
 
248
+ # prepend the rails_context if not yet applied
249
+ def prepend_render_rails_context(render_value)
250
+ return render_value if @rendered_rails_context
251
+
252
+ data = {
253
+ rails_context: rails_context
254
+ }
255
+
256
+ @rendered_rails_context = true
257
+
258
+ rails_context_content = content_tag(:div,
259
+ "",
260
+ id: "js-react-on-rails-context",
261
+ style: ReactOnRails.configuration.skip_display_none ? nil : "display:none",
262
+ data: data)
263
+ "#{rails_context_content}\n#{render_value}".html_safe
264
+ end
265
+
236
266
  def render_redux_store_data(redux_store_data)
237
- content_tag(:div,
238
- "",
239
- class: "js-react-on-rails-store",
240
- style: ReactOnRails.configuration.skip_display_none ? nil : "display:none",
241
- data: redux_store_data)
267
+ result = content_tag(:div,
268
+ "",
269
+ class: "js-react-on-rails-store",
270
+ style: ReactOnRails.configuration.skip_display_none ? nil : "display:none",
271
+ data: redux_store_data)
272
+ prepend_render_rails_context(result)
242
273
  end
243
274
 
244
275
  def next_react_component_index
@@ -252,8 +283,9 @@ module ReactOnRailsHelper
252
283
 
253
284
  # Returns Array [0]: html, [1]: script to console log
254
285
  # NOTE, these are NOT html_safe!
255
- def server_rendered_react_component_html(options, props, react_component_name, dom_id)
256
- return { "html" => "", "consoleReplayScript" => "" } unless prerender(options)
286
+ def server_rendered_react_component_html(props, react_component_name, dom_id,
287
+ prerender:, trace:, raise_on_prerender_error:)
288
+ return { "html" => "", "consoleReplayScript" => "" } unless prerender
257
289
 
258
290
  # On server `location` option is added (`location = request.fullpath`)
259
291
  # React Router needs this to match the current route
@@ -265,21 +297,22 @@ module ReactOnRailsHelper
265
297
 
266
298
  wrapper_js = <<-JS
267
299
  (function() {
300
+ var railsContext = #{rails_context.to_json};
268
301
  #{initialize_redux_stores}
269
302
  var props = #{props_string(props)};
270
303
  return ReactOnRails.serverRenderReactComponent({
271
304
  name: '#{react_component_name}',
272
305
  domNodeId: '#{dom_id}',
273
306
  props: props,
274
- trace: #{trace(options)},
275
- location: '#{request.fullpath}'
307
+ trace: #{trace},
308
+ railsContext: railsContext
276
309
  });
277
310
  })()
278
311
  JS
279
312
 
280
313
  result = ReactOnRails::ServerRenderingPool.server_render_js_with_console_logging(wrapper_js)
281
314
 
282
- if result["hasErrors"] && raise_on_prerender_error(options)
315
+ if result["hasErrors"] && raise_on_prerender_error
283
316
  # We caught this exception on our backtrace handler
284
317
  # rubocop:disable Style/RaiseArgs
285
318
  raise ReactOnRails::PrerenderError.new(component_name: react_component_name,
@@ -314,66 +347,58 @@ module ReactOnRailsHelper
314
347
  memo << <<-JS
315
348
  reduxProps = #{props};
316
349
  storeGenerator = ReactOnRails.getStoreGenerator('#{store_name}');
317
- store = storeGenerator(reduxProps);
350
+ store = storeGenerator(reduxProps, railsContext);
318
351
  ReactOnRails.setStore('#{store_name}', store);
319
352
  JS
320
353
  end
321
354
  result
322
355
  end
323
356
 
324
- def raise_on_prerender_error(options)
325
- options.fetch(:raise_on_prerender_error) { ReactOnRails.configuration.raise_on_prerender_error }
357
+ # This is the definitive list of the default values used for the rails_context, which is the
358
+ # second parameter passed to both component and store generator functions.
359
+ def rails_context
360
+ @rails_context ||= begin
361
+ uri = URI.parse(request.original_url)
362
+ # uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
363
+
364
+ result = {
365
+ # URL settings
366
+ href: request.original_url,
367
+ location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
368
+ scheme: uri.scheme, # http
369
+ host: uri.host, # foo.com
370
+ pathname: uri.path, # /posts
371
+ search: uri.query, # id=30&limit=5
372
+
373
+ # Locale settings
374
+ i18nLocale: I18n.locale,
375
+ i18nDefaultLocale: I18n.default_locale,
376
+ httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
377
+ }
378
+
379
+ if ReactOnRails.configuration.rendering_extension
380
+ custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
381
+ result.merge!(custom_context) if custom_context
382
+ end
383
+ result
384
+ end
326
385
  end
327
386
 
328
- def trace(options)
329
- options.fetch(:trace) { ReactOnRails.configuration.trace }
387
+ def raise_on_prerender_error_option(val)
388
+ val.nil? ? ReactOnRails.configuration.raise_on_prerender_error : val
330
389
  end
331
390
 
332
- def prerender(options)
333
- options.fetch(:prerender) { ReactOnRails.configuration.prerender }
391
+ def trace_option(val)
392
+ val.nil? ? ReactOnRails.configuration.trace : val
334
393
  end
335
394
 
336
- def replay_console(options)
337
- options.fetch(:replay_console) { ReactOnRails.configuration.replay_console }
395
+ def prerender_option(val)
396
+ val.nil? ? ReactOnRails.configuration.prerender : val
338
397
  end
339
398
 
340
- # rubocop:disable Metrics/CyclomaticComplexity
341
- # rubocop:disable Metrics/PerceivedComplexity
342
- def parse_options_props(component_name, options, other_options)
343
- other_options ||= {}
344
- if options.is_a?(Hash) && options.key?(:props)
345
- props = options[:props]
346
- final_options = options.except(:props)
347
- final_options.merge!(other_options) if other_options.present?
348
- else
349
- # either no props specified or deprecated
350
- if other_options.present? || options.is_a?(String)
351
- deprecated_syntax = true
352
- else
353
- options_has_no_reserved_keys =
354
- %i(prerender trace replay_console raise_on_prerender_error).none? do |key|
355
- options.key?(key)
356
- end
357
- deprecated_syntax = options_has_no_reserved_keys && options.present?
358
- end
359
-
360
- if deprecated_syntax
361
- puts "Deprecation: react_component now takes props as an explicity named parameter :props. "\
362
- " Props as the second arg will be removed in a future release. Called for "\
363
- "component_name: #{component_name}, controller: #{controller_name}, "\
364
- "action: #{action_name}."
365
- options = {} if options.is_a?(String) && options.blank?
366
- props = options
367
- final_options = other_options
368
- else
369
- options ||= {}
370
- final_options = options.merge(other_options)
371
- end
372
- end
373
- [final_options, props]
399
+ def replay_console_option(val)
400
+ val.nil? ? ReactOnRails.configuration.replay_console : val
374
401
  end
375
- # rubocop:enable Metrics/CyclomaticComplexity
376
- # rubocop:enable Metrics/PerceivedComplexity
377
402
 
378
403
  def use_hot_reloading?
379
404
  ENV["REACT_ON_RAILS_ENV"] == "HOT"
@@ -0,0 +1,111 @@
1
+ # Hot Reloading of Assets For Rails Development
2
+
3
+ This document outlines the steps to setup your React On Rails Environment so that you can experience the pleasure of hot reloading of JavaScript and Sass during your Rails development work. There are 2 examples of this setup:
4
+
5
+ 1. [spec/dummy](../../spec/dummy): Simpler setup used for integration testing this gem.
6
+ 1. [shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/). Full featured setup using Twitter bootstrap.
7
+
8
+ ## High Level Strategy
9
+
10
+ We'll use a Webpack Dev server on port 3500 to provide the assets to Rails, rather than the asset pipeline, and only during development mode. This is configured via the `Procfile.hot`.
11
+
12
+ `Procfile.static` provides an alternative that uses "static" assets, similar to a production deployment.
13
+
14
+ The secret sauce is in the [app/views/layouts/application.html.erb](../../spec/dummy/app/views/layouts/application.html.erb) where it uses view helpes to configure the correct assets to load, being either the "hot" assets or the "static" assets.
15
+
16
+ ## Places to Configure (Files to Examine)
17
+
18
+ 1. See the Webpack config files. Note, these examples are now setup for using [CSS Modules](https://github.com/css-modules/css-modules).
19
+ 1. [client/webpack.client.base.config.js](../../spec/dummy/client/webpack.client.base.config.js): Common configuration for hot or static assets.
20
+ 1. [client/webpack.client.rails.hot.config.js](../../spec/dummy/client/webpack.client.rails.hot.config.js): Setup for hot loading, using react-transform-hmr.
21
+ 1. [client/webpack.client.rails.build.config.js](../../spec/dummy/client/webpack.client.rails.build.config.js): Setup for static loading, as is done in a production deployment.
22
+ 1. [app/views/layouts/application.html.erb](../../spec/dummy/app/views/layouts/application.html.erb): Uses the view helpers `env_stylesheet_link_tag` and `env_javascript_include_tag` which will either do the hot reloading or the static loading.
23
+ 1. See the Procfiles: [Procfile.hot](../../spec/dummy/Procfile.hot) and [Procfile.static](../../spec/dummy/Procfile.static). These:
24
+ 1. Start the webpack processes, depending on the mode or HOT or not.
25
+ 2. Start the rails server, setting an ENV value of REACT_ON_RAILS_ENV to HOT if we're hot loading or else setting this to blank.
26
+ 1. Configure the file Rails asset pipeline files:
27
+ 1. [app/assets/javascripts/application_static.js](../../spec/dummy/app/assets/javascripts/application_static.js)
28
+ 1. [app/assets/stylesheets/application_static.css.scss](../../spec/dummy/app/assets/stylesheets/application_static.css.scss)
29
+ 1. Be sure your [config/initializers/assets.rb](../../spec/dummy/config/initializers/assets.rb) is configured to include the webpack generated files.
30
+ 1. Copy the [client/server-rails-hot.js](../../spec/dummy/client/server-rails-hot.js) to the your client directory.
31
+ 1. Copy the scripts in the top level and client level `package.json` files:
32
+ 1. Top Level: [package.json](../../spec/dummy/package.json)
33
+ 1. Client Level: [package.json](../../spec/dummy/client/package.json)
34
+
35
+
36
+ ## Code Snippets
37
+ Please refer to the examples linked above in `spec/dummy` as these code samples might be out of date.
38
+
39
+
40
+ ### config/initializers/assets.rb
41
+
42
+ ```ruby
43
+ # Add folder with webpack generated assets to assets.paths
44
+ Rails.application.config.assets.paths << Rails.root.join("app", "assets", "webpack")
45
+
46
+ # Precompile additional assets.
47
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
48
+ Rails.application.config.assets.precompile << "server-bundle.js"
49
+
50
+ type = ENV["REACT_ON_RAILS_ENV"] == "HOT" ? "non_webpack" : "static"
51
+ Rails.application.config.assets.precompile +=
52
+ [
53
+ "application_#{type}.js",
54
+ "application_#{type}.css"
55
+ ]
56
+ ```
57
+
58
+ ### app/views/layouts/application.html.erb
59
+
60
+ ```erb
61
+ <head>
62
+ <title>Dummy</title>
63
+
64
+ <!-- These do use turbolinks 5 -->
65
+ <%= env_stylesheet_link_tag(static: 'application_static',
66
+ hot: 'application_non_webpack',
67
+ media: 'all',
68
+ 'data-turbolinks-track' => "reload") %>
69
+
70
+ <!-- These do not use turbolinks, so no data-turbolinks-track -->
71
+ <!-- This is to load the hot assets. -->
72
+ <%= env_javascript_include_tag(hot: ['http://localhost:3500/vendor-bundle.js',
73
+ 'http://localhost:3500/app-bundle.js']) %>
74
+
75
+ <!-- These do use turbolinks 5 -->
76
+ <%= env_javascript_include_tag(static: 'application_static',
77
+ hot: 'application_non_webpack',
78
+ 'data-turbolinks-track' => "reload") %>
79
+
80
+ <%= csrf_meta_tags %>
81
+ </head>
82
+ ```
83
+
84
+ ### Procfile.static
85
+ ```
86
+ # Run Rails without hot reloading (static assets).
87
+ rails: REACT_ON_RAILS_ENV= rails s -b 0.0.0.0
88
+
89
+ # Build client assets, watching for changes.
90
+ rails-client-assets: npm run build:dev:client
91
+
92
+ # Build server assets, watching for changes. Remove if not server rendering.
93
+ rails-server-assets: npm run build:dev:server
94
+ ```
95
+
96
+ ### Procfile.hot
97
+
98
+ ```
99
+ # Procfile for development with hot reloading of JavaScript and CSS
100
+
101
+ # Development rails requires both rails and rails-assets
102
+ # (and rails-server-assets if server rendering)
103
+ rails: REACT_ON_RAILS_ENV=HOT rails s -b 0.0.0.0
104
+
105
+ # Run the hot reload server for client development
106
+ hot-assets: HOT_RAILS_PORT=3500 npm run hot-assets
107
+
108
+ # Keep the JS fresh for server rendering. Remove if not server rendering
109
+ rails-server-assets: npm run build:dev:server
110
+ ```
111
+
@@ -0,0 +1,32 @@
1
+ # Installation Overview
2
+
3
+ Here's an overview of installation if you're not using the generator.
4
+
5
+ Note, the best to understand how to use ReactOnRails is to study the examples:
6
+
7
+ 1. [spec/dummy](../../spec/dummy): Simple, no DB example.
8
+ 2. [github.com/shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial): Full featured example.
9
+
10
+ ## Configure the `/client` Directory
11
+
12
+ This directory has no references to Rails outside of the destination directory for the files created by the various Webpack config files.
13
+
14
+ The only requirements within this directory for basic React on Rails integration are:
15
+
16
+ 1. Your webpack configuration files:
17
+ 1. Create outputs in a directory like `/app/assets/webpack`, which is customizable in your `config/initializers/react_on_rails.rb`.
18
+ 1. Provide server rendering if you wish to use that feature.
19
+ 1. Your JavaScript code "registers" any components and stores per the ReactOnRails APIs of ReactOnRails.register(components) and ReactOnRails.registerStore(stores). See API docs in [README.md](../../README.md) and the [ReactOnRails.js source](../../node_package/src/ReactOnRails.js).
20
+ 1. Set your registration file as an "entry" point in your Webpack configs.
21
+ 1. You create scripts in `client/package.json` per the example apps. These are used for building your Webpack assets. Also do this for your top level `package.json`.
22
+
23
+ ## Rails Steps (outside of /client)
24
+ 1. Configure the `config/initializers/react_on_rails.rb`. You can adjust some necessary settings and defaults. See file [spec/dummy/config/initializers/react_on_rails.rb](../../spec/dummy/config/initializers/react_on_rails.rb) for a detailed example of configuration, including comments on the different values to configure.
25
+ 1. Configure your Procfiles per the example apps. These are at the root of your Rails installation.
26
+ 1. Configure `config/initializers/assets.rb` probably like [spec/dummy/config/initializers/assets.rb](../../spec/dummy/config/initializers/assets.rb). This example shows what's necessary if you're enabling the hot-reloading Rails development option.
27
+ 1. Configure your top level JavaScript files for inclusion in your layout. You'll want a version that you use for static assets, and you want a file for any files in your setup that are not part of your webpack build. The reason for this is for use with hot-reloading. If you are not using hot reloading, then you only need to configure your `application.js` file to include your Webpack generated files. For more information on hot reloading, see [Hot Reloading of Assets For Rails Development](hot-reloading-rails-development.md)
28
+
29
+ 1. Configure your `lib/tasks/assets.rake` file to run webpack during asset precompilation.
30
+ 1. If you are deploying to Heroku, see [heroku-deployment.md](heroku-deployment.md)
31
+
32
+ If I missed anything, please submit a PR or file an issue.
@@ -6,12 +6,14 @@ However, when attempting to use server-rendering, it is necessary to take steps
6
6
  If you are working with the HelloWorldApp created by the react_on_rails generator, then the code below corresponds to the module in `client/app/bundles/HelloWorld/startup/HelloWorldAppServer.jsx`.
7
7
 
8
8
  ```js
9
- const RouterApp = (props, location) => {
10
- const store = createStore(props);
11
-
9
+ const RouterApp = (props, railsContext) => {
12
10
  let error;
13
11
  let redirectLocation;
14
12
  let routeProps;
13
+ const { location } = railsContext;
14
+
15
+ // create your hydrated store
16
+ const store = createStore(props);
15
17
 
16
18
  // See https://github.com/reactjs/react-router/blob/master/docs/guides/advanced/ServerRendering.md
17
19
  match({ routes, location }, (_error, _redirectLocation, _routeProps) => {
@@ -2,6 +2,9 @@
2
2
 
3
3
  While React On Rails does not *enforce* a specific project structure, we do *recommend* a standard organization. The more we follow standards as a community, the easier it will be for all of us to move between various Rails projects that include React On Rails.
4
4
 
5
+ The best way to understand these standards is to follow this example: [github.com/shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial)
6
+
7
+ ## JavaScript Assets
5
8
  1. `/client`: All client side JavaScript goes under the `/client` directory. Place all the major domains of the client side app under client.
6
9
  1. `/client/app`: All application JavaScript. Note the adherence to the [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript#naming-conventions) where we name the files to correspond to exported Objects (PascalCase) or exported functions (camelCase). We don't use dashes or snake_case for JavaScript files, except for possibly some config files.
7
10
  1. `/client/app/bundles`: Top level of different app domains. Use a name within this directory for you app domains. For example, if you had a domain called `widget-editing`, then you would have: `/client/app/bundles/widget-editing`
@@ -18,5 +21,24 @@ While React On Rails does not *enforce* a specific project structure, we do *rec
18
21
  * `/store`: Store, which might be [configured differently for dev vs. production](https://github.com/reactjs/redux/tree/master/examples/real-world/store).
19
22
  * `/startup`: Component bindings to stores, with registration of components and stores.
20
23
  * `/schemas`: Schemas for AJAX JSON requests and responses, as used by the [Normalizr](https://github.com/gaearon/normalizr) package.
24
+
25
+ ## CSS, Sass, Fonts, and Images
26
+ Should you move your styling assets to Webpack? Or stick with the plain Rails asset pipeline. It depends! You have 2 basic choices:
27
+
28
+ ### Simple Rails Way
29
+ This isn't really any technique, as you keep handling all your styling assets using Rails standard tools, such as using the [sass-rails gem](https://rubygems.org/gems/sass-rails/versions/5.0.4). Basically, Webpack doesn't get involved with styling. Your Rails layouts just doing the styling the standard Rails way.
30
+
31
+ #### Advantages
32
+ 1. Much simpler! There's no changes really from your current processes.
33
+
34
+ ### Using Webpack to Manage Styling Assets
35
+ This technique involves customization of the webpack config files to generate CSS, image, and font assets. See [webpack.client.rails.build.config.js](https://github.com/shakacode/react_on_rails/blob/master/spec%2Fdummy%2Fclient%2Fwebpack.client.rails.build.config.js) for an example how to set the webpack part.
36
+
37
+ #### Directory structure
21
38
  1. `/client/app/assets`: Assets for CSS for client app.
22
39
  1. `/client/app/assets/fonts` and `/client/app/assets/styles`: Globally shared assets for styling. Note, most Sass and image assets will be stored next to the JavaScript files.
40
+
41
+ #### Advantages
42
+ 1. You can use [CSS modules](https://github.com/css-modules/css-modules), which is super compelling once you seen the benefits.
43
+ 1. You can do hot reloading of your assets. Thus, you do not have to refresh your web page to see asset change, including changing styles.
44
+ 1. You can run your client code on a mocked out express server for super fast prototyping. In other words, your client application can somewhat more easily be move to a different application server.
@@ -19,7 +19,7 @@ The React on Rails setup provides several key components related to front-end de
19
19
  6. Happiness for us is actively participating in open source, so we want to be where the action is, which is with the npm libraries on github.com.
20
20
  7. You can get set up on React on Rails **FAST** using our application generator.
21
21
  8. By placing all client-side development inside of the `/client` directory, pure JavaScript developers can productively do development separate from Rails. Instead of Rails APIs, stub APIs on an express server can provide a simple backend, allowing for rapid iteration of UI prototypes.
22
- 9. Just because we're not relying on the Rails asset pipeline for ES6 conversion does not mean that we're deploying Rails apps in any different way. We still use the asset pipeline to include our Webpack compiled JavaScript. This only requires a few small modifications, as explained in our doc [Heroku Deployment](additional_reading/heroku_deployment.md).
22
+ 9. Just because we're not relying on the Rails asset pipeline for ES6 conversion does not mean that we're deploying Rails apps in any different way. We still use the asset pipeline to include our Webpack compiled JavaScript. This only requires a few small modifications, as explained in our doc [Heroku Deployment](additional-reading/heroku_deployment.md).
23
23
 
24
24
  ## Convention over Configuration
25
25
  * React on Rails has taken the hard work out of figuring out the JavaScript tooling that works best with Rails. Not only could you spend lots of time researching different tooling, but then you'd have to figure out how to splice it all together. This is where a lot of "JavaScript fatigue" comes from. The following keep the code clean and consistent:
File without changes
@@ -1,10 +1,10 @@
1
- # Tutorial for v2.0
1
+ # Tutorial for React on Rails
2
2
 
3
- I just released RC3 of [React On Rails](https://github.com/shakacode/react_on_rails/tree/npm-react-on-rails-js). Here's a tiny tutorial to get you started. This tutorial setups up a new Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering.
3
+ This tutorial setups up a new Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering.
4
4
 
5
5
  You can find:
6
6
 
7
- * [Source code for this sample app](https://github.com/justin808/test-react-on-rails-3)
7
+ * [Source code for this sample app](https://github.com/justin808/test-react-on-rails-3) (for an older version)
8
8
  * [Live on Heroku](https://shakacode-react-on-rails.herokuapp.com/hello_world)
9
9
 
10
10
  By the time you read this, the latest may have changed. Be sure to check the versions here:
@@ -12,7 +12,7 @@ By the time you read this, the latest may have changed. Be sure to check the ver
12
12
  * https://rubygems.org/gems/react_on_rails
13
13
  * https://www.npmjs.com/package/react-on-rails
14
14
 
15
- Trying out v2 is super easy, so long as you have the basic prerequisites. This includes the basics for Rails 4.x and node version 4+. I recommend `rvm` and `nvm` to install Ruby and Node.
15
+ Trying out v4 is super easy, so long as you have the basic prerequisites. This includes the basics for Rails 4.x and node version 5+. I recommend `rvm` and `nvm` to install Ruby and Node.
16
16
 
17
17
  ```
18
18
  cd <directory where you want to create your new Rails app>
@@ -55,7 +55,8 @@ module ReactOnRails
55
55
  server_renderer_pool_size: 1,
56
56
  server_renderer_timeout: 20,
57
57
  skip_display_none: false,
58
- webpack_generated_files: []
58
+ webpack_generated_files: [],
59
+ rendering_extension: nil
59
60
  )
60
61
  end
61
62
 
@@ -65,14 +66,15 @@ module ReactOnRails
65
66
  :logging_on_server, :server_renderer_pool_size,
66
67
  :server_renderer_timeout, :raise_on_prerender_error,
67
68
  :skip_display_none, :generated_assets_dirs, :generated_assets_dir,
68
- :webpack_generated_files
69
+ :webpack_generated_files, :rendering_extension
69
70
 
70
71
  def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
71
72
  trace: nil, development_mode: nil,
72
73
  logging_on_server: nil, server_renderer_pool_size: nil,
73
74
  server_renderer_timeout: nil, raise_on_prerender_error: nil,
74
75
  skip_display_none: nil, generated_assets_dirs: nil,
75
- generated_assets_dir: nil, webpack_generated_files: nil)
76
+ generated_assets_dir: nil, webpack_generated_files: nil,
77
+ rendering_extension: nil)
76
78
  self.server_bundle_js_file = server_bundle_js_file
77
79
  self.generated_assets_dirs = generated_assets_dirs
78
80
  self.generated_assets_dir = generated_assets_dir
@@ -94,6 +96,7 @@ module ReactOnRails
94
96
  self.server_renderer_timeout = server_renderer_timeout # seconds
95
97
 
96
98
  self.webpack_generated_files = webpack_generated_files
99
+ self.rendering_extension = rendering_extension
97
100
  end
98
101
  end
99
102
  end
@@ -99,7 +99,7 @@ watch processes, such by running a clean on your generated bundles before starti
99
99
 
100
100
  If you are frequently running tests, you can run webpack in watch mode for static assets to
101
101
  speed up this process. See the official documentation:
102
- https://github.com/shakacode/react_on_rails/blob/master/docs/additional_reading/rspec_configuration.md
102
+ https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/rspec-configuration.md
103
103
  MSG
104
104
 
105
105
  if already_compiled_client_file
@@ -24,7 +24,7 @@ module ReactOnRails
24
24
  # faster. The helper looks for these processes and will abort recompiling if it finds them
25
25
  # to be running.
26
26
  #
27
- # See docs/additional_reading/rspec_configuration.md for more info
27
+ # See docs/additional-reading/rspec-configuration.md for more info
28
28
  #
29
29
  # Params:
30
30
  # config - config for rspec
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ReactOnRails
3
- VERSION = "4.0.3".freeze
3
+ VERSION = "5.0.0.rc.1".freeze
4
4
  end