LoginSignup
14
15

More than 5 years have passed since last update.

React 触ってみたよ!

Last updated at Posted at 2016-06-03

React 触ってみた

  • 実は Qiita で記事書くの初めてです!どうぞお手柔らかに!
  • 世の流れにとり残されてる感があったので、重い腰をあげて React に触れてみたのでその備忘録。
  • できるだけモダンなフロントエンド開発をするための、素地を整えるところまでをゴールとする。

構成

方針

  • 開発環境は vagrant(ubuntu) でやる
  • 既存の Rails アプリケーションに乗せる
  • フロントエンドの管理に関するものは、すべて npm で管理する(gem ではやらない)
  • フロントエンドに関するコードはすべて app_root/frontend に置く
  • 自分で書いた js, jsx 部
    • app_root/app/assets/javascripts/dist/main.js に出力する
  • 外部ライブラリ js 部
    • app_root/app/assets/javascripts/dist/vendor.js に出力する
  • 自分で書いた css 部
    • app_root/app/assets/stylesheet/dist/main.css に出力する
  • 外部ライブラリ css 部
    • app_root/app/assets/stylesheet/dist/vendor.css に出力する

まず Rails から

軽くセットアップ

command
$ cd ~/
$ rails new react-test -d mysql
$ cd react-test
$ bin/rake db:create db:migrate

検証に必要な分だけの、最低限のコード書く

Gemfile.rb
gem 'slim-rails'
command
$ bin/rails g controller test
app/controllers/test_controller.rb
class TestController < ApplicationController
  def index
  end
end
app/views/test/index.html.slim
#container
config/routes.rb
root 'test#index'
command
$ bin/rails s -b 0.0.0.0

これで準備完了。

React 導入準備

node いれる

command
$ curl -L git.io/nodebrew | perl - setup
# .bashrc, .zshrc などに PATH 書く
export PATH=$HOME/.nodebrew/current/bin:$PATH
$ source ~/.zshrc
$ nodebrew ls-remote
# 20160603 時点での Stable は v5.11.1 だった(https://nodejs.org/en/blog/)
$ nodebrew install-binary v5.11.1
$ nodebrew use v5.11.1
$ node -v
v5.11.1
$ npm -v
3.8.6

app_root/frontend 以下の準備

command
$ cd ~/react-test
$ mkdir frontend
$ cd frontend
$ npm init
# とりあえず全部エンター押しとく

これで package.json がとりまできた。

パッケージ準備

React + ES6 + Babel + Webpack + gulp + Material Design Lite を使えるようにする

command
# React 用
$ npm install --save react react-dom react-router react-tap-event-plugin
# ES6, Babel, Webpack 用
$ npm install --save-dev babel babel-loader babel-core babel-preset-react babel-preset-es2015 webpack
# gulp 用
$ npm install --save-dev gulp gulp-autoprefixer gulp-concat gulp-concat-css gulp-ruby-sass gulp-webpack
# Material Design Lite 用
$ gulp install --save material-design-lite

--save は「パッケージ(≒プロジェクト)の実行に必要なパッケージの定義」らしい
--save-dev は「パッケージの開発に必要なパッケージの定義」らしい

package.json
{
  "name": "frontend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel": "^6.5.2",
    "babel-core": "^6.9.1",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.5.0",
    "gulp": "^3.9.1",
    "gulp-autoprefixer": "^3.1.0",
    "gulp-concat": "^2.6.0",
    "gulp-concat-css": "^2.3.0",
    "gulp-ruby-sass": "^2.0.6",
    "gulp-webpack": "^1.5.0",
    "webpack": "^1.13.1"
  },
  "dependencies": {
    "material-design-lite": "^1.1.3",
    "react": "^15.1.0",
    "react-dom": "^15.1.0",
    "react-router": "^2.4.1",
    "react-tap-event-plugin": "^1.0.0"
  }
}

ここまでで、package.json はこうなった。

ビルド周り

package.json
"scripts": {
  "build": "gulp build"
},

package.json を上記のように編集する。
これで、$ npm run build で、 $ gulp build が走るようになる。

command
$ cd ~/react-test/frontend
$ vim gulpfile.js
gulpfile.js
var gulp = require('gulp');
var webpack = require('gulp-webpack');
var concat = require('gulp-concat');
var sass = require('gulp-ruby-sass');
var autoprefixer = require('gulp-autoprefixer');
var concatCss = require('gulp-concat-css');

const JS_SRC = '';
const JS_DEST = '../app/assets/javascripts/dist';
const CSS_SRC = 'src/stylesheets/main.scss';
const CSS_DEST = '../app/assets/stylesheets/dist';

var webpackConfig = {
  entry: {
    main: './src/javascripts/main.js',
  },
  output: {
    filename: 'main.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel?presets[]=react,presets[]=es2015'
      }
    ]
  }
}

