react_on_rails 6.0.5 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc +2 -3
- data/.gitignore +1 -1
- data/.travis.yml +15 -13
- data/CHANGELOG.md +27 -15
- data/{docs/contributor-info/contributing.md → CONTRIBUTING.md} +24 -1
- data/Gemfile +1 -1
- data/KUDOS.md +3 -0
- data/NEWS.md +3 -0
- data/PROJECTS.md +1 -1
- data/README.md +143 -202
- data/app/helpers/react_on_rails_helper.rb +29 -17
- data/docs/additional-reading/node-server-rendering.md +127 -7
- data/docs/additional-reading/rails-assets.md +74 -10
- data/docs/additional-reading/react-router.md +1 -1
- data/docs/additional-reading/server-rendering-tips.md +3 -0
- data/docs/api/javascript-api.md +23 -0
- data/docs/contributor-info/releasing.md +1 -1
- data/docs/misc/doctrine.md +6 -6
- data/docs/tutorial.md +74 -93
- data/lib/generators/USAGE +5 -1
- data/lib/generators/react_on_rails/base_generator.rb +2 -2
- data/lib/generators/react_on_rails/install_generator.rb +8 -0
- data/lib/generators/react_on_rails/node_generator.rb +22 -0
- data/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md +1 -1
- data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +3 -2
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +7 -3
- data/lib/generators/react_on_rails/templates/node/base/client/node/package.json +10 -0
- data/lib/generators/react_on_rails/templates/node/base/client/node/server.js +87 -0
- data/lib/react_on_rails/assets_precompile.rb +112 -0
- data/lib/react_on_rails/configuration.rb +1 -1
- data/lib/react_on_rails/server_rendering_pool.rb +1 -0
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +1 -1
- data/lib/react_on_rails/utils.rb +1 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +3 -2
- data/lib/tasks/assets.rake +10 -73
- data/package.json +9 -7
- metadata +7 -5
- data/Dockerfile_tests +0 -12
- data/docker-compose.yml +0 -11
@@ -341,29 +341,41 @@ ReactOnRails.setStore('#{store_name}', store);
|
|
341
341
|
|
342
342
|
# This is the definitive list of the default values used for the rails_context, which is the
|
343
343
|
# second parameter passed to both component and store generator functions.
|
344
|
+
# rubocop:disable Metrics/AbcSize
|
344
345
|
def rails_context(server_side:)
|
345
346
|
@rails_context ||= begin
|
346
|
-
# Using Addressable instead of standard URI to better deal with
|
347
|
-
# non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
|
348
|
-
uri = Addressable::URI.parse(request.original_url)
|
349
|
-
# uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
|
350
|
-
|
351
347
|
result = {
|
352
|
-
|
353
|
-
href: request.original_url,
|
354
|
-
location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
|
355
|
-
scheme: uri.scheme, # http
|
356
|
-
host: uri.host, # foo.com
|
357
|
-
port: uri.port,
|
358
|
-
pathname: uri.path, # /posts
|
359
|
-
search: uri.query, # id=30&limit=5
|
360
|
-
|
348
|
+
inMailer: controller.present? && controller.is_a?(ActionMailer::Base),
|
361
349
|
# Locale settings
|
362
350
|
i18nLocale: I18n.locale,
|
363
|
-
i18nDefaultLocale: I18n.default_locale
|
364
|
-
httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
|
351
|
+
i18nDefaultLocale: I18n.default_locale
|
365
352
|
}
|
366
|
-
|
353
|
+
if request.present?
|
354
|
+
# Check for encoding of the request's original_url and try to force-encoding the
|
355
|
+
# URLs as UTF-8. This situation can occur in browsers that do not encode the
|
356
|
+
# entire URL as UTF-8 already, mostly on the Windows platform (IE11 and lower).
|
357
|
+
original_url_normalized = request.original_url
|
358
|
+
if original_url_normalized.encoding.to_s == "ASCII-8BIT"
|
359
|
+
original_url_normalized = original_url_normalized.force_encoding("ISO-8859-1").encode("UTF-8")
|
360
|
+
end
|
361
|
+
|
362
|
+
# Using Addressable instead of standard URI to better deal with
|
363
|
+
# non-ASCII characters (see https://github.com/shakacode/react_on_rails/pull/405)
|
364
|
+
uri = Addressable::URI.parse(original_url_normalized)
|
365
|
+
# uri = Addressable::URI.parse("http://foo.com:3000/posts?id=30&limit=5#time=1305298413")
|
366
|
+
|
367
|
+
result.merge!(
|
368
|
+
# URL settings
|
369
|
+
href: uri.to_s,
|
370
|
+
location: "#{uri.path}#{uri.query.present? ? "?#{uri.query}" : ''}",
|
371
|
+
scheme: uri.scheme, # http
|
372
|
+
host: uri.host, # foo.com
|
373
|
+
port: uri.port,
|
374
|
+
pathname: uri.path, # /posts
|
375
|
+
search: uri.query, # id=30&limit=5
|
376
|
+
httpAcceptLanguage: request.env["HTTP_ACCEPT_LANGUAGE"]
|
377
|
+
)
|
378
|
+
end
|
367
379
|
if ReactOnRails.configuration.rendering_extension
|
368
380
|
custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
|
369
381
|
result.merge!(custom_context) if custom_context
|
@@ -1,18 +1,32 @@
|
|
1
|
-
|
1
|
+
# Node.js for Server Rendering
|
2
2
|
|
3
|
-
|
3
|
+
Node.js can be used as the backend for server-side rendering instead of [execJS](https://github.com/rails/execjs). Before you try this, consider the tradeoff of extra complexity with your deployments versus *potential* performance gains. We've found that using ExecJS with [mini_racer](https://github.com/discourse/mini_racer) to be "fast enough" so far. That being said, we've heard of other large websites using Node.js for better server rendering performance.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
If you're serious about this comparing Node.js versus execJS/mini_racer, then [get in touch](mailto:justin@shakacode.com)! We can definitely collaborate with you on refining this solution. However, please try out these instructions first.
|
6
|
+
|
7
|
+
## Setup of React on Rails with Node.js Server Rendering
|
8
|
+
**Warning: this is an experimental feature.**
|
9
|
+
|
10
|
+
* Every time the webpack bundle changes, you have to restart the server yourself.
|
11
|
+
|
12
|
+
To do this you need to add a few files and then configure react_on_rails to use NodeJS. Here are the relevant files to add.
|
13
|
+
|
14
|
+
Node server rendering allows you to use separate NodeJS process as a renderer. The process loads your configured server_bundle_js file and then executes javascript to render the component inside its environment. The communication between rails and node occurs
|
15
|
+
via a socket (`client/node/node.sock`)
|
9
16
|
|
10
17
|
### Getting started
|
11
18
|
|
19
|
+
### Configuration
|
20
|
+
|
21
|
+
#### Update the React on Rails Initializer
|
22
|
+
|
12
23
|
To use node process just set `server_render_method = "NodeJS"` in `config/initializers/react_on_rails.rb`. To change back
|
13
24
|
to ExecJS set `server_render_method = "ExecJS"`
|
14
25
|
|
15
|
-
|
26
|
+
```ruby
|
27
|
+
# app/config/initializers/react_on_rails.rb
|
28
|
+
config.server_render_method = "NodeJS"
|
29
|
+
```
|
16
30
|
|
17
31
|
You need to configure the name of the server bundle in two places:
|
18
32
|
|
@@ -26,3 +40,109 @@ You need to configure the name of the server bundle in two places:
|
|
26
40
|
# not affect performance.
|
27
41
|
config.server_bundle_js_file = "webpack-bundle.js"
|
28
42
|
```
|
43
|
+
|
44
|
+
And in `client/node/package.json`
|
45
|
+
|
46
|
+
```javascript
|
47
|
+
// client/node/package.json
|
48
|
+
{
|
49
|
+
"name": "react_on_rails_node",
|
50
|
+
"version": "0.0.0",
|
51
|
+
"private": true,
|
52
|
+
"scripts": {
|
53
|
+
"start": "node ./server.js -s webpack-bundle.js"
|
54
|
+
},
|
55
|
+
"dependencies": {
|
56
|
+
}
|
57
|
+
}
|
58
|
+
```
|
59
|
+
|
60
|
+
And you'll need this file: `client/node/server.js`
|
61
|
+
|
62
|
+
```javascript
|
63
|
+
// client/node/server.js
|
64
|
+
var net = require('net');
|
65
|
+
var fs = require('fs');
|
66
|
+
|
67
|
+
var bundlePath = '../../app/assets/webpack/';
|
68
|
+
var bundleFileName = 'webpack-bundle.js';
|
69
|
+
|
70
|
+
var currentArg;
|
71
|
+
|
72
|
+
function Handler() {
|
73
|
+
this.queue = [];
|
74
|
+
this.initialized = false;
|
75
|
+
}
|
76
|
+
|
77
|
+
Handler.prototype.handle = function (connection) {
|
78
|
+
var callback = function () {
|
79
|
+
connection.setEncoding('utf8');
|
80
|
+
connection.on('data', (data)=> {
|
81
|
+
console.log('Processing request: ' + data);
|
82
|
+
var result = eval(data);
|
83
|
+
connection.write(result);
|
84
|
+
});
|
85
|
+
};
|
86
|
+
|
87
|
+
if (this.initialized) {
|
88
|
+
callback();
|
89
|
+
} else {
|
90
|
+
this.queue.push(callback);
|
91
|
+
}
|
92
|
+
};
|
93
|
+
|
94
|
+
Handler.prototype.initialize = function () {
|
95
|
+
console.log('Processing ' + this.queue.length + ' pending requests');
|
96
|
+
var callback;
|
97
|
+
while (callback = this.queue.pop()) {
|
98
|
+
callback();
|
99
|
+
}
|
100
|
+
|
101
|
+
this.initialized = true;
|
102
|
+
};
|
103
|
+
|
104
|
+
var handler = new Handler();
|
105
|
+
|
106
|
+
process.argv.forEach((val) => {
|
107
|
+
if (val[0] == '-') {
|
108
|
+
currentArg = val.slice(1);
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
|
112
|
+
if (currentArg == 's') {
|
113
|
+
bundleFileName = val;
|
114
|
+
}
|
115
|
+
});
|
116
|
+
|
117
|
+
try {
|
118
|
+
fs.mkdirSync(bundlePath);
|
119
|
+
} catch (e) {
|
120
|
+
if (e.code != 'EEXIST') throw e;
|
121
|
+
}
|
122
|
+
|
123
|
+
fs.watchFile(bundlePath + bundleFileName, (curr) => {
|
124
|
+
if (curr && curr.blocks && curr.blocks > 0) {
|
125
|
+
if (handler.initialized) {
|
126
|
+
console.log('Reloading server bundle must be implemented by restarting the node process!');
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
|
130
|
+
require(bundlePath + bundleFileName);
|
131
|
+
console.log('Loaded server bundle: ' + bundlePath + bundleFileName);
|
132
|
+
handler.initialize();
|
133
|
+
}
|
134
|
+
});
|
135
|
+
|
136
|
+
var unixServer = net.createServer(function (connection) {
|
137
|
+
handler.handle(connection);
|
138
|
+
});
|
139
|
+
|
140
|
+
unixServer.listen('node.sock');
|
141
|
+
|
142
|
+
process.on('SIGINT', () => {
|
143
|
+
unixServer.close();
|
144
|
+
process.exit();
|
145
|
+
});
|
146
|
+
|
147
|
+
```
|
148
|
+
|
@@ -1,19 +1,83 @@
|
|
1
|
-
|
1
|
+
# Rails assets and the Extract Text Plugin
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
The [Webpack file loader](https://github.com/webpack/file-loader) copies referenced files to
|
4
|
+
the destination output directory, with an MD5 hash. The other term for this is a "digest".
|
5
|
+
|
6
|
+
> By default the filename of the resulting file is the MD5 hash of the file's contents with
|
7
|
+
the original extension of the required resource.
|
8
|
+
|
9
|
+
The most common use cases for Webpack processed files are images used for backgrounds in
|
10
|
+
CSS and fonts for CSS. However, this applies to any file that might be processed using the
|
11
|
+
Webpack file loader.
|
12
|
+
|
13
|
+
## The Problem
|
14
|
+
To understand the problem, it helps to read this article:
|
15
|
+
[What is fingerprinting and why should I care](http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care-questionmark)
|
16
|
+
Basically, when Rails prepares assets for production deployments, it also adds a digest
|
17
|
+
to the file names. E.g., `img1.jpg` becomes `img1-dbu097452jf2v2.jpg`.
|
7
18
|
|
8
19
|
When compiling its native css Rails transforms all urls and links to digested
|
9
20
|
versions, i.e. `background-image: image-url(img1.jpg)` becomes
|
10
21
|
`background-image: url(img1-dbu097452jf2v2.jpg)`. However this doesn't happen for js and
|
11
22
|
css files compiled by webpack on the client side, because they don't use
|
12
|
-
`image-url` and `asset-url
|
23
|
+
`image-url` and `asset-url`. Without some fix, these assets would fail to load.
|
13
24
|
|
14
|
-
|
25
|
+
When Webpack's client JavaScript uses images in render methods, e.g. `<img src='...' />` or
|
26
|
+
in css, e.g. `background-image: url(...)` The code (such as the CSS) generated by the Webpack
|
27
|
+
will have the Webpack digested name (MD5 hash). Since the Webpack generated CSS expects
|
28
|
+
just one level of "digesting", this "double-digesting" from Rails will cause such these assets
|
29
|
+
fail to load.
|
15
30
|
|
16
|
-
|
17
|
-
|
18
|
-
|
31
|
+
## The Solution: Symlink Original File Names to New File Names
|
32
|
+
React on Rails creates symlinks of non-digested versions (original webpack digested file names)
|
33
|
+
to the Rails deployed digested versions when doing a Rails assets compile. The solution is
|
34
|
+
implemented using `assets:precompile` after-hook in
|
35
|
+
file [lib/tasks/assets.rake](../../lib/tasks/assets.rake)
|
36
|
+
The assets for symlinking are defined by `config.symlink_non_digested_assets_regex` in
|
37
|
+
`config/initializers/react_on_rails.rb`.
|
38
|
+
|
39
|
+
## Disabling the Symlinking
|
19
40
|
To disable symlinks set this parameter to `nil`.
|
41
|
+
|
42
|
+
|
43
|
+
## Example from /spec/dummy
|
44
|
+
|
45
|
+
If you run
|
46
|
+
|
47
|
+
```
|
48
|
+
cd spec/dummy
|
49
|
+
RAILS_ENV=production bundle exec rake assets:precompile
|
50
|
+
rails s -e production
|
51
|
+
```
|
52
|
+
|
53
|
+
You will see this. This shows how the file names output by rails. Note the original names after
|
54
|
+
being processed by Webpack are just MD5's.
|
55
|
+
|
56
|
+
```
|
57
|
+
I, [2016-07-17T23:46:56.301981 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/server-bundle-42935dea382802a27e91b7df444a2813f74b4e6a0fce5606d863aaa10c0623d7.js
|
58
|
+
I, [2016-07-17T23:46:56.305649 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/server-bundle-42935dea382802a27e91b7df444a2813f74b4e6a0fce5606d863aaa10c0623d7.js.gz
|
59
|
+
I, [2016-07-17T23:46:56.370390 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/application_static-dfa728160c3cdebc633c2f6fb3823411530b307044f4dfe460790eef00b4e421.js
|
60
|
+
I, [2016-07-17T23:46:56.370566 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/application_static-dfa728160c3cdebc633c2f6fb3823411530b307044f4dfe460790eef00b4e421.js.gz
|
61
|
+
I, [2016-07-17T23:46:56.372895 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/application_static-17ed778d5061d4797556632b7bfbf405e067d9e7f140060a7f56a09788251f16.css
|
62
|
+
I, [2016-07-17T23:46:56.373012 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/application_static-17ed778d5061d4797556632b7bfbf405e067d9e7f140060a7f56a09788251f16.css.gz
|
63
|
+
I, [2016-07-17T23:46:56.374531 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756-ab14eebb171a9a5c9bfdeb2f88933d2dc4904ea8bb09444984e52b13d230e251.svg
|
64
|
+
I, [2016-07-17T23:46:56.374818 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756-ab14eebb171a9a5c9bfdeb2f88933d2dc4904ea8bb09444984e52b13d230e251.svg.gz
|
65
|
+
I, [2016-07-17T23:46:56.392207 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/5cf5db49df178f9357603f945752a1ef-033650e1d6193b70d59bb60e773f47b6d9aefdd56abc7ccdba3c7bed4e57ccad.png
|
66
|
+
I, [2016-07-17T23:46:56.393208 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/8970f5e1e92aea933b502a2d73976b76-877bde3739dc7080c3fb00ee9012db6f21ed0dbbf11cd596dbb6e1a35bfb71f9.png
|
67
|
+
I, [2016-07-17T23:46:56.395490 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa-6d1ab3741d5a164dc2aab48bb74429aebe2e2e29606feca581081697624dc18c.ttf
|
68
|
+
I, [2016-07-17T23:46:56.395846 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa-6d1ab3741d5a164dc2aab48bb74429aebe2e2e29606feca581081697624dc18c.ttf.gz
|
69
|
+
I, [2016-07-17T23:46:56.396979 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0-5731789fd0d7847a582b52b55a83e7a0ad4684acd5a9b487557635a08c112d0e.svg
|
70
|
+
I, [2016-07-17T23:46:56.397669 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0-5731789fd0d7847a582b52b55a83e7a0ad4684acd5a9b487557635a08c112d0e.svg.gz
|
71
|
+
I, [2016-07-17T23:46:56.399261 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056-efba50c701b697fc8160603b9e876adcf47511f35af68701db285272c965a45f.svg
|
72
|
+
I, [2016-07-17T23:46:56.399660 #77382] INFO -- : Writing /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056-efba50c701b697fc8160603b9e876adcf47511f35af68701db285272c965a45f.svg.gz
|
73
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756-ab14eebb171a9a5c9bfdeb2f88933d2dc4904ea8bb09444984e52b13d230e251.svg to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756.svg
|
74
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756-ab14eebb171a9a5c9bfdeb2f88933d2dc4904ea8bb09444984e52b13d230e251.svg.gz to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/2ac2dd94f9b7e54292f6d051f1e4e756.svg.gz
|
75
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/5cf5db49df178f9357603f945752a1ef-033650e1d6193b70d59bb60e773f47b6d9aefdd56abc7ccdba3c7bed4e57ccad.png to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/5cf5db49df178f9357603f945752a1ef.png
|
76
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/8970f5e1e92aea933b502a2d73976b76-877bde3739dc7080c3fb00ee9012db6f21ed0dbbf11cd596dbb6e1a35bfb71f9.png to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/8970f5e1e92aea933b502a2d73976b76.png
|
77
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa-6d1ab3741d5a164dc2aab48bb74429aebe2e2e29606feca581081697624dc18c.ttf to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa.ttf
|
78
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa-6d1ab3741d5a164dc2aab48bb74429aebe2e2e29606feca581081697624dc18c.ttf.gz to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/ecb4572a5e478b107dfcb60c16a7eefa.ttf.gz
|
79
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0-5731789fd0d7847a582b52b55a83e7a0ad4684acd5a9b487557635a08c112d0e.svg to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0.svg
|
80
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0-5731789fd0d7847a582b52b55a83e7a0ad4684acd5a9b487557635a08c112d0e.svg.gz to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fbd0d00cc9b670f05c17893a40da08d0.svg.gz
|
81
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056-efba50c701b697fc8160603b9e876adcf47511f35af68701db285272c965a45f.svg to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056.svg
|
82
|
+
React On Rails: Symlinking /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056-efba50c701b697fc8160603b9e876adcf47511f35af68701db285272c965a45f.svg.gz to /Users/justin/shakacode/react_on_rails/spec/dummy/public/assets/fc2dcaaf2057331ff76c5d37e1aa7056.svg
|
83
|
+
```
|
@@ -3,7 +3,7 @@ React on Rails supports the use of React Router. Client-side code doesn't need a
|
|
3
3
|
|
4
4
|
However, when attempting to use server-rendering, it is necessary to take steps that prevent rendering when there is a router error or redirect. In these cases, the client code should return an object containing the `error` and a `redirectLocation` instead of the React component. The `react_component` helper method in your Rails view will automatically detect that there was an error/redirect and handle it accordingly.
|
5
5
|
|
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/
|
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/HelloWorldApp.jsx`.
|
7
7
|
|
8
8
|
```js
|
9
9
|
const RouterApp = (props, railsContext) => {
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# Server Rendering Tips
|
2
2
|
|
3
|
+
Be sure to use mini_racer. See [issues/428](https://github.com/shakacode/react_on_rails/issues/428)
|
4
|
+
|
3
5
|
## General Tips
|
4
6
|
- Your code can't reference `document`. Server side JS execution does not have access to `document`, so jQuery and some
|
5
7
|
other libs won't work in this environment. You can debug this by putting in `console.log`
|
@@ -8,6 +10,7 @@
|
|
8
10
|
component. Since the passed in props Hash from the view helper applies to client and server side code, the best way to
|
9
11
|
do this is to use a generator function.
|
10
12
|
- If you're serious about server rendering, it's worth the effort to have different entry points for client and server rendering. It's worth the extra complexity.
|
13
|
+
- You can enable node server rendering if you want. See more information here: https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/node-server-rendering.md
|
11
14
|
|
12
15
|
The point is that you have separate files for top level client or server side, and you pass some extra option indicating that rendering is happening server side.
|
13
16
|
|
data/docs/api/javascript-api.md
CHANGED
@@ -34,4 +34,27 @@ The best source of docs is the main [ReactOnRails.js](../../node_package/src/Rea
|
|
34
34
|
* `traceTurbolinks: true|false Gives you debugging messages on Turbolinks events
|
35
35
|
*/
|
36
36
|
setOptions(options)
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Allow directly calling the page loaded script in case the default events that trigger react
|
40
|
+
* rendering are not sufficient, such as when loading JavaScript asynchronously with TurboLinks:
|
41
|
+
* More details can be found here:
|
42
|
+
* https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/turbolinks.md
|
43
|
+
*/
|
44
|
+
reactOnRailsPageLoaded()
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Returns CSRF authenticity token inserted by Rails csrf_meta_tags
|
48
|
+
* @returns String or null
|
49
|
+
*/
|
50
|
+
|
51
|
+
authenticityToken()
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Returns header with csrf authenticity token and XMLHttpRequest
|
55
|
+
* @param {*} other headers
|
56
|
+
* @returns {*} header
|
57
|
+
*/
|
58
|
+
|
59
|
+
authenticityHeaders(otherHeaders = {})
|
37
60
|
```
|
@@ -3,7 +3,7 @@
|
|
3
3
|
We're now releasing this as a combined ruby gem plus npm package. We will keep the version numbers in sync.
|
4
4
|
|
5
5
|
## Testing the Gem before Release from a Rails App
|
6
|
-
See [Contributing](
|
6
|
+
See [Contributing](../../CONTRIBUTING.md)
|
7
7
|
|
8
8
|
## Releasing a new gem version
|
9
9
|
Run `rake -D release` to see instructions on how to release via the rake task.
|
data/docs/misc/doctrine.md
CHANGED
@@ -4,7 +4,7 @@ By Justin Gordon, January 26, 2016
|
|
4
4
|
|
5
5
|
This document is an extension and complement to [The Rails Doctrine](http://rubyonrails.org/doctrine/). If you haven't read that document, I suggest you do so first.
|
6
6
|
|
7
|
-
As stated in the [React on Rails README](
|
7
|
+
As stated in the [React on Rails README](../../README.md), the project objective is to provide an opinionated and optimal framework for integrating **Ruby on Rails** with modern JavaScript tooling and libraries. When considering what goes into **react_on_rails**, we ask ourselves, is the functionality related to the intersection of using Rails and with modern JavaScript? A good example is view helper integration of React components on a Rails view. If the answer is yes, then the functionality belongs right here. In other cases, we're releasing separate npm packages or Ruby gems. For example, we needed an easy way to integrate [Twitter Bootstrap](http://getbootstrap.com/) with Webpack, and we released the [npm bootstrap-loader](https://github.com/shakacode/bootstrap-loader/).
|
8
8
|
|
9
9
|
Besides the project objective, let's stick with the "Rails Doctrine" and keep the following in mind.
|
10
10
|
|
@@ -19,13 +19,13 @@ 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/
|
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:
|
26
|
-
* [Style Guide](coding-style/style.md)
|
27
|
-
* [linters](
|
28
|
-
* [Recommended Project Structure](recommended-project-structure.md)
|
26
|
+
* [Style Guide](../coding-style/style.md)
|
27
|
+
* [linters](../contributor-info/linters.md)
|
28
|
+
* [Recommended Project Structure](../additional-reading/recommended-project-structure.md)
|
29
29
|
|
30
30
|
We're big believers in this quote from the Rails Doctrine:
|
31
31
|
|
@@ -61,7 +61,7 @@ ES5 was ugly. ES6 is beautiful. React is beautiful. Client side code written wit
|
|
61
61
|
Assuming that you're building the type of app that's a good fit for Rails (document/database based with lots of business rules), the tight integration of modern JavaScript with React on top of Ruby on Rails is better than building a pure client side app and separate microservices. Here's why:
|
62
62
|
|
63
63
|
* Via React on Rails, we can seamlessly integrate React UI components with Rails.
|
64
|
-
* Tight integration allows for trivial set up of server rendering of React on top of Rails, complete with support for fragment caching of the server rendered HTML, and integration with [Turbolinks](https://github.com/
|
64
|
+
* Tight integration allows for trivial set up of server rendering of React on top of Rails, complete with support for fragment caching of the server rendered HTML, and integration with [Turbolinks](https://github.com/turbolinks/turbolinks).
|
65
65
|
* Tight integration allows mixing and matching Rails pages with React driven pages, even on the same page. Not every part of a UI requires the high fidelity achievable using React. Many existing apps may have hundreds of standards Rails forms. Support for mixing and matching React with Rails forms provides the best of both worlds.
|
66
66
|
|
67
67
|
## Progress over Stability
|
data/docs/tutorial.md
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
*Version 5.2 and greater have removed the non-essential options. See the [changelog](../CHANGELOG.md) for details on what was removed.*
|
1
|
+
# React on Rails Basic Tutorial
|
4
2
|
|
5
3
|
This tutorial setups up a new Rails app with **React on Rails**, demonstrating Rails + React + Redux + Server Rendering.
|
6
4
|
|
7
|
-
|
5
|
+
After finishing this tutorial you will get application that can do the following (live on Heroku):
|
6
|
+
|
7
|
+
![example](https://cloud.githubusercontent.com/assets/371302/17368567/111cc722-596b-11e6-9b72-ac5967a60e42.gif)
|
8
|
+
|
9
|
+
You can find here:
|
10
|
+
* [Source code for this app](https://github.com/dzirtusss/hello-react-on-rails)
|
11
|
+
* [Live on Heroku](https://hello-react-on-rails.herokuapp.com/)
|
8
12
|
|
9
|
-
|
13
|
+
Old version of this app is here:
|
14
|
+
* [Source code](https://github.com/justin808/test-react-on-rails-3)
|
10
15
|
* [Live on Heroku](https://shakacode-react-on-rails.herokuapp.com/hello_world)
|
11
16
|
|
12
17
|
By the time you read this, the latest may have changed. Be sure to check the versions here:
|
@@ -14,116 +19,84 @@ By the time you read this, the latest may have changed. Be sure to check the ver
|
|
14
19
|
* https://rubygems.org/gems/react_on_rails
|
15
20
|
* https://www.npmjs.com/package/react-on-rails
|
16
21
|
|
17
|
-
|
22
|
+
##Setting up the environment
|
18
23
|
|
19
|
-
|
20
|
-
cd <directory where you want to create your new Rails app>
|
21
|
-
# any name you like
|
22
|
-
rails new test-react-on-rails-3
|
23
|
-
cd test-react-on-rails-3
|
24
|
-
# git-extras command to make a new git repo and commit everything
|
25
|
-
git setup
|
26
|
-
vim Gemfile
|
27
|
-
```
|
24
|
+
Trying out **React on Rails** 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. Rails can be installed as ordinary gem.
|
28
25
|
|
29
|
-
Add this line to your Gemfile:
|
30
|
-
|
31
|
-
```
|
32
|
-
gem 'react_on_rails'
|
33
26
|
```
|
27
|
+
nvm install node # download and install latest stable Node
|
28
|
+
nvm alias default node # make it default version
|
29
|
+
nvm list # check
|
34
30
|
|
31
|
+
rvm install 2.3.1 # download and install latest stable Ruby (update to exact version)
|
32
|
+
rvm use 2.3.1 --default # use it and make it default
|
33
|
+
rvm list # check
|
35
34
|
|
36
|
-
|
37
|
-
bundle
|
38
|
-
bundle exec rails generate react_on_rails:install -R -S -H -L
|
39
|
-
bundle && npm i
|
40
|
-
npm run rails-server
|
35
|
+
gem install rails # download and install latest stable Rails
|
41
36
|
```
|
42
37
|
|
43
|
-
|
44
|
-
* S => Server Rendering
|
45
|
-
* H => Heroku setup
|
46
|
-
* L => Linters
|
38
|
+
Then we need to create a fresh Rails application as following:
|
47
39
|
|
48
|
-
|
49
|
-
Visit http://localhost:3000/hello_world and see your React On Rails app running!
|
50
|
-
|
51
|
-
```
|
52
|
-
npm run express-server
|
53
40
|
```
|
41
|
+
cd <basic directory where you want to create your new Rails app>
|
54
42
|
|
55
|
-
|
56
|
-
|
57
|
-
Visit http://localhost:4000 and see your React On Rails app running using the Webpack Dev server.
|
58
|
-
|
59
|
-
With this setup, you can make changes to your JS or CSS and the browser will hot reload the changes (no page refresh required).
|
43
|
+
rails new test-react-on-rails # any name you like
|
60
44
|
|
61
|
-
|
62
|
-
|
63
|
-
```html
|
64
|
-
<h1>Welcome to React On Rails!</h1>
|
45
|
+
cd test-react-on-rails
|
65
46
|
```
|
66
47
|
|
67
|
-
|
68
|
-
|
69
|
-
If you save, you'll soon see this screen:
|
70
|
-
|
71
|
-
<img src="http://forum.shakacode.com/uploads/default/original/1X/228706a99a411548a4539f72446d3f115ed36f95.png" width="555" height="500">
|
72
|
-
|
48
|
+
![01](https://cloud.githubusercontent.com/assets/20628911/17464917/3c29e55a-5cf2-11e6-8754-046ba3ee92d9.png)
|
73
49
|
|
74
|
-
|
50
|
+
Add **React On Rails** gem to your Gemfile (`vim Gemfile` or `nano Gemfile` or in IDE):
|
75
51
|
|
76
|
-
|
77
|
-
|
78
|
-
|
52
|
+
```
|
53
|
+
gem 'react_on_rails', '~>6' # use latest gem version > 6
|
54
|
+
```
|
79
55
|
|
80
|
-
|
56
|
+
![02](https://cloud.githubusercontent.com/assets/20628911/17464919/3c2d74c2-5cf2-11e6-8704-a84958832fbb.png)
|
81
57
|
|
82
|
-
|
58
|
+
put everything under git repository (or `rails generate` will not work properly)
|
83
59
|
|
84
60
|
```
|
85
|
-
|
86
|
-
|
61
|
+
# Here are git commands to make a new git repo and commit everything
|
62
|
+
git init
|
63
|
+
git add -A
|
64
|
+
git commit -m "Initial commit"
|
87
65
|
```
|
88
66
|
|
89
|
-
|
67
|
+
update dependencies and generate empty app via `react_on_rails:install`. If you haven't done first git commit it will generate error and you just need to commit.
|
90
68
|
|
91
|
-
|
69
|
+
```
|
70
|
+
bundle
|
71
|
+
rails generate react_on_rails:install
|
72
|
+
bundle && npm install
|
73
|
+
```
|
92
74
|
|
93
|
-
|
75
|
+
![03](https://cloud.githubusercontent.com/assets/20628911/17464918/3c2c1f00-5cf2-11e6-9525-7b2e15659e01.png)
|
94
76
|
|
95
|
-
|
77
|
+
and then run server with
|
96
78
|
|
97
79
|
```
|
98
|
-
|
80
|
+
foreman start -f Procfile.dev
|
81
|
+
```
|
99
82
|
|
100
|
-
|
101
|
-
Running Rubocop Linters via `rubocop -S -D .`
|
102
|
-
rubocop -S -D .
|
103
|
-
Warning: Deprecated pattern style '/Users/justin/scratch/test-react-on-rails-3/client/node_modules/**/*' in /Users/justin/scratch/test-react-on-rails-3/.rubocop.yml
|
104
|
-
Inspecting 22 files
|
105
|
-
......................
|
83
|
+
![04](https://cloud.githubusercontent.com/assets/20628911/17464921/3c2fdb40-5cf2-11e6-9343-6afa53593a70.png)
|
106
84
|
|
107
|
-
22 files inspected, no offenses detected
|
108
|
-
Running ruby-lint Linters via `ruby-lint app config spec lib`
|
109
|
-
ruby-lint app config spec lib
|
110
|
-
scss-lint found no lints
|
111
|
-
Running eslint via `cd client && npm run eslint . -- --ext .jsx,.js`
|
112
|
-
cd client && npm run eslint . -- --ext .jsx,.js
|
113
85
|
|
114
|
-
|
115
|
-
> eslint --ext .js,.jsx . "." "--ext" ".jsx,.js"
|
86
|
+
Visit http://localhost:3000/hello_world and see your **React On Rails** app running!
|
116
87
|
|
117
|
-
|
118
|
-
cd client && npm run jscs .
|
88
|
+
![05](https://cloud.githubusercontent.com/assets/20628911/17464920/3c2e8ae2-5cf2-11e6-9e30-5ec5f9e2cbc6.png)
|
119
89
|
|
120
|
-
|
121
|
-
> jscs --verbose . "."
|
90
|
+
### Custom IP & PORT setup (Cloud9 example)
|
122
91
|
|
123
|
-
|
124
|
-
|
92
|
+
In case you are running some custom setup with different IP or PORT you should also edit Procfile.dev. For example to be able to run on free Cloud9 IDE we are putting IP 0.0.0.0 and PORT 8080
|
93
|
+
|
94
|
+
``` Procfile.dev
|
95
|
+
web: rails s -p 8080 -b 0.0.0.0
|
125
96
|
```
|
126
97
|
|
98
|
+
Then visit https://your-shared-addr.c9users.io:8080/hello_world
|
99
|
+
|
127
100
|
## RubyMine
|
128
101
|
|
129
102
|
It's super important to exclude certain directories from RubyMine or else it will slow to a crawl as it tries to parse all the npm files.
|
@@ -131,9 +104,6 @@ It's super important to exclude certain directories from RubyMine or else it wil
|
|
131
104
|
* `app/assets/webpack`
|
132
105
|
* `client/node_modules`
|
133
106
|
|
134
|
-
<img src="http://forum.shakacode.com/uploads/default/original/1X/a1b3e1146d86915f7d5d1c89548e81ec208458cc.png" width="338" height="500">
|
135
|
-
|
136
|
-
|
137
107
|
## Deploying to Heroku
|
138
108
|
|
139
109
|
### Create Your Heroku App
|
@@ -141,7 +111,7 @@ It's super important to exclude certain directories from RubyMine or else it wil
|
|
141
111
|
|
142
112
|
1. Visit https://dashboard.heroku.com/new and create an app, say named `my-name-react-on-rails`:
|
143
113
|
|
144
|
-
|
114
|
+
![06](https://cloud.githubusercontent.com/assets/20628911/17465014/1f29bf3c-5cf4-11e6-869f-4215987ae854.png)
|
145
115
|
|
146
116
|
Run this command that looks like this from your new heroku app
|
147
117
|
|
@@ -161,6 +131,9 @@ Set heroku to use multiple buildpacks:
|
|
161
131
|
gem 'pg'
|
162
132
|
```
|
163
133
|
|
134
|
+
![07](https://cloud.githubusercontent.com/assets/20628911/17465015/1f2f4042-5cf4-11e6-8287-2fb077550809.png)
|
135
|
+
|
136
|
+
|
164
137
|
2. Replace your `database.yml` file with this (assuming your app name is "ror").
|
165
138
|
|
166
139
|
```yml
|
@@ -190,25 +163,33 @@ Then you need to setup postgres so you can run locally:
|
|
190
163
|
|
191
164
|
```
|
192
165
|
bundle
|
193
|
-
|
194
|
-
|
166
|
+
rake db:setup
|
167
|
+
rake db:migrate
|
195
168
|
```
|
196
169
|
|
170
|
+
![08](https://cloud.githubusercontent.com/assets/20628911/17465016/1f3559f0-5cf4-11e6-8ab4-c5572e4644a5.png)
|
171
|
+
|
197
172
|
I'd recommend adding this line to the top of your `routes.rb`. That way, your root page will go to the Hello World page for React On Rails.
|
198
173
|
|
199
174
|
```ruby
|
200
175
|
root "hello_world#index"
|
201
176
|
```
|
202
177
|
|
203
|
-
|
178
|
+
![09](https://cloud.githubusercontent.com/assets/20628911/17465018/1f3b685e-5cf4-11e6-93f8-105fc48517d0.png)
|
204
179
|
|
205
|
-
Then push your app to Heroku!
|
180
|
+
Then after all changes are done don't forget to commit them with git and finally you can push your app to Heroku!
|
206
181
|
|
207
|
-
|
182
|
+
```
|
183
|
+
git add -A
|
184
|
+
git commit -m "Latest changes"
|
185
|
+
git push heroku master
|
186
|
+
```
|
208
187
|
|
209
|
-
|
188
|
+
![10](https://cloud.githubusercontent.com/assets/20628911/17465017/1f38fbaa-5cf4-11e6-8d86-a3d91e3878e0.png)
|
210
189
|
|
211
|
-
|
212
|
-
|
190
|
+
Here it is:
|
191
|
+
|
192
|
+
* [Source code for this sample app](https://github.com/dzirtusss/hello-react-on-rails)
|
193
|
+
* [Live on Heroku](https://hello-react-on-rails.herokuapp.com/)
|
213
194
|
|
214
195
|
Feedback is greatly appreciated! As are stars on github!
|