突然ですが、環境構築って毎朝髭を剃るのと同じぐらい面倒で苦手です。
この記事をご覧になっているということは、少なからずあなたも環境構築に苦手意識があるのではないでしょうか。
社内のメンバーからも「環境構築はコンビニでたむろするヤンキーぐらい苦手」という声を良く耳にします。
私は思います、この環境構築という最初のハードルが、クリエイティブな行動を阻害していると!
環境構築の手間さえ省ければ、きっとこの世の中にはもっと多くのサービスが創出されると確信しています!
そこで今回は、"RailsをAPIサーバーとして利用"し、"Reactで描画を行う"サービスをつくりまくるための環境構築マニュアルを公開します!
以下すべてに当てはまる人が本記事の対象読者です
- なんかオシャレっぽいからMac使ってます!
- プログラミングスクール卒業したから個人アプリつくりたいぜ!
- React.jsっていうJavascriptのモダンなフレームワークを身につけて周りと差を付けたいぜ!
- react-railsとかのGemを使わない方法でRailsとReact間のやりとりを疎結合にしたい!
- Docker?なにそれ美味しいの?(本記事ではDockerの解説はしません)
0. 事前インストール
名前 | 説明 |
---|---|
Ruby | いわずもがな |
Rails | いわずもがな |
MySQL | いわずもがな |
brew | パッケージ管理 (主にサーバー側) |
yarn | パッケージ管理 (主にフロント側) |
1. Railsアプリの作成
rails new アプリ名 -–skip-turbolinks --webpack=react --database=mysql --api
人生に何回この『rails new』コマンドを打ったかでRailsエンジニアとしての価値が決まると、まことしやかに噂される。
ちなみにオプションは必要であれば書き換えてOKです
2. Webpackerのインストール
Webpackerとは、Rails標準装備のモジュールバンドラーで、Webpackのラッパーです。
バンドラーというのは束ねる人のことです。
HTML、CSS、JSなど色々な形式のファイルを束ねてくれるやつです。
ちなみにラッパーは韻を踏む人のことではありません。
サランラップとかのラッパーです。『包む』という意味です。
Webpackerは内部でWebpackを呼び出しているので、WebpackerはWebpackのラッパーです。
ちなみにフロントエンドに興味があるなら、Webpackの知識はある程度あった方が良いです。
"Babel"とか"ES6"とかそういうワードとセットで覚えるとGOODです!
rails webpacker:install
rails webpacker:install:react
3. MySQLのインストール
今回はDBにMySQLを使ってみます。
私は普段の業務ではPostgreSQLを使用しているのですが、プログラミングスクール卒の方はMySQLに慣れていると思うので。
新規プロダクトのDB選定はその現場で使い慣れているものを使用しているところが多いような気がしています。
違ったらすみません。
ちなみに余談of余談ですが、個人的にはNoSQLのMongoDBとかに興味があったりします。
理由は、「なんとなく知ってたらイケてるエンジニアっぽいから」です。
今回はbrewというパッケージマネージャー経由でMySQLをインストールします
brew install mysql
4. MySQLユーザーの作成
MySQLがインストールできたら、今回のアプリで使用するためのユーザーを作成します。
各コマンドについては、特に詳しく説明する必要もなさそうなので割愛します。
・ルートユーザーにログイン
mysql -u root -p
・ユーザー作成
好きなユーザー名とパスワードを設定
create user 'ユーザー名'@'localhost' identified by 'パスワード';
・作成したユーザーの確認
作成したユーザーが表示されていれば成功
select User,Host from mysql.user;
・権限付与
grant all on *.* to '[ユーザー名]'@'localhost';
・config/database.ymlの設定変更
ユーザーの作成が一通り終わったら、作成したユーザーとRailsを紐付けます。
RailsのDB設定はdatabase.ymlに記述するのがルールです。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV['DATABASE_USERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
host: <%= ENV['DATABASE_HOST'] %>
development:
<<: *default
database: app_name_development
test:
<<: *default
database: app_name_test
production:
<<: *default
database: app_name_production
username: <%= ENV['APP_NAME_DATABASE_USERNAME'] %>
password: <%= ENV['APP_NAME_DATABASE_PASSWORD'] %>
『app_name_○○』はRails newした時のアプリ名に置き換えてください
usernameやpasswordはGitHubで公開しちゃうと見えてしまうので
gem『dotenv』等を使って隠蔽することをおすすめします。
ちなみにdotenvで作成した『.env』ファイルをGit管理から外しておかないと意味が無いので、作ったら『.gitignore』に『.env』を忘れずに追加しましょう!
「何を言っているのかわからない...」という人は「dotenv 環境変数」とかで調べてみよう!
「わからないことを調べる」のは、エンジニアの基本です!
この『調べる』をいかに深堀りしてできるかが、成長の近道のような気がしています。
5. データベースの作成
rake db:create
6. Railsサーバーの起動
rails s
7. Webで確認
「Yay! You’re on Rails!」が表示されていれば成功
環境構築はもう少し続きます。
もう6合目ぐらいには来てます。もう少し。
8. Webpackerの設定(任意)
・splitchunks
チャンクを自動分割してくれるWebpackのプラグインです。
ファイルサイズの節約ができたりするけど、別になくても良いです。
config/webpack/environment.jsの変更
const { environment } = require('@rails/webpacker');
environment.splitChunks();
module.exports = environment;
app/views/top/show.html.erb
javascript/packs/の中にある「index」という名前の付いたファイルを参照するの意。
<%# splitchunksを使う場合 %>
<%= javascript_packs_with_chunks_tag 'index' %>
<%# splitchunksを使わない場合 %>
<%= javascript_pack_tag 'index' %>
9. ルーティング設定
config/routes.rb
Rails.application.routes.draw do
# ルートページ設定
root "top#show"
end
10. エントリーポイントの作成
・ルートページのコンロトーラー作成
app/controllers/top_controller.rb
class TopController < ApplicationController
def show
end
end
・Reactで描画するためのid属性を追加
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>アプリケーションタイトル</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= javascript_pack_tag 'application' %>
</head>
<body>
<div id="root"> ←これです
<%= yield %>
</div>
</body>
</html>
・Reactのエントリーポイント作成
app/javascript/packs/index.jsx
app/views/top/show.html.erbから参照されるファイル
このファイルがReactの入り口です。
非同期、ルーティング、状態管理等、React用のパッケージをimportして設定しています。
各パッケージのインストールは後で行います。
// このファイルがRailsのViewから呼ばれる一番最初のファイルです(EntryPoint)
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk'
import {
Router,
Route,
Switch,
IndexRoute,
useLocation
} from 'react-router-dom';
import { createBrowserHistory } from 'history';
import { composeWithDevTools } from 'redux-devtools-extension';
// reducer
import rootReducer from '~/src/reducers/';
// Component
import Top from '~/src/components/tops/';
const middleWares = [thunk];
// 開発環境の場合、開発ツールを使用するための設定
const enhancer = process.env.NODE_ENV === 'development' ?
composeWithDevTools(applyMiddleware(...middleWares)) : applyMiddleware(...middleWares);
const store = createStore(rootReducer, enhancer);
const customHistory = createBrowserHistory();
render(
<Provider store={store}>
<Router history={customHistory}>
<Route render={({ location }) => (
<div>
<Switch location={location}>
<Route exact path='/' component={Top} />
</Switch>
</div>
)}/>
</Router>
</Provider>,
document.getElementById('root')
)
・Reactコンポーネント作成
app/javascript/src/components/tops/index.jsx
Reactコンポーネントの記述にはjsxという拡張子のファイルを使用します。
JSファイルの中にHTMLを記述します。
最初はJSの中にHTMLタグを書くことに気持ち悪さを感じますが、その内慣れます。
import React from 'react';
const Top = () => (
<h1>
<center>アプリケーションのタイトル</center>
</h1>
)
export default Top;
・Reactリデューサーをまとめる処理の作成
app/javascript/src/reducers/index.js
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import top from '~/src/modules/tops/';
export default combineReducers({
form: formReducer,
top,
});
ここでまとめたものがReduxのstoreに格納されます。
Reduxとは状態を一元管理してくれるパッケージのことです。
storeとは状態を格納する箱のことです。Reduxの一番重要な機能です。
Reactの開発において、Reduxの利用は必須ではありませんが、React単体だとプロダクトの規模が大きくなるにつれて状態管理が辛くなるので、初めから入れておいた方がいいです。
LPとか規模の小さいプロダクトならなくても良いです。
・Reactモジュール作成
ディレクトリ構成はducksパターンを採用。
ducksパターンというのは『action type』、『action creator』、『reducer』を1つのファイルにまとめて記述する考え方のことです。設計の概念です。何かをインストールするとかではないです。
app/javascript/src/modules/tops/index.js
// action-type
const TOP_INITIAL = 'TOP_INITIAL';
// reducer
const initialState = {
top: null,
}
export default function top(state = initialState, action) {
switch (action.type) {
case TOP_INITIAL:
return {
...state,
}
default:
return state
}
}
// action-creator
export const topInitial = () => ({
type: TOP_INITIAL,
});
通常は『action type』、『action creator』、『reducer』それぞれでファイルを作成するところ、ducksパターンを取り入れると1つのファイルにまとまるので、単純にファイル数が少なくて済みます。
中規模プロダクトでも全然耐えられる設計概念なのでおすすめです。
「action typeって何?」と思った人はRedux公式で調べてみましょう!
11. 必要なパッケージインストール
yarnというパッケージマネージャーを使用してインストールします。
似た様なパッケージマネージャーで『npm』がありますが、『yarn』は『npm』の上位互換です。
yarnでインストールしたパッケージは、ルートディレクトリ直下の『package.json』というファイルに自動で追加されます。
『yarn add パッケージ名』でパッケージの追加
『yarn remove パッケージ名』でパッケージの削除です。
yarn add redux react-redux react-router-dom redux-devtools-extension redux-form redux-thunk axios @babel/preset-react babel-plugin-root-import
もし興味があれば『@reduxjs/toolkit』、『@material-ui/core』もおすすめです
12. パス指定設定ファイルの作成(任意)
独学でReactを少しでも開発したことがある方なら一度はこう思ったはず
「React相対パス地獄なりがち。」
Reactはimport時の相対パス指定地獄に陥りがちです。
そうならないよう『babel-plugin-root-import』を入れることをおすすめします。
実は上記11.の『yarn add』の中にこっそり入っているので、コマンドをコピペして実行した方は私の策略によりすでに入っています。
『.babelrc』というファイルを作ってそこに設定を記述します。
『.babelrc』ファイルを作る場所はルートディレクトリ直下。
.babelrc
{
"plugins": [
[
"babel-plugin-root-import",
{
"paths": [
{
"rootPathSuffix": "./app/javascript/src",
"rootPathPrefix": "~/src/"
},
]
}
]
]
}
上記設定は『./app/javascript/src』というパス指定を『~/src/』という文字列でも指定できるように設定しているだけです。
これで、Reactコンポーネントでのimport時に『~/src/○○』が使えるようになるので、相対パス地獄から抜け出せます。
ちなみに『"~/src/"』の部分は『"~/"』でも『"@/src/"』でも好きに設定できます。
13. webpack-dev-serverの起動
./bin/webpack-dev-server
自動コンパイルしてくれる開発用サーバーです。
常にコードの監視もしているので、Reactのコードを書き換えると自動でブラウザ上の描画も書き換えてくれます。
(ちなみにRailsのModelやController、Viewなどは監視対象外なので変更しても自動描画はされません。素直に『command + R』でブラウザ更新しましょう。)
お疲れ様でした
これでRails & Reactの開発環境が整った...はずです。
http://localhost:3000/に「アプリケーションのタイトル」が表示されていれば無事成功です!
それでは楽しい3R(Ruby on Rails on React)開発を!
トラブルシューティング
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/' succeeds before bundling.
上記エラーメッセージが表示されてbundle installが失敗する場合↓
sudo xcodebuild -license accept
で解決できる場合もある