rails, react, hypernovaの環境構築からのHello World！

# 概要

rails、nodejs環境をVMに構築して、サーバサイドレンダリング用ライブラリであるHypernovaの環境構築から、Hello worldまでをメモ。

# 環境・バージョン
- Amazon linux2 (vagrant)
    - [こちらのVagrantfile](https://qiita.com/shunsuke_takahashi/items/48b8aee9afb1f030be3b)ですぐに立ち上がる。
- Vagrantfileを編集（下記をそれぞれ追記）
    - config.vm.network "forwarded_port", guest: 3000, host: 3000
    - config.vm.network "private_network", ip: "192.168.33.10"
    - config.vm.synced_folder ".", "/Vagrant"
- OS設定まわりを少し
    - UTC→JST
    - vagrantユーザ以外の個人ユーザを作成
    - timezone変更
    - hostname変更
    - export LANG=ja_JP.UTF-8 を.bash_profileに追記
    - yum install gcc-c++ openssl-devel git readline-devel sqlite-devel -y
    - yum update
    - rbenv、nvmインストール
- ruby, nodejsインストール

```sh
# ruby/rails(rbenv)
$ rbenv -v
rbenv 1.1.1-28-gb943955
$ ruby -v
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]
$ gem -v
2.6.13
$ rails -v
Rails 5.1.4

# node/npm(nvm)
$ nvm --version
0.33.8
$ node -v
v7.9.0
$ npm -v
4.2.0
```



### 1. Railsアプリの作成
rails newでアプリを作成します。

```sh
$ rails new hypernova-getting-started-with-rails
```

### 2. Controllerの作成
`/welcome/index`で動作するcontrollerを作成します。

```sh
$ rails generate controller welcome index
```

### 3. browserify-railsの導入
Gemfile に以下の一行を追加してbundle installを行います。

```rb:Gemfile
gem "browserify-rails"
```

```sh
$ bundle install
Installing browserify-rails 4.2.0
```

### 4. JavaScriptの環境設定 (package.json)
以下のコマンドで`package.json`を作成し、必要なパッケージ情報などを追記します。

```sh
% npm init -y
```

```json:package.json
{
  "name": "hypernova-getting-started-with-rails",
  "private": true,
  "dependencies": {
    "hypernova": "^1.0.0",
    "hypernova-react": "^1.0.0",
    "react": "^15.1.0",
    "react-dom": "^15.1.0"
  },
  "devDependencies": {
    "browserify": "^13.0.1",
    "browserify-incremental": "^3.1.1"
  },
  "description": "This README would normally document whatever steps are necessary to get the application up and running.",
  "version": "1.0.0",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "fk2000",
  "license": "MIT"
}
```

`package.json`が用意できたら以下のコマンドを実行しJavaScriptのパッケージをインストールします。

```sh
% npm install
```

### 5. Hypernova/serverの設定
`Rails.root`ディレクトリに`hypernova.js`を作ります。

```js:hypernova.js
const hypernova = require('hypernova/server');

hypernova({
  devMode: true,

  getComponent(name) {
    if (name === 'MyComponent.js') {
      return require('./app/assets/javascripts/MyComponent.js');
    }
    return null;
  },

  port: 3030,
});
```

### 6. Hypernova/rubyの設定
Gemfileにhypernovaを追加することで、Ruby(Rails)用のHypernovaクライアントを読み込みます。

`Gemfile`に以下1行を追加し、`bundle install`を実行してインストールします。

```rb:Gemfile
gem "hypernova"
```

続いて、Railsアプリから先ほどのhypernova.jsに記述した`Hypernova/server`へアクセスするための設定を追加します。

`#{Rails.root}/config/initializers/hypernova.rb`として以下を作成します。

```rb:config/initializers/hypernova.rb
require 'hypernova'

Hypernova.configure do |config|
  config.host = 'localhost'
  config.port = 3030
end
```

`config.port`には`hypernova.js`に記載したポート番号「3030」と一致させます。


### 7. Hypernova/reactを使用したReactコンポーネント
`props.name`を受け取って表示し、クリックするとアラートを表示するだけのシンプルなReactコンポーネントを作成します。ファイルは`#{Rails.root}/app/assets/javascripts/`に`MyComponent.js`というファイル名としています。

```js:app/assets/javascripts/MyComponent.js
var React = require('react');
var renderReact = require('hypernova-react').renderReact;

function MyComponent(props) {
  return React.createElement('div', {
    onClick: function () {
      alert('Click handlers work.');
    },
  }, 'Hello, ' + props.name + '!');
}

module.exports = renderReact('MyComponent.js', MyComponent);
```

### 8. RailsアプリからHypernova呼び出し
`Hypernova/ruby`は2つのmethodを提供します。Hypernovaによるサーバサイドレンダリングをサポートする`around_filter`の`hypernova_render_support`と、Reactコンポーネントを`props`を指定してViewに読み込む`render_react_component`です。

以下のように、使用するControllerとViewで以下のように呼び出します。

```rb:app/controllers/welcome_controller.rb
class WelcomeController < ApplicationController
  around_filter :hypernova_render_support
  def index
  end
end
```

```html+erb:app/views/welcome/index.html.erb
<%= render_react_component('MyComponent.js', name: 'World') %>
```




さらに、Viewで読み込むJavaScriptファイルを指定するために、`app/views/layouts/application.html.erb`を修正します。`javascript_include_tag`の位置を`<head>`内から`</body>`の直前へ移動しています。

```udiff:app/views/layouts/application.html.erb
 <!DOCTYPE html>
 <html>
   <head>
     <title>HypernovaGettingStartedWithRails</title>
     <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
-    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
     <%= csrf_meta_tags %>
   </head>
   <body>
 
   <%= yield %>
 
+  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
   </body>
 </html>
```

### 9. 動作を確認してみる
Railsアプリを起動します。

```sh
% bin/rails server
```

起動したら、ブラウザで http://localhost:3000/welcome/index へアクセスします。

ところが、下記のように表示されます。
![screenshot-127.0.0.1-3000-2018-01-25-14-39-04-560.png](https://qiita-image-store.s3.amazonaws.com/0/2567/e6cb4d5f-44be-7006-0f3d-872fdb7f5504.png)

※参考にした記事ではwelcome_controller.rbに追加したメソッド名は「around_filter」となっていましたが、「undefined method `around_filter'」となり、「Did you mean? around_action」と出力されてたので下記のように変更しました。

```diff:変更後のapp/controllers/welcome_controller.rb
class WelcomeController < ApplicationController
- around_filter :hypernova_render_support
+ around_action :hypernova_render_support
  def index
  end
end
```

再度、rails s でrailsを再起動し、ブラウザを確認すると、`Hello, World!`と表示され、文字をクリックするとブラウザアラートボックスが表示されることが確認できます。

![20180125_rails_hypernova.png](https://qiita-image-store.s3.amazonaws.com/0/2567/dac7980e-93ab-2eff-6752-2702007203db.png)


ページのソースを確認してみると、該当部分は以下のようになっていると思います。

```js+erb
<div data-hypernova-key="MyComponentjs"></div>
<script type="application/json" data-hypernova-key="MyComponentjs"><!--{"name":"Hypernova"}--></script>
```

これは、 **サーバサイドレンダリングを利用していない** のですが、正しくアプリは動作しています。

サーバサイドレンダリング編へつづく。


# 参考URL
https://qiita.com/noriaki/items/e2dac69b9dd88334dd43