LoginSignup
35
37

More than 5 years have passed since last update.

Docker上でRails&Vue.jsでのSPAの開発環境構築

Last updated at Posted at 2018-12-31

目的

6月あたりから仕事でRails&Vueの開発をしているんですが参加した時点ではコーディングできる状態になっていて
自分ではプロジェクト作成や開発環境構築などを全くしなかったのでその辺の理解を深めるために
年末年始を使って自力で構築してみました

最終的なゴール

  • Docker上で、Rails&Vue(webpackで単一ファイルコンポーネント)のSPAの開発環境を構築 ←今回やる
  • swaggerを使ってAPI定義してバックエンドとフロントエンドを円滑に開発
  • リポジトリへpush時にCIで自動テストしてAWS(Elastic Beanstalk)へデプロイされるようにする

今回のゴール

  • Docker上でバックエンド(Rails)とフロントエンド(Vue.js)の開発ができる状態にする
  • ローカルでの開発だけでなくデプロイして公開できる状態にする
    • webpackでビルドしたものをRailsから配信できる状態

技術スタック

・Docker
・Rails
・Vue.js
・Webpack(Webpackerもいずれ試す)

Railsプロジェクト作成

必要なディレクトリとファイル作成

ディレクトリを作ってその中に
- Dockerfile
- docker-compose.yml
- Gemfile
を作る

rails_vue_spa/
 ├ Dockerfile
 ├ docker-compose.yml
 └ Gemfile


rails_vue_spa/Dockerfile
FROM ruby:2.5.1

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - &&\
    apt-get update -qq &&\
    apt-get install -y nodejs
ENV TZ=Asia/Tokyo

COPY Gemfile .
RUN bundle install

WORKDIR /usr/src/app

Ruby環境のイメージをビルドするためのDockerfile

rails_vue_spa/docker-compose.yml
version: '3'
volumes:
  bundle:
services:
  app:
    build: .
    ports:
      - 3000:3000
    volumes:
      - bundle:/usr/local/bundle
      - .:/usr/src/app:delegated
    stdin_open: true
    tty: true
    command: /bin/sh

そのうちDBのコンテナと繋げる&操作性がdocker-composeの方が好きなのでdocker-compose.ymlを用意

rails_vue_spa/Gemfile
source 'https://rubygems.org'

gem 'rails', '~> 5.2.2'

とりあえずrailsだけ

Docker立ち上げてRailsプロジェクト作る

Host側
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app sh
Docker側
# rails new .
       exist
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /usr/src/app/Gemfile? (enter "h" for help) [Ynaqdhm] 

yでエンター

Docker側
# rails s -b 0.0.0.0 -p 3000

http://localhost:3000 でrailsサンプルページが表示されるか確認

Docker側
# ^C
# exit

Ctrl+Cでrailsサーバ止めてDocker上のコンソール終了

Host側
$ docker-compose down

一度Docker止める

Dockerの設定修正

rails_vue_spa/Dockerfile
FROM ruby:2.5.1

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - &&\
    apt-get update -qq &&\
    apt-get install -y nodejs
ENV TZ=Asia/Tokyo

COPY Gemfile .
COPY Gemfile.lock .
RUN bundle install

WORKDIR /usr/src/app

イメージビルド時にlockファイルからgemがインストールされるようにDockerfileを修正

rails_vue_spa/docker-compose.yml
version: '3'
volumes:
  bundle:
services:
  app:
    build: .
    ports:
      - 3000:3000
    volumes:
      - bundle:/usr/local/bundle
      - .:/usr/src/app:delegated
    stdin_open: true
    tty: true
    command: /bin/sh -c "bundle install; rm /usr/src/app/tmp/pids/server.pid; rails s -b 0.0.0.0 -p 3000"

コンテナ起動時にもlockファイルからgemがインストールされ、
railsサーバが起動するようにdocker-compose.yml修正

rm /usr/src/app/tmp/pids/server.pid;
はコンテナ止める時にpidファイルが残って再度サーバ立ち上げようとした時にエラーになることがあるため

Host側
$ docker-compose build --no-cache
$ docker-compose up -d

http://localhost:3000 にアクセスしてサンプルページが表示されればok

Railsプロジェクトの中にVueの開発環境構築

frontend/配下にVueプロジェクト作成

Host側
$ docker-compose exec app sh

Dockerの中に入って

Docker側
# pwd
/usr/src/app
# mkdir frontend
# cd frontend
# npm install -g vue-cli
# vue init webpack

