Skip to content

Commit 63aa9bc

Browse files
jbhatabjustin808
authored andcommitted
Add node server rendering as an option to the generator (#469)
1 parent 78cbcb7 commit 63aa9bc

File tree

11 files changed

+152
-1
lines changed

11 files changed

+152
-1
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. Items under
44
Contributors: please follow the recommendations outlined at [keepachangelog.com](http://keepachangelog.com/). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare to the latest release version.
55

66
## [Unreleased]
7-
7+
- Node option for installer added as alternative for server rendering [#469](https://github.com/shakacode/react_on_rails/pull/469) by [jbhatab](https://github.com/jbhatab).
88
- React on Rails server rendering now supports contexts outside of browser rendering, such as ActionMailer templates [#486](https://github.com/shakacode/react_on_rails/pull/486) by [eacaps](https://github.com/eacaps).
99
- React on Rails now correctly parses single-digit version strings from package.json [#491](https://github.com/shakacode/react_on_rails/pull/491) by [samphilipd ](https://github.com/samphilipd ).
1010
- Fixed assets symlinking to correctly use filenames with spaces. Begining in [#510](https://github.com/shakacode/react_on_rails/pull/510), ending in [#513](https://github.com/shakacode/react_on_rails/pull/513) by [dzirtusss](https://github.com/dzirtusss)

docs/additional-reading/node-server-rendering.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ If you're serious about this comparing Node.js versus execJS/mini_racer, then [g
77
## Setup of React on Rails with Node.js Server Rendering
88
**Warning: this is an experimental feature.**
99

10+
* Every time the webpack bundle changes, you have to restart the server yourself.
11+
1012
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.
1113

1214
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

docs/additional-reading/server-rendering-tips.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Be sure to use mini_racer. See [issues/428](https://github.com/shakacode/react_o
1010
component. Since the passed in props Hash from the view helper applies to client and server side code, the best way to
1111
do this is to use a generator function.
1212
- 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
1314

1415
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.
1516

lib/generators/USAGE

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ can pass the redux option if you'd like to have redux setup for you automaticall
99
to integrate the Redux state container framework. The necessary node modules
1010
will be automatically included for you.
1111

12+
* Node
13+
14+
Passing the --node generator option sets up the necessary files for node to render the react_components.
15+
1216
*******************************************************************************
1317

1418
After running the generator, you will want to:

lib/generators/react_on_rails/install_generator.rb

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ class InstallGenerator < Rails::Generators::Base
1717
desc: "Install Redux gems and Redux version of Hello World Example. Default: false",
1818
aliases: "-R"
1919

20+
# --redux
21+
class_option :node,
22+
type: :boolean,
23+
default: false,
24+
desc: "Sets up node as a server rendering option. Default: false",
25+
aliases: "-N"
26+
2027
# --ignore-warnings
2128
class_option :ignore_warnings,
2229
type: :boolean,
@@ -46,6 +53,7 @@ def invoke_generators
4653
invoke "react_on_rails:base"
4754
invoke "react_on_rails:react_no_redux" unless options.redux?
4855
invoke "react_on_rails:react_with_redux" if options.redux?
56+
invoke "react_on_rails:node" if options.node?
4957
end
5058

5159
# NOTE: other requirements for existing files such as .gitignore or application.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require "rails/generators"
2+
3+
module ReactOnRails
4+
module Generators
5+
class NodeGenerator < Rails::Generators::Base
6+
Rails::Generators.hide_namespace(namespace)
7+
source_root(File.expand_path("../templates", __FILE__))
8+
9+
def create_node_directory
10+
empty_directory("client/node")
11+
end
12+
13+
def copy_base_redux_files
14+
base_path = "node/base/"
15+
%w(client/node/server.js
16+
client/node/package.json).each do |file|
17+
copy_file(base_path + file, file)
18+
end
19+
end
20+
end
21+
end
22+
end

lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt

+4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,11 @@ ReactOnRails.configure do |config|
6767
config.skip_display_none = false
6868

6969
# The server render method - either ExecJS or NodeJS
70+
<%- if options.node? -%>
71+
config.server_render_method = "NodeJS"
72+
<%- else -%>
7073
config.server_render_method = "ExecJS"
74+
<%- end -%>
7175

7276
# Client js uses assets not digested by rails.
7377
# For any asset matching this regex, non-digested symlink will be created (what webpack's css wants)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "react_on_rails_node",
3+
"version": "0.0.0",
4+
"private": true,
5+
"scripts": {
6+
"start": "node ./server.js -s webpack-bundle.js"
7+
},
8+
"dependencies": {
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
var net = require('net');
2+
var fs = require('fs');
3+
4+
var bundlePath = '../../app/assets/webpack/';
5+
var bundleFileName = 'webpack-bundle.js';
6+
7+
var currentArg;
8+
9+
function Handler() {
10+
this.queue = [];
11+
this.initialized = false;
12+
}
13+
14+
Handler.prototype.handle = function (connection) {
15+
var callback = function () {
16+
connection.setEncoding('utf8');
17+
connection.on('data', (data)=> {
18+
console.log('Processing request: ' + data);
19+
var result = eval(data);
20+
connection.write(result);
21+
});
22+
};
23+
24+
if (this.initialized) {
25+
callback();
26+
} else {
27+
this.queue.push(callback);
28+
}
29+
};
30+
31+
Handler.prototype.initialize = function () {
32+
console.log('Processing ' + this.queue.length + ' pending requests');
33+
var callback;
34+
while (callback = this.queue.pop()) {
35+
callback();
36+
}
37+
38+
this.initialized = true;
39+
};
40+
41+
var handler = new Handler();
42+
43+
process.argv.forEach((val) => {
44+
if (val[0] == '-') {
45+
currentArg = val.slice(1);
46+
return;
47+
}
48+
49+
if (currentArg == 's') {
50+
bundleFileName = val;
51+
}
52+
});
53+
54+
try {
55+
fs.mkdirSync(bundlePath);
56+
} catch (e) {
57+
if (e.code != 'EEXIST') throw e;
58+
}
59+
60+
fs.watchFile(bundlePath + bundleFileName, (curr) => {
61+
if (curr && curr.blocks && curr.blocks > 0) {
62+
if (handler.initialized) {
63+
console.log('Reloading server bundle must be implemented by restarting the node process!');
64+
return;
65+
}
66+
67+
require(bundlePath + bundleFileName);
68+
console.log('Loaded server bundle: ' + bundlePath + bundleFileName);
69+
handler.initialize();
70+
}
71+
});
72+
73+
var unixServer = net.createServer(function (connection) {
74+
handler.handle(connection);
75+
});
76+
77+
unixServer.listen('node.sock');
78+
79+
process.on('SIGINT', () => {
80+
unixServer.close();
81+
process.exit();
82+
});

spec/react_on_rails/generators/install_generator_spec.rb

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
include_examples "react_with_redux_generator"
2323
end
2424

25+
context "--node" do
26+
before(:all) { run_generator_test_with_args(%w(--node)) }
27+
include_examples "base_generator", application_js: true
28+
include_examples "node_generator"
29+
end
30+
31+
context "-N" do
32+
before(:all) { run_generator_test_with_args(%w(-N)) }
33+
include_examples "base_generator", application_js: true
34+
include_examples "node_generator"
35+
end
36+
2537
context "without existing application.js or application.js.coffee file" do
2638
before(:all) { run_generator_test_with_args([], application_js: false) }
2739
include_examples "base_generator", application_js: false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
shared_examples "node_generator" do
2+
it "copies base redux files" do
3+
%w(client/node/server.js
4+
client/node/package.json).each { |file| assert_file(file) }
5+
end
6+
end

0 commit comments

Comments
 (0)