diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aa25fe3b0..8870a750e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ Contributors: please follow the recommendations outlined at [keepachangelog.com] ## [Unreleased] +## [6.0.5] +##### Added +- Node option for installer added as alternative for server rendering. + ## [6.0.4] ##### Fixed - Added polyfill for clearTimeout which is used by babel-polyfill. diff --git a/README.md b/README.md index 8c6163ac55..987fdb2d74 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Aloha from Justin Gordon and the [ShakaCode](http://www.shakacode.com) Team! We * On Twitter, follow [@railsonmaui](https://twitter.com/railsonmaui) and [@shakacode](https://twitter.com/shakacode) for updates on releases. # NEWS +* 2016-07-08: 6.0.5 added node option to the installer to easily setup alternative server renderer. * 2016-06-13: 6.0.4 shipped with a critical fix regarding a missing polyfill for `clearTimeout`, used by babel-polyfill. * 2016-06-06: 6.0.2 shipped with a critical fix if you are fragment caching the server generated React. * *See [NEWS.md](NEWS.md) for more notes over time.* diff --git a/lib/generators/react_on_rails/install_generator.rb b/lib/generators/react_on_rails/install_generator.rb index 580978715b..91be836f8c 100644 --- a/lib/generators/react_on_rails/install_generator.rb +++ b/lib/generators/react_on_rails/install_generator.rb @@ -17,6 +17,13 @@ class InstallGenerator < Rails::Generators::Base desc: "Install Redux gems and Redux version of Hello World Example. Default: false", aliases: "-R" + # --redux + class_option :node, + type: :boolean, + default: false, + desc: "Sets up node as a server rendering option. Default: false", + aliases: "-N" + # --ignore-warnings class_option :ignore_warnings, type: :boolean, @@ -46,6 +53,7 @@ def invoke_generators invoke "react_on_rails:base" invoke "react_on_rails:react_no_redux" unless options.redux? invoke "react_on_rails:react_with_redux" if options.redux? + invoke "react_on_rails:node" if options.node? end # NOTE: other requirements for existing files such as .gitignore or application. diff --git a/lib/generators/react_on_rails/node_generator.rb b/lib/generators/react_on_rails/node_generator.rb new file mode 100644 index 0000000000..becb69bb43 --- /dev/null +++ b/lib/generators/react_on_rails/node_generator.rb @@ -0,0 +1,22 @@ +require "rails/generators" + +module ReactOnRails + module Generators + class NodeGenerator < Rails::Generators::Base + Rails::Generators.hide_namespace(namespace) + source_root(File.expand_path("../templates", __FILE__)) + + def create_node_directory + empty_directory("client/node") + end + + def copy_base_redux_files + base_path = "node/base/" + %w(client/node/server.js + client/node/package.json).each do |file| + copy_file(base_path + file, file) + end + end + end + end +end diff --git a/lib/generators/react_on_rails/templates/node/base/client/node/package.json b/lib/generators/react_on_rails/templates/node/base/client/node/package.json new file mode 100644 index 0000000000..81a68cb174 --- /dev/null +++ b/lib/generators/react_on_rails/templates/node/base/client/node/package.json @@ -0,0 +1,10 @@ +{ + "name": "react_on_rails_node", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./server.js -s webpack-bundle.js" + }, + "dependencies": { + } +} \ No newline at end of file diff --git a/lib/generators/react_on_rails/templates/node/base/client/node/server.js b/lib/generators/react_on_rails/templates/node/base/client/node/server.js new file mode 100644 index 0000000000..5363abe997 --- /dev/null +++ b/lib/generators/react_on_rails/templates/node/base/client/node/server.js @@ -0,0 +1,82 @@ +var net = require('net'); +var fs = require('fs'); + +var bundlePath = '../../app/assets/webpack/'; +var bundleFileName = 'webpack-bundle.js'; + +var currentArg; + +function Handler() { + this.queue = []; + this.initialized = false; +} + +Handler.prototype.handle = function (connection) { + var callback = function () { + connection.setEncoding('utf8'); + connection.on('data', (data)=> { + console.log('Processing request: ' + data); + var result = eval(data); + connection.write(result); + }); + }; + + if (this.initialized) { + callback(); + } else { + this.queue.push(callback); + } +}; + +Handler.prototype.initialize = function () { + console.log('Processing ' + this.queue.length + ' pending requests'); + var callback; + while (callback = this.queue.pop()) { + callback(); + } + + this.initialized = true; +}; + +var handler = new Handler(); + +process.argv.forEach((val) => { + if (val[0] == '-') { + currentArg = val.slice(1); + return; + } + + if (currentArg == 's') { + bundleFileName = val; + } +}); + +try { + fs.mkdirSync(bundlePath); +} catch (e) { + if (e.code != 'EEXIST') throw e; +} + +fs.watchFile(bundlePath + bundleFileName, (curr) => { + if (curr && curr.blocks && curr.blocks > 0) { + if (handler.initialized) { + console.log('Reloading server bundle must be implemented by restarting the node process!'); + return; + } + + require(bundlePath + bundleFileName); + console.log('Loaded server bundle: ' + bundlePath + bundleFileName); + handler.initialize(); + } +}); + +var unixServer = net.createServer(function (connection) { + handler.handle(connection); +}); + +unixServer.listen('node.sock'); + +process.on('SIGINT', () => { + unixServer.close(); + process.exit(); +}); diff --git a/spec/react_on_rails/generators/install_generator_spec.rb b/spec/react_on_rails/generators/install_generator_spec.rb index 5efacafac8..68e7423b73 100644 --- a/spec/react_on_rails/generators/install_generator_spec.rb +++ b/spec/react_on_rails/generators/install_generator_spec.rb @@ -22,6 +22,18 @@ include_examples "react_with_redux_generator" end + context "--node" do + before(:all) { run_generator_test_with_args(%w(--node)) } + include_examples "base_generator", application_js: true + include_examples "node_generator" + end + + context "-N" do + before(:all) { run_generator_test_with_args(%w(-N)) } + include_examples "base_generator", application_js: true + include_examples "node_generator" + end + context "without existing application.js or application.js.coffee file" do before(:all) { run_generator_test_with_args([], application_js: false) } include_examples "base_generator", application_js: false diff --git a/spec/react_on_rails/support/shared_examples/node_generator.rb b/spec/react_on_rails/support/shared_examples/node_generator.rb new file mode 100644 index 0000000000..6d4f501fa4 --- /dev/null +++ b/spec/react_on_rails/support/shared_examples/node_generator.rb @@ -0,0 +1,6 @@ +shared_examples "node_generator" do + it "copies base redux files" do + %w(client/node/server.js + client/node/package.json).each { |file| assert_file(file) } + end +end