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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -7
- data/NEWS.md +1 -1
- data/README.md +186 -78
- data/app/helpers/react_on_rails_helper.rb +99 -74
- data/docs/{additional_reading → additional-reading}/babel.md +0 -0
- data/docs/{additional_reading/heroku_deployment.md → additional-reading/heroku-deployment.md} +0 -0
- data/docs/additional-reading/hot-reloading-rails-development.md +111 -0
- data/docs/additional-reading/installation-overview.md +32 -0
- data/docs/{additional_reading/node_dependencies_and_npm.md → additional-reading/node-dependencies-and-npm.md} +0 -0
- data/docs/{additional_reading → additional-reading}/rails_view_rendering_from_inline_javascript.md +0 -0
- data/docs/{additional_reading → additional-reading}/react-and-redux.md +0 -0
- data/docs/{additional_reading/react_router.md → additional-reading/react-router.md} +5 -3
- data/docs/{recommended-project-structure.md → additional-reading/recommended-project-structure.md} +22 -0
- data/docs/{additional_reading/rspec_configuration.md → additional-reading/rspec-configuration.md} +0 -0
- data/docs/{additional_reading/server_rendering_tips.md → additional-reading/server-rendering-tips.md} +0 -0
- data/docs/{additional_reading → additional-reading}/tips.md +0 -0
- data/docs/{additional_reading → additional-reading}/turbolinks.md +0 -0
- data/docs/{additional_reading → additional-reading}/updating-dependencies.md +0 -0
- data/docs/{additional_reading → additional-reading}/webpack.md +0 -0
- data/docs/{contributing.md → contributor-info/contributing.md} +0 -0
- data/docs/{generator_testing.md → contributor-info/generator-testing.md} +0 -0
- data/docs/{releasing.md → contributor-info/releasing.md} +0 -0
- data/docs/{code_of_conduct.md → misc/code_of_conduct.md} +0 -0
- data/docs/{doctrine.md → misc/doctrine.md} +1 -1
- data/docs/{rails3.md → misc/rails3.md} +0 -0
- data/docs/{tutorial-v2.md → tutorial.md} +4 -4
- data/lib/react_on_rails/configuration.rb +6 -3
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +1 -1
- data/lib/react_on_rails/test_helper.rb +1 -1
- data/lib/react_on_rails/version.rb +1 -1
- data/package.json +1 -1
- metadata +26 -27
- data/docs/additional_reading/hot-reloading-rails-development.md +0 -32
- data/docs/additional_reading/manual_installation.md +0 -117
- 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,
|
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 =
|
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
|
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(
|
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 =
|
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
|
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}#{
|
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
|
-
|
240
|
-
|
241
|
-
|
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(
|
256
|
-
|
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
|
275
|
-
|
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
|
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
|
-
|
325
|
-
|
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
|
329
|
-
|
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
|
333
|
-
|
391
|
+
def trace_option(val)
|
392
|
+
val.nil? ? ReactOnRails.configuration.trace : val
|
334
393
|
end
|
335
394
|
|
336
|
-
def
|
337
|
-
|
395
|
+
def prerender_option(val)
|
396
|
+
val.nil? ? ReactOnRails.configuration.prerender : val
|
338
397
|
end
|
339
398
|
|
340
|
-
|
341
|
-
|
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"
|
File without changes
|
data/docs/{additional_reading/heroku_deployment.md → additional-reading/heroku-deployment.md}
RENAMED
File without changes
|
@@ -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.
|
File without changes
|
data/docs/{additional_reading → additional-reading}/rails_view_rendering_from_inline_javascript.md
RENAMED
File without changes
|
File without changes
|
@@ -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,
|
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) => {
|
data/docs/{recommended-project-structure.md → additional-reading/recommended-project-structure.md}
RENAMED
@@ -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.
|
data/docs/{additional_reading/rspec_configuration.md → additional-reading/rspec-configuration.md}
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -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](
|
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
|
1
|
+
# Tutorial for React on Rails
|
2
2
|
|
3
|
-
|
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
|
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/
|
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/
|
27
|
+
# See docs/additional-reading/rspec-configuration.md for more info
|
28
28
|
#
|
29
29
|
# Params:
|
30
30
|
# config - config for rspec
|