gulp.task('js:main', function() {
  gulp.src(JS_SRC)
  .pipe(webpack(webpackConfig))
  .pipe(gulp.dest(JS_DEST));
});

gulp.task('js:vendor', function() {
  gulp.src([
    'node_modules/material-design-lite/material.min.js'
  ])
  .pipe(concat('vendor.js'))
  .pipe(gulp.dest(JS_DEST));
});

gulp.task('css:main', function(){
  sass(CSS_SRC, { style: 'expanded', bundleExec: true })
  .pipe(autoprefixer())
  .pipe(concatCss('main.css'))
  .pipe(gulp.dest(CSS_DEST));
});

gulp.task('css:vendor', function() {
  gulp.src([
    'node_modules/material-design-lite/material.min.css'
  ])
  .pipe(concatCss('vendor.css'))
  .pipe(gulp.dest(CSS_DEST));
});

gulp.task('build', ['js:main', 'js:vendor', 'css:main', 'css:vendor']);

これで、

  • 自分で書いた js, jsx 部
    • app_root/app/assets/javascripts/dist/main.js に出力する
  • 外部ライブラリ js 部
    • app_root/app/assets/javascripts/dist/vendor.js に出力する
  • 自分で書いた css 部
    • app_root/app/assets/stylesheet/dist/main.css に出力する
  • 外部ライブラリ css 部
    • app_root/app/assets/stylesheet/dist/vendor.css に出力する

という目的が達成できるようになった。

ディレクトリ構成

これで開発準備は整った。
下記実現したいディレクトリ構成。

app/frontend
└── app/frontend
    ├── gulpfile.js
    ├── package.json
    ├── src
    │   ├── javascripts
    │   │   ├── components
    │   │   │   └── test_page
    │   │   │       ├── fuga.js
    │   │   │       ├── hoge.js
    │   │   │       └── index.js
    │   │   ├── main.js
    │   │   └── utils
    │   └── stylesheets
    │       ├── main.scss
    │       └── pages
    │           └── test_page.scss
    └── test

ここでもう一度 Rails 側の設定をする

config/initializers/assets.rb
Rails.application.config.assets.precompile += %w(dist/main.js)
Rails.application.config.assets.precompile += %w(dist/vendor.js)
Rails.application.config.assets.precompile += %w(dist/main.css)
Rails.application.config.assets.precompile += %w(dist/vendor.css)

これで、 */dist 以下に出力されたファイルを、アセットパイプラインに乗せて、Rails 側から指定できるようになる。

app/views/layouts/application.html.slim
= javascript_include_tag 'dist/main'
= javascript_include_tag 'dist/vendor'
= stylesheet_link_tag 'dist/main'
= stylesheet_link_tag 'dist/vendor'
= stylesheet_link_tag 'https://fonts.googleapis.com/iconfamily=Material+Icons'

<body>...</body> の最後で読み込む必要がある点に注意。

main.js について

app/frontend/src/javascripts/main.js
import React from 'react';
import ReactDom from 'react-dom';
import { Router, Route, Link, browserHistory } from 'react-router';
import injectTapEventPlugin from "react-tap-event-plugin";

injectTapEventPlugin();

import TestPage from './components/test_page/index';

ReactDom.render((
  <Router history={browserHistory}>
    <Route path='/' component={TestPage} />
  </Router>
),document.querySelector('#container'));
  • main.js は Webpack と gulp によって、app_root/app/assets/javascripts/dist/main.js にビルドされる。
  • react-router により、マッチした path があると、component={XXXXXX} で指定したコンポーネントを表示してくれる。
  • Rails 側で用意した #container に、React で書いた分をぼこっとマウントする感じ。

React で表示してみる

frontend/src/javascripts/components/test_page/index.js
import React from 'react';

export default class TestPage extends React.Component {
  constructor() {
    super();
    this.state = {
    };
  }

  render() {
    return (
      <div className='mdl-grid'>
        <div className='mdl-cell mdl-cell--2-offset mdl-cell--8-col'>
          <button className='mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect'>ALL IS WELL!</button>
        </div>
      </div>
    );
  }
}
  • js の予約語との兼ね合いにより、class => className, for => htmlfor と書かなければならないなど、jsx はちょっと癖がある。

表示!

さあ、ここまできたら、ブラウザで確認してみよう!
マテリアルデザインっぽいボタンがポツリと出現しているはず!
これにてモダンなフロントエンド開発の素地作り終了!
スクリーンショット 2016-06-04 0.58.01.png

コード

https://github.com/mugiwaranonoma/react-test
一応 git にあげておいた。

今後

  • gulpfile.js もっと書き込んでいかねば(gulp 触るのも初めてだった)
  • redux 導入したい
  • redux-router(?) で、SPA なのに URL がきちんと確認できるようにしたい
  • ESLint いれたい
  • Webpack と gulp が混在してるのどうにかしたい
  • node_modules 以下のファイルを、Webpack もビルドできるのなら、Webpack だけにできそうな感じはある
14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15