? Generate project in current directory? (Y/n) y
? Project name (frontend)
? Project description A Vue.js project
? Author
❯ Runtime + Compiler: recommended for most users
  Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere
? Install vue-router? (Y/n) y
? Use ESLint to lint your code? (Y/n) y
? Pick an ESLint preset
❯ Standard (https://github.com/standard/standard)
  Airbnb (https://github.com/airbnb/javascript)
  none (configure it yourself)
? Set up unit tests (Y/n) y
? Pick a test runner (Use arrow keys)
❯ Jest
  Karma and Mocha
  none (configure it yourself)
? Setup e2e tests with Nightwatch? (Y/n) y
? Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys)
❯ Yes, use NPM
  Yes, use Yarn
  No, I will handle that myself
  • Railsプロジェクト直下にfrontendディレクトリ作成
  • vue-cliをインストール
  • vueプロジェクト作成(色々選択肢出るけど基本ずっとそのままエンターでok)

Dockerの設定を修正

Dockerfile
FROM ruby:2.5.1

RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - &&\
    apt-get update -qq &&\
    apt-get install -y nodejs
ENV TZ=Asia/Tokyo

WORKDIR /usr/src/app
COPY Gemfile .
COPY Gemfile.lock .
RUN bundle install

RUN mkdir frontend
COPY frontend/package.json frontend/.
COPY frontend/package-lock.json frontend/.
RUN cd frontend && npm install
  • イメージビルド時にfrontend直下にnode_modulesをインストールするように修正

docker-compose.yml
version: '3'
volumes:
  bundle:
services:
  app:
    build: .
    ports:
      - 3000:3000
      - 8080:8080
    volumes:
      - bundle:/usr/local/bundle
      - .:/usr/src/app:delegated
      - /usr/src/app/frontend/node_modules
    stdin_open: true
    tty: true
    command: /bin/sh -c "bundle install; rm /usr/src/app/tmp/pids/server.pid; rails s -b 0.0.0.0 -p 3000"
  • webpack-dev-server用に8080ポート開ける
  • ボリュームマウント時にnode_modulesが消えないようにボリュームトリックを使う(※参考)

Host側
$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up -d

Dockerイメージビルドからし直して立ち上げる

webpack-dev-serverの設定修正

frontend/config/index.js
host: 'localhost', // can be overwritten by process.env.HOST

frontend/config/index.js
host: '0.0.0.0', // can be overwritten by process.env.HOST

に修正

webpack-dev-server起動して確認

Host側
$ docker-compose exec app sh

でDockerに入って

Docker側
# cd frontend
# npm run dev

webpack-dev-server起動して
http://localhost:8080/#/ にアクセスにサンプルページが表示されればok
Ctrl+Cで終了

Vueプロジェクトをビルドしてみる

Docker側
# pwd
/usr/src/app/frontend
# npm run build

でフロントエンドをビルドするとfrontend/distの直下に
ビルドしたcssやjsとそれらを読み込んでいるindex.htmlが作成される

rails_vue_spa/
            └ frontend/
                     └ dist/
                          ├ index.html
                          └ static/
                                 ├ css/
                                 │   ├ app.30790115300ab27614ce176899523b62.css
                                 │   └ app.30790115300ab27614ce176899523b62.css.map
                                 └ js/
                                    ├ app.f79767c5ed5e2af21cfb.js
                                    ├ app.f79767c5ed5e2af21cfb.js.map
                                    ├ manifest.2ae2e69a05c33dfc65f8.js
                                    ├ manifest.2ae2e69a05c33dfc65f8.js.map
                                    ├ vendor.42fc6c515ccdfe89bd76.js
                                    └ vendor.42fc6c515ccdfe89bd76.js.map

そのままだとビルドしてできたものにハッシュがついてて扱いづらいのでハッシュがつかないようにする

Vueプロジェクトのビルドの設定変更

frontend/build/webpack.prod.conf.js
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
.
.
.
filename: utils.assetsPath('css/[name].[contenthash].css'),

frontend/build/webpack.prod.conf.js
filename: utils.assetsPath('js/[name].js'),
chunkFilename: utils.assetsPath('js/[id].js')
.
.
.
filename: utils.assetsPath('css/[name].css'),

へ修正して

Docker側
# npm run build

ビルドしなおすと

rails_vue_spa/
            └ frontend/
                     └ dist/
                          ├ index.html
                          └ static/
                                 ├ css/
                                 │   ├ app.css
                                 │   └ app.css.map
                                 └ js/
                                    ├ app.js
                                    ├ app.js.map
                                    ├ manifest.js
                                    ├ manifest.js.map
                                    ├ vendor.js
                                    └ vendor.js.map

となる

ビルドしたフロントエンドのファイルをRailsサーバから配信されるようにする

Railsのルーティングとコントローラ準備

config/routes.rb
root to: 'index#index'
app/controllers/index_controller.rb
class IndexController < ApplicationController
  def index; end
end

Railsのviews作成

frontend/dist/index.html(実際は改行ないけど見やすいように整形した)
<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <meta name=viewport content="width=device-width,initial-scale=1">
        <title>frontend</title>
        <link href=/static/css/app.css rel=stylesheet>
    </head>
    <body>
        <div id=app></div>
        <script type=text/javascript src=/static/js/manifest.js></script>
        <script type=text/javascript src=/static/js/vendor.js></script>
        <script type=text/javascript src=/static/js/app.js></script>
    </body>
</html>

を参考にcssとjs読み込み部分をassets以下を読み込むように修正して以下のerbを作る

app/views/index/index.html.erb
<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <meta name=viewport content="width=device-width,initial-scale=1">
        <title>frontend</title>
        <%= stylesheet_link_tag 'application', media: 'all' %>
    </head>
    <body>
        <div id=app></div>
        <%= javascript_include_tag 'application' %>
    </body>
</html>

このままだとまだ読み込まれないので
frontend/dist/static/css/*app/assets/stylesheets/frontend/配下へ、
frontend/dist/static/js/*app/assets/javascripts/frontend/配下へ移動する

app/assets/javascripts/application.js
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .

app/assets/javascripts/application.js
//= require frontend/manifest
//= require frontend/vendor
//= require_tree .

へ変更
//= require_tree .だけで置いてあるjs全部読み込むが
manifestvendorを先に読み込まないとエラーになるので上記のようにする必要がある

これでvueでビルドしたものがrailsから配信されるようになるので
http://localhost:3000 にアクセスするとvueのサンプルページが表示されるようになる

画像について

ロゴのpngとかはbase64にエンコードされた状態になるためビルドした時に画像は出力されないが
ぐるぐるするアニメーションのgifはエンコードされずdist/static/img/配下に出力される(なんでだろう?)

試しにfrontend/src/asstes/loader.gifを置いて

frontend/src/App.vue
<img src="./assets/logo.png">

frontend/src/App.vue
<img src="./assets/loader.gif">

にしてビルドするとdist/static/img/loader.78f8cb8.gifも生成されるようになる

が、
画像のパスstatic/img/loader.78f8cb8.gifapp.jsの中に書かれてしまうため
frontend/dist/static/img/配下をapp/assets/images/ではなくpublic/static/img/配下に置く

フロントエンドのビルドが楽になるように

上記のcss,js,imgの移動を含めたビルドの流れをスクリプトにまとめる

scripts/build-frontend.sh
#!/bin/bash

cd /usr/src/app/frontend
npm install
npm run build

cp -a /usr/src/app/frontend/dist/static/js/. /usr/src/app/app/assets/javascripts/frontend
cp -a /usr/src/app/frontend/dist/static/css/. /usr/src/app/app/assets/stylesheets/frontend

if [ -d /usr/src/app/frontend/dist/static/img/ ] ;then
  # ディレクトリないとcpでエラーになるからなければ作る
  if [ ! -d /usr/src/app/public/static/img ] ;then
    mkdir -p /usr/src/app/public/static/img
  fi
  cp -a /usr/src/app/frontend/dist/static/img/. /usr/src/app/public/static/img/
fi



ここまで準備すると、

Host側
docker-compose exec app scripts/build-frontend.sh

とか

Host側
$ docker-compose exec app sh
Docker側
# scripts/build-frontend.sh

ってするだけでフロントエンドがビルドされて最新状態のものが
http://localhost:3000
で見れるようになる

このスクリプトは後々のCIでのビルド&デプロイでも活用する

ってことで今回のゴール

  • Docker上でバックエンド(Rails)とフロントエンド(Vue.js)の開発ができる状態にする
  • ローカルでの開発だけでなくデプロイして公開できる状態にする
    • → webpackでビルドしたものをRailsから配信する

までたどり着きました

次回は
swaggerを使ってAPI定義してバックエンドとフロントエンドを円滑に開発

次次回
リポジトリへのpush時にCIで自動テストしてAWS(Elastic Beanstalk)へデプロイされるようにする

をやってみたいと思います

35
37
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
35
37