はじめに
フロントエンド用アプリとしてReact(Create React App)、バックエンド用アプリとしてRails(API mode)を使用し、Herokuで動かすまでの手順をまとめてみました。
Herokuは無料プランでフロントエンド、バックエンドの2つのアプリを立ち上げます。
まとめた内容としては以下の流れとなります。
- ローカルで動くものを作る
- Herokuにデプロイする
- Herokuで動かす
環境
バージョン | |
---|---|
node | v11.3.0 |
npm | 6.4.1 |
React | 16.4.2 |
Rails | 5.2.1 |
Ruby | 2.5.1 |
事前準備
- Herokuのアカウント登録
- ローカルで
create-react-app
インストール(本記事に沿ってreact
プロジェクトを作成する場合は必要です。)
1. ローカルで動くものを作る
まずはローカルで動くものを作ってみます。
以下のフォルダ構成を作成します。
react-rails-heroku
└ projects
├ react-frontend
└ rails-backend
react-rails-heroku
にはローカルで起動する際、フロントエンドとバックエンドをまとめて起動できるようなコマンドを仕込みますが、後ほど説明します。
$ mkdir react-rails-heroku && cd react-rails-heroku
$ mkdir projects && cd projects
$ create-react-app react-frontend
$ bundle init
# 生成されたGemfileにある `gem "rails"` のコメントアウトを外す
$ bundle install --path vendor/bundle
$ bundle exec rails new rails-backend --database=postgresql --skip-bundle --api
これで一旦プロジェクトの雛形がそれぞれ出来ました。
1.1. バックエンドの実装
フロントエンドとのやり取りを行う為のエンドポイントをバックエンド側に用意します。
# フロントエンドからのアクセスを許可する為に `gem 'rack-cors'` のコメントアウトを外す
$ bundle install --path vendor/bundle
$ bundle exec rails db:create
ルートを追加
Rails.application.routes.draw do
get "hello_world", to: 'application#hello_world'
end
hello_world
メソッド定義
class ApplicationController < ActionController::API
def hello_world
render json: { text: "Hello World" }
end
end
フロントからのアクセスを許可
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins /localhost\:\d+/
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
1.2. フロントエンドの実装
パッケージインストールしていない場合はインストールして下さい。
$ npm i
バックエンドのURLを指定します。
process.env.REACT_APP_SERVER_URL
で取得できる環境変数になります。
REACT_APP_SERVER_URL=http://localhost:5000
FetchAPIを使ってバックエンドから値を取得し、表示します。
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
text: null
};
}
componentDidMount() {
const fetchInit = {
method: "GET",
headers: { "content-type": "application/json" }
};
fetch(new URL("hello_world", process.env.REACT_APP_SERVER_URL), fetchInit)
.then(response => response.json())
.then(response => this.setState(response));
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Response: {this.state.text}</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;
1.3. 実行
フロントエンドは 3000
番ポート、バックエンドは 5000
番ポートで起動します。
$ npm start
$ bundle exec rails s -p 5000
http://localhost:3000/ にアクセスすると確認できます。
1.4. フロントエンドとバックエンドを1コマンドで動かすコマンドを仕込む
1.4.1. npm start
で実行できるようにします。
$ npm init
scripts
に追加していきます。
"scripts": {
"start": "bundle exec foreman start"
}
foreman
で実行する為の設定をします。
$ bundle init
生成された Gemfile
に foreman
を追加し、インストールします。
また、バックエンドの起動に必要な gem
がここにも必要になります。
-# gem "rails"
+gem "rails"
+gem "foreman"
+gem 'bootsnap', require: false
+gem 'rack-cors'
+gem 'listen'
+gem 'pg'
$ bundle install --path vendor/bundle
backend: exec /usr/bin/env sh -c 'cd projects/rails-backend && npm start'
frontend: exec /usr/bin/env PORT=3000 sh -c 'cd projects/react-frontend && npm start'
1.4.2. バックエンドも npm start
で実行できるようにします。
$ npm init
scripts
に追加していきます。
"scripts": {
"start": "bundle exec foreman start"
}
foreman
で実行する為の設定をします。
Gemfile
に foreman
を入れ、インストールします。
+gem "foreman"
$ bundle install --path vendor/bundle
ここで注意ですが、 Procfile
に記述した起動コマンドでHerokuでも起動されてしまいます。
デフォルトの bin/rails server -p $PORT -e $RAILS_ENV
で起動させるようにし、この設定は開発環境のみ動くようにします。
web: exec /usr/bin/env PORT=5000 sh -c 'bundle exec rails s'
foreman
の起動で参照するファイルを Procfile.dev
にします。
.foreman
ファイルはローカルでのみ参照されるようにするので、コミットする際は外すようにして下さい。(2.1
に除外するコマンドを記載しています。)
procfile: Procfile.dev
実行します。
$ npm start
1.3
と同様にhttp://localhost:3000/ にアクセスすると確認できます。
2. Herokuにデプロイする
一旦Herokuにデプロイしてみたいと思います。
CLIでHerokuにログインしておいてください。
$ heroku login
2.1. バックエンドをデプロイ
$ git init
$ git config --local user.name [アカウント名]
$ git config --local user.email [メールアドレス]
$ echo "/vendor/bundle" >> .gitignore
$ echo ".foreman" >> .gitignore
$ git add --all
$ git commit -m "initial commit"
# Herokuアプリを作成する(アプリ名の前にアカウント名を付ける等して、ユニークな名前にして下さい。)
$ heroku create xxxxx-rails-backend
$ git push heroku master
バックエンドのアプリケーションが作成されました。
https://dashboard.heroku.com/apps
Open app ボタンを押してアクセスすると真っ白の画面が表示されます。
URLの後ろに hello_world
を付けると Hello World
が返ってきます。
2.2. フロントエンドをデプロイ
$ git init
$ git config --local user.name [アカウント名]
$ git config --local user.email [メールアドレス]
$ git add --all
$ git commit -m "initial commit"
# バックエンド同様アプリ名はユニークな名前にして下さい。
# Create React Appは `buildpack` を使ってHerokuにアプリを作成します。
$ heroku create xxxxx-react-frontend --buildpack mars/create-react-app
$ git push heroku master
mars/create-react-app
の buildpack
を使ってデプロイするので、
デプロイ後、 heroku
上で build
を自動でしてくれます。
ローカルで build
してから丸ごとデプロイする必要はありません。
この時以下のようなエラーが出た場合、
error Your lockfile needs to be updated, but yarn was run with `--frozen-lockfile`.
yarn install
してコミットし、再度 push
して下さい
$ yarn install
$ git add yarn.lock
$ git commit -m "add yarn.lock"
$ git push heroku master
フロントエンドもアプリケーションが作成されました。
https://dashboard.heroku.com/apps
フロントエンドにアクセスしてみますが、
まだ、レスポンスが受け取れません。
フロントエンドがリクエストを投げている先が http://localhost:5000/hello_world
となってしまっていることが原因です。
では、開発環境と本番環境でエンドポイントを切り替えるように対応します。
2.3. 本番環境のフロントエンドから本番環境のバックエンドを見る
2.3.1. フロントエンド
1.2
で紹介したフロントエンドの対応で指定したエンドポイントは開発環境用でした。
これを本番環境の production
では heroku
のバックエンドを見るようにしたい。
本番環境用のバックエンドのURLを指定します。
2.1
で紹介した際、アクセスしたURLを設定してください。
これで production
で動かす場合、.env.production
の REACT_APP_SERVER_URL
の環境変数が参照されるようになります。
※厳密には build
した際、この値が反映される。
REACT_APP_SERVER_URL=https://xxxxx-rails-backend.herokuapp.com/
2.3.2. バックエンド
1.1
で紹介した、フロントからのアクセスを許可したオリジンは開発環境用でした。
これを本番環境の production
では heroku
のフロントエンドも許可したい。
2.2
で紹介した際、アクセスしたURLを許可してください。
- origins /localhost\:\d+/
+ origins /localhost\:\d+/, /xxxxx-react-frontend\.herokuapp\.com/
2.4. 修正をデプロイ
2.4.1. バックエンド
$ git add config/initializers/cors.rb
$ git commit -m "update cors origins"
$ git push heroku master
2.4.2 フロントエンド
$ git add .env.production
$ git commit -m "add .env.production"
$ git push heroku master
3. Herokuで動かす
2.2
でアクセスしたURLに再度アクセスします。
無事、 Hello World
を取得出来ました。
おまけ
ローカルでは気軽に db:migrate:reset
を実行していましたが、 heroku
でも実行したい場面がありました。
HerokuでバックエンドのDBを reset
する方法
あらかじめ heroku login
でログインしておいて下さい。
heroku pg:reset DATABASE --app xxxxx-rails-backend
# 確認メッセージが表示されるので、再度プロジェクト名(ここでは `xxxxx-rails-backend` )を入力
heroku rake db:migrate # マイグレーション実行
heroku rake db:seed # seedを流したい場合
最後に
今回紹介した、フロントエンド、バックエンド、それらをまとめて動かす開発パックをgithubにあげているので、参考にして頂ければと思います。
個人的に react
プロジェクトを heroku
にデプロイする際、 buildpack
を使うことや、 フロントエンドとバックエンドをまとめて起動するコマンドを仕込む際、バックエンド側で起動に使用している gem
が開発パック側にも必要となるところで詰まったり、調べることが多かったです。