【保存版】Docker上に構築したRails6でVue.jsを表示する方法(エラー対処法&Vuetifyの使い方)

docker-rails-vue-js-prograshi(プロぐらし)-kv Rails
記事内に広告が含まれていることがあります。
[PR]

Docker上にRails6を構築し、Rails経由でVue.jsファイルを読み込んでブラウザ上に表示する方法についてです。

フロントエンドはVue.jsで作成し、DBなどのバックエンドをRailsで構築するアプリケーションを想定しています。

特に、Docker上でRails6を使ってVue.js使う設定にすると、Webpackerでファイルがコンパイルできないといった不具合に見舞われることがあります。

それらの対処法も踏まえて解説しています。最終的に、次のようなページを表示します。

Docker上に構築したRails6でVue.jsを表示するまでの流れ

Docker上に構築したRails6でVue.jsを表示するまでの流れは次のようになります。

  1. Dcoker上にRailsを構築する
  2. DBの設定をする
  3. ビューファイルを作成する
  4. WebpackerでVueをインストールする
  5. vue-loaderのバージョンを下げる(コンパイルエラー対応)
  6. Babelの設定を変更する(大量の警告を非表示にする)
  7. コンパイルするファイル名の変更(hello_vue.js → main.js)
  8. ビューファイルを編集してVue.jsの内容を表示する
  9. Vueテンプレートを作成して読み込む
  10. Vuetifyを使う

実際には、1~7までで、Vue.jsの内容を表示することができます。より実用的な使い方のために、(8)vueテンプレートの切出しと読み込み、(9)Vuetifyの活用方法を追加しています。

Point
  • WebpackerでVueを追加する。
  • vue-loaderのバージョン。(コンパイルエラーの修正)
  • Babelの設定。(警告の非表示)
  • Vuetifyのインストールと使い方。(UIコンポーネントの活用)


(追記)Webpackerのコンパイルが遅い場合は以下をご参考ください。

【簡単】Dcoker上のRailsでWebpackerのコンパイルが遅すぎるを解決する方法


Dcoker上にRailsとDBサーバーを構築する

Dcoker上にRailsを構築します。次の5つのファイルが必要になります。

  1. Dockerfile
  2. Gemfile
  3. Gemfile.lock
  4. entrypoint.sh
  5. docker-compsoe.yml

最初にプロジェクトのルートディレクトリを作成し、移動しておきます。

$ mkdir rails-vue
$ cd rails-ve

Dockerfileの作成

Rubyのバージョンに指定がない場合は、Ruby公式サイトで安定版を調べた後、docker hubのRubyイメージで該当するものを確認します。

Rubyのイメージのバージョン

Rubyのイメージのバージョンで3系を指定するとwebpackerのインストールでエラーが発生します。2系の安定版を指定することを推奨します。

Rails6からはJavaScriptや画像などのアセットを管理するためにWebpackerを使います。Webpackerをインストールするために、Node.jsとYarnをインストールしておく必要があります

DBはPostgreSQLを指定しています。

(参考)Rails公式 Railsをはじめよう

$ vim Dockerfile
FROM ruby:2.7.4

#apt-keyとdevconfのエラー対策
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV DEBCONF_NOWARNINGS=yes

# node.jsと必要なライブラリのインストトール
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client \
            curl apt-transport-https wget

# yarnのインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
      echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
      apt-get update && apt-get install -y yarn

#aptキャッシュの削除
RUN rm -rf /var/lib/apt/lists/*

# ディレクトリ・ファイルの作成
RUN mkdir /rails-vue
WORKDIR /rails-vue
COPY Gemfile /rails-vue/Gemfile
COPY Gemfile.lock /rails-vue/Gemfile.lock

# gem(Rails6)のインストール
RUN bundle install
COPY . /rails-vue

RUN yarn install --check-files
RUN bundle exec rails webpacker:compile

# コンテナ起動時に毎回実行するスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# rails起動コマンド
CMD ["rails", "server", "-b", "0.0.0.0"]

ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn

apt-keyのエラー対策として、環境変数でAPT_KEY_DONT_WARN_ON_DANGEROUS_USAGEを設定しています。値は「DontWarn」を指定していますが、1でも何でもいいです。

対象のエラー内容

Warning: apt-key output should not be parsed (stdout is not a terminal)

ENV DEBCONF_NOWARNINGS=yes

apt-utilsがないために表示されるエラー対策として、環境変数でENV DEBIAN_FRONTENDを設定しています。

apt-utilsはなくても問題なく動くため、軽量化のためにもインストールしません。

対象のエラー内容

debconf: delaying package configuration, since apt-utils is not installed

rm -rf /var/lib/apt/lists/*

aptが自動生成したキャッシュが溜まっていくと容量を圧迫します。軽量化のため削除しています。


Gemfileの作成

GemfileとはRailsのライブラリであるgemを管理するためのファイルです。bundle installを実行すると、Gemfileを参照して、まだインストールされていないgemがあればインストールします。

インストールしたいgemがあればGemfileに追記してから、bundle installを実行します。

$ vim Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

~>6 というのは、バージョン6系の最新版という意味です。


Gemfile.lockの作成

Gemfile.lockはインストール済みのgemとそのバージョンの一覧です。内容は自動で生成されるので、自分で中身を編集する必要はありません。

ここではファイルを生成するのみです。

touch Gemfile.lock

GemfileとGemfile.lockの違い

ファイル内容直接編集
Gemfileインストール対象のgem
Gemfile.lockインストール済みのgem×


entrypoint.sh

コンテナ起動時に実行するシェルスクリプトを作成します。

vim entrypoint.sh
#!/bin/bash
set -e

# 初期に作成されるPIDを削除する
rm -f /rails-vue/tmp/pids/server.pid

# DockerfileのCMDにセットしたすべての引数を実行する
exec "$@"

#!/bin/bash

#! の後にこのファイルに書かれているスクリプトを指定します。ここでは bash で読み込むという指定です。bashのシェルスクリプトを作成するときは冒頭に必ず記載します。

set -e

エラー発生時にシェルスクリプトを終了するための設定を有効化しています。
(参考)シェルスクリプトの罠を避ける三つの tips

rm -f /PJ名/tmp/pids/server.pid

server.pidファイルにはプロジェクトのPIDが入ります。これがあると、railsを起動したときに、A server is already running. というエラーが発生するので、削除します。

exec “$@”

execは処理を実行するコマンドです。”$@” はすべての引数を展開する記述です。DcokerfileのCMDで記述した["rails", "server", "-b", "0.0.0.0"]の4つの引数が入ります。

つまり、 exec rails server -b 0.0.0.0 となります。

exec rails server -b 0.0.0.0

rails serverはrailsの起動コマンドです。rails sと同じです。bオプションはrailsをどのIPアドレスに紐づけるかを指定します。0.0.0.0はすべてのIPアドレスを指します。

つまり、コンテナ内のすべてのIPアドレスに紐付ける形でrailsを起動しています。


docker-compose.ymlの作成

Dcoker上でRailsコンテナとDBコンテナを紐付けて起動するための処理をdocker-compose.ymlに記述します。

$ vim docker-compose.yml 
version: '3'
services:
  db:
    image: postgres
    container_name: rails-vue-db
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_HOST_AUTH_METHOD: 'trust'

  web:
    build: .
    container_name: rails-vue-web
    command: bash -c "rm -f tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/rails-vue
    ports:
      - "3000:3000"
    depends_on:
      - db


プロジェクトのビルド

railsアプリケーションの作成

docker-sompose runコマンドでwebコンテナを起動し、起動したコンテナの中で、rails newコマンドを実行します。

$ docker-compose run web rails new . --force --no-deps --database=postgresql

サービス名 web 以降はすべて引数として渡すデータです。rails newでアプリケーション名は現在のディレクトリ 「.」を指定し、以下のオプションをつけて実行しています。

--force: 既存ファイルがある場合は強制的に上書き
--no-deps: リンクしたサービスを起動しない(ここではdbサービス)
--database=postgresql: DBはPostgreSQLを指定

tips

コンテナ内でrailsを初回起動する時に--skip-bundlebundle installスキップし後ほど実行)してしまうと、次のビルド時にwebpackerがないというエラーが発生してスタックするので、外しておくことを推奨します。

最初に作成した5つのファイルに加えてファイルが生成されます。

$ ls -a
.			.git			Dockerfile		Rakefile		config			entrypoint.sh		package.json		test
..			.gitattributes		Gemfile			app			config.ru		lib			postcss.config.js	tmp
.DS_Store		.gitignore		Gemfile.lock		babel.config.js		db			log			public			vendor
.browserslistrc		.ruby-version		README.md		bin			docker-compose.yml	node_modules		storage			yarn.lock

アプリケーションのビルド

rails newによりgemfileが書き変わるので、書き換わったファイルでイメージをビルドしなおします。

ビルドを実行すると、Dockerfileがもう一度実行されるので、bundle installも実行されます。

$ docker-compose build

Successfully built 33a02920b593、Successfully tagged rails-vue_web:latestのように表示されればビルド成功です。


追記するのは、3行のみです。

DBの設定

データベース設定ファイルの編集

DBに接続するための情報をconfig/database.ymlに追記します。

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  #####追記#####
  host: db
  username: postgres
  passowrd:
  #############

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

Dockerコンテナ内に作成したRailsアプリケーションの中でDBを生成します。

$ docker-compose run web rails db:create


「アプリケーション名_development」と「アプリケーション名_test」の2つのBが生成されます。

$ docker-compose run web rails db:create
Starting rails-vue_db_1 ... done
Creating rails-vue_web_run ... done
Created database 'rails_vue_development'
Created database 'rails_vue_test'


コンテナを起動

Dockerコンテナ内のrailsの下準備が終わったので、コンテナを起動します。

$ docker-compose up


きちんと起動できるか確かめるために、-dオプションは付けない方が推奨です。

-dをつけた場合はバックグラウンドでの起動となるため、エラーやアクセスログが表示されません。

http://0.0.0.0:3000 にアクセスして、Railsのページが表示されれば成功です。

ビューファイルを作成する

http://0.0.0.0:3000/home/index で別のページが表示されるようにします。

homeコントローラーのindexアクションを指定して、ビューファイルを作成します。

rails g <コントローラ名> <アクション名>
tips

ここでのビューファイルはRailsのビューのことで、Vue.jsとは関係ありません

実例

コンテナの外から、コマンドを実行します。

$ docker-compose run web rails g controller home index
Creating rails-vue_web_run ... done
Running via Spring preloader in process 22
      create  app/controllers/home_controller.rb
       route  get 'home/index'
      invoke  erb
      create    app/views/home
      create    app/views/home/index.html.erb
      invoke  test_unit
      create    test/controllers/home_controller_test.rb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/home.scss

コントローラ、ビューファイル、SCSS、ルーティングなど、ページ表示に必要なファイル群が一気に生成されます。

http://0.0.0.0:3000/home/index にアクセスして以下のページが表示されればOKです。


WebpackerでVueをインストールする

RailsでVue.jsを読み込むために、Webpackerを使ってRailsにVueを追加します。これを追加することで、Vueファイルのコンパイルが可能になります。

また、デフォルトで、hello_vue.jsという「Hello Vue!」をブラウザに表示するテスト用のファイルも生成してくれます。

rails webpacker:install:vue

実例

Dockerコンテナの外から実行する場合は、サービスを指定して、引数でコマンドを渡します。

$ docker-compose run web rails webpacker:install:vue
省略
Webpacker now supports Vue.js 🎉


webpack関連のファイルが更新され、app.vueやhello_vue.jsといったファイルが生成されます。

        modified:   config/webpack/environment.js
        modified:   config/webpacker.yml
        modified:   package.json
        modified:   yarn.lock

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        app/javascript/app.vue
        app/javascript/packs/hello_vue.js
        config/webpack/loaders/


vue-loaderのバージョンを下げる(コンパイルエラー対応)

rails webpacker:install:vueでVueをインストールした状態では、コンパイルエラーが発生します。

これは、vue-loaderのバージョンが新しすぎて、必要なライブラリが入っていないためです。このため、vue-loaderのバージョンを15系まで落とします。

package.jsonファイルの修正

Webpackerはgemではなくyarn(node.js)で管理されているので、package.jsonに記載されている vue-loaderのバージョンを修正します。

"dependencies": {
  (省略)
    "vue-loader": "15.9.2",
  (省略)
  },


インストール

yarnを使って、package.jsonの内容を読み込み必要なライブラリをインストールします。

# yarn install

▼Dockerコンテナの外から実行する場合

docker-compose.ymlファイルのあるディレクトリで以下を実行します。

# docker-compose run <Railsのサービス名> yarn install


実例

$ docker exec -it rails-vue-web bash
root@59229383d91c:/rails-vue# yarn install
yarn install v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.3.2: The platform "linux" is incompatible with this module.
info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@1.2.13: The platform "linux" is incompatible with this module.
info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > vue-loader@15.9.2" has unmet peer dependency "css-loader@*".
[4/4] Building fresh packages...
success Saved lockfile.
Done in 21.29s.

vue-loader@15.9.2″のインストールが完了しました。

エラー内容の詳細についてはこちらをご参考。


Babelの設定を変更する(大量の警告を非表示にする)

デフォルトの状態では、コンパイル時にBabel関連の警告が大量に表示されるため、この表示をオフにします。

(エラーではなく警告なのでコンパイルは実行できるのですが、コンパイルのたびにターミナル(黒画面)が警告で埋まります)

["@babel/plugin-proposal-private-methods", { "loose": true }]をルート直下にあるbabel.config.jsファイルに追記します。

    plugins: [
     (省略),
     ["@babel/plugin-proposal-private-methods", { "loose": true }]
    ].filter(Boolean)

保存すれば完了です。

次回のコンパイル以降は警告が表示されなくなります。

実際の記述例

module.exports = function(api) {
  var validEnv = ['development', 'test', 'production']
  var currentEnv = api.env()
  var isDevelopmentEnv = api.env('development')
  var isProductionEnv = api.env('production')
  var isTestEnv = api.env('test')

  if (!validEnv.includes(currentEnv)) {
    throw new Error(
      'Please specify a valid `NODE_ENV` or ' +
        '`BABEL_ENV` environment variables. Valid values are "development", ' +
        '"test", and "production". Instead, received: ' +
        JSON.stringify(currentEnv) +
        '.'
    )
  }

  return {
    presets: [
      isTestEnv && [
        '@babel/preset-env',
        {
          targets: {
            node: 'current'
          }
        }
      ],
      (isProductionEnv || isDevelopmentEnv) && [
        '@babel/preset-env',
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          corejs: 3,
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ]
    ].filter(Boolean),
    plugins: [
      'babel-plugin-macros',
      '@babel/plugin-syntax-dynamic-import',
      isTestEnv && 'babel-plugin-dynamic-import-node',
      '@babel/plugin-transform-destructuring',
      [
        '@babel/plugin-proposal-class-properties',
        {
          loose: true
        }
      ],
      [
        '@babel/plugin-proposal-object-rest-spread',
        {
          useBuiltIns: true
        }
      ],
      [
        '@babel/plugin-transform-runtime',
        {
          helpers: false
        }
      ],
      [
        '@babel/plugin-transform-regenerator',
        {
          async: false
        }
      ],
      ["@babel/plugin-proposal-private-methods", { "loose": true }]
    ].filter(Boolean)
  }
}


エラーの詳細やコンパイル結果についてはこちらをご参照ください。


hello_vue.jsをmain.jsに変更する

Webpackのコンパイル対象となる大元のファイル名をhello_vue.jsからmain.jsに変更します。(変更しなくても使えますが、変更するとより本格的に見えるようになります)

ファイル名の変更

hello_vue.js を main.js に変更します。

$ mv app/javascript/packs/hello_vue.js app/javascript/packs/main.js


home/index.html.erbの修正

app/views/home/index.html.erb にWebpackerを使ってコンパイル後の hello_vue.js を読み込んでいる記述を変更します。

<%= javascript_pack_tag 'main' %>
<%= stylesheet_pack_tag 'main' %>

manifest.jsonの修正

manifest.jsonはコンパイル時にWebpackerが自動で生成するファイルです。元のファイルとコンパイル後のファイルの対応表になっています。

hello_vue.jsの状態で既にコンパイルされているため、この記述を変更します。

hello_vue を main に一括置換します。

{
  "application.js": "/packs/js/application-e421b4aa3f716bebdab1.js",
  "application.js.map": "/packs/js/application-e421b4aa3f716bebdab1.js.map",
  "entrypoints": {
    "application": {
      "js": [
        "/packs/js/application-e421b4aa3f716bebdab1.js"
      ],
      "js.map": [
        "/packs/js/application-e421b4aa3f716bebdab1.js.map"
      ]
    },
    "main": {
      "js": [
        "/packs/js/main-f10dedba5d1ccdc85afe.js"
      ],
      "js.map": [
        "/packs/js/main-f10dedba5d1ccdc85afe.js.map"
      ]
    }
  },
  "main.js": "/packs/js/main-f10dedba5d1ccdc85afe.js",
  "main.js.map": "/packs/js/main-f10dedba5d1ccdc85afe.js.map",
}

(参考)修正前のファイル

{
  "application.js": "/packs/js/application-e421b4aa3f716bebdab1.js",
  "application.js.map": "/packs/js/application-e421b4aa3f716bebdab1.js.map",
  "entrypoints": {
    "application": {
      "js": [
        "/packs/js/application-e421b4aa3f716bebdab1.js"
      ],
      "js.map": [
        "/packs/js/application-e421b4aa3f716bebdab1.js.map"
      ]
    },
    "hello_vue": {
      "js": [
        "/packs/js/hello_vue-f10dedba5d1ccdc85afe.js"
      ],
      "js.map": [
        "/packs/js/hello_vue-f10dedba5d1ccdc85afe.js.map"
      ]
    }
  },
  "hello_vue.js": "/packs/js/hello_vue-f10dedba5d1ccdc85afe.js",
  "hello_vue.js.map": "/packs/js/hello_vue-f10dedba5d1ccdc85afe.js.map",
}


以上でmain.jsへの置き換えは完了です。保存して、ブラウザをリロードしページが表示されればOKです。

ビューファイルを編集してVue.jsの内容を表示する

ここまでで、Vue.jsファイルをコンパイルする準備が整ったので、実際に、ブラウザにVue.jsの内容を出力します。

出力するファイルは、rails webpacker:install:vueで自動生成されたテスト用の、app.vueを使います。

表示するルーティングには作成済みのHomeコントローラーのindexアクションを使います。app/views/home/index.html.erb を以下のように書き換えます。

<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>

保存して、Railsを起動するとコンパイルが走ります。

http://localhost:3000/home/index にアクセスして「Hello Vue!」と表示されればvue.jsファイルの表示に成功です。

tips

Webpackerのデフォルト状態のコンパイルはとても時間がかかります。

一度、ctrl + c で起動中のコンテナを終了し、次のコマンドで再起動すれば、劇的に速くなります。

$ docker-compose up -d && docker-compose exec web bin/webpack-dev-server


詳細は【簡単】Dcoker上のRailsでWebpackerのコンパイルが遅すぎるを解決する方法 をご参考ください。

<%= javascript_pack_tag ‘hello_vue’ %>とは?

javascript_pack_tagはWebpackerでコンパイルしたjsファイルを読み込むためのヘルパーメソッドです。

Webpackerは app/javascript/packs 配下にあるJavaScriptファイルを、コンパイルして public/packs/js 配下に出力します。そのコンパイルしたファイルを読み込んでいます。

javascript_pack_tag '元のファイル名' として使います。元のファイル名は .js を省略して指定します。

<%= stylesheet_pack_tag ‘hello_vue’ %>とは?

stylesheet_pack_tagはWebpackerでコンパイルしたcssファイルを読み込むためのヘルパーメソッドです。

Webpackerは app/assets/stylesheets 配下にあるscssやcssファイルを、コンパイルして public/assets 配下に出力します。そのコンパイルしたファイルを読み込んでいます。

stylesheet_pack_tag '元のファイル名' として使います。元のファイル名は拡張子を省略して指定します。

<%= %>とは?

<%= 処理 %>は、erbの中で使うHTMLタグと一緒に使う記述で、記載した処理結果を出力(print)するためのものです。

<% 処理 %>とした場合は、処理は行いますが、その結果を出力しません。

なお、<%== 処理 %> のようにイコールを2つにすると、中に記述したタグなどをエスケープせずそのまま表示します。<%# %>はコメントアウトに使います。

vueファイルの編集

Hello Vue!を表示しているページの内容を編集します。以下のように「picture」いうテキストと画像を表示します。

画像の追加

app/assets/images配下に画像を追加します。ここでは、mountain.jpgを追加しました。

app/assets/images/mountain.jpg

app.vueの編集

app.vueを以下のように変更します。

<template>
  <div id="app">
    <p>{{ message }}</p>
    <div class="picture-wrapper">
        <p>picture</p>
        <img src="../assets/images/mountain.jpg" alt="">
    </div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!",
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
.picture-wrapper{
  margin: 0 auto;
  max-width: 60%;
}
.picture-wrapper img{
  width: 100%;
}
</style>


保存してリロードすれば完成です。

テンプレートファイルを作成して読み込む

現在使っているvueファイルは app.vueのみですが、他のテンプレートパーツを作成して読み込むようにします。

テンプレートファイルの作成

先ほどページに追加したテキストと画像を別のテンプレートに切り出して読み込みます。

app/javascript配下に components ディレクトリを作成し、Mountain.vue ファイルを作成します。

tips

Vueコンポーネントのファイル名はキャメルケースを使うことが多いです。

 ▼例

  • Mountain.vue
  • MountainGallery.vue
<template>
  <div class="picture-wrapper">
    <p>picture</p>
    <img src="../../assets/images/mountain.jpg" alt="">
  </div>
</template>

<script>
export default {
  name: 'Mountain'
}
</script>

<style>
p{
  text-align: center;
}
.picture-wrapper{
  margin: 0 auto;
  max-width: 60%;
}
.picture-wrapper img{
  width: 100%;
}
</style>

画像のパスが間違っているとコンパイルエラーが発生するので注意してください。

app.vueでテンプレートを読み込む

続いて、作成したテンプレートをapp.vueの中で読み込みます。

points
  • ファイルにモジュール名をつけてインポートする(import A from B
  • コンポーネントとしてモジュールを読み込む(components ※複数形)
  • templateタグの中で、モジュールを読み込む( <モジュール名/>

<template>
  <div id="app">
    <p>{{ message }}</p>
    <Mountain/>
  </div>
</template>

<script>
import Mountain from "./components/Mountain"

export default {
  components: {
    Mountain
  },
  data: function () {
    return {
      message: "Hello Vue!",
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>


保存してリロードすれば、先ほどと同じ内容のページが表示されます。(※「picture」のスタイルからfont-size: 2em; が外れます。理由は以下ご参照)

(補足)スタイルについて

VueファイルはHTMLとスタイルを合わせて記述します(単一コンポーネントファイルと言います)。スタイルは各ファイルのみで適用となるため、

app.vueで指定しているスタイルは、テンプレートとして読み込んでいるファイルには適用されません。それぞれ個別に指定する必要があります。

すべてのVueファイルにスタイルを共通で設定したい場合は、app/assets/stylesheets/application.css に記述します。

p{
  color: red;
}

保存してコンパイルすると、app.vueと、mountain.vueの両方のファイルにスタイルが適用されます。


Vuetifyを使う

VuetifyはVue.jsで使うことができるマテリアルデザインのUIフレームワークです。簡単にいうと、おしゃれなボタンなどのパーツをとても簡単に設置できるパーツのライブラリです。

(参考)Vuetify公式ページ

Vuetify公式ページのWebpackでのインストール手順を参考にしていきます。

Vuetifyのインストール

Railsコンテナ内でyarn add vuetify を実行します。コンテナの外から実行する場合は以下になります。

docker-compose run web yarn add vuetify

webの部分は、docker-composeで指定してあるRailsのサービス名を記載してください。

hello_vue.jsの編集

Vuetifyのインスタンスを生成し、変数vuetifyに格納します。 Vueのインスタンス初期化を行うところで、vuetifyをオプションとして渡します。

import Vue from 'vue'
import App from '../app.vue'
import Vuetify from 'vuetify' //追加
import 'vuetify/dist/vuetify.min.css' //追加

Vue.use(Vuetify) //追加
const vuetify = new Vuetify(); //追加

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    vuetify, //追加
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)

  console.log(app)
})

GoogleフォントのCDNリンク設置

VuetifyはGoogleのRobotoフォントとMaterial Designアイコンを使用するため、CDNのリンクを共通レイアウトのheadタグ内に含めます。

<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">

共通レイアウトは app/views/layouts/application.html.erb です。

また、application.jsは使っていないため削除します。

<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

修正後のapplication.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>RailsVue</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

以上でVuetifyを使う準備は完了です。

Vuetifyを使う

VuetifyのUIコンポーネントをテンプレート内で呼び出します。

Vuetifyはv-appタグの中で使う必要があります。v-appタグの中にない場合、指定したスタイルが適用されないなどの不具合が発生します。(※この中で読み込むテンプレートには不要です。)

まずは、簡単にアラートUIを表示してみます。app/javascript/app.vue の

  • templateタグの中のdivタグをv-appタグに変更します。
  • v-alertタグを追加します。スタイルの調整は決められた属性を使います。
<template>
  <v-app id="app">
    <p>{{ message }}</p>
    <Mountain/>

    <v-alert
      type="success"
      width="400px"
      color="green"
      class="mx-auto"
    >Alert created by Vuetify</v-alert>

  </v-app>
</template>

<script>
import Mountain from "./components/Mountain"

export default {
  components: {
    Mountain
  },
  data: function () {
    return {
      message: "Hello Vue!",
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>


保存してページをリロードします。画像の下に次のようなVuetifyのUIコンポーネントが表示されれば正しく読み込めています。

Vuetify UIコンポーネントのスタイル指定方法

Vuetify UIコンポーネントのスタイルを指定するときは、各コンポーネント毎に使えるスタイルを公式ページで確認します。

例えば、Vuetify alertsコンポーネントの場合だと、右側のオプションでスタイルを選択することができます。

スタイルが決まったら下に表示されているコードをvueファイルのテンプレート内にコピペすれば完了です。

他に、全体的に使える属性として、widthやheightがあります。それぞれpxや%で指定することができます。

marginやpaddingを指定したい場合は、専用の表記で指定します。例えば、左右方向のmarginをautoにしたい場合は、mx-auto をclass属性の値として指定します class="mx-auto"。加えて、margin-topを40pxにしたい場合は、mt-10を追加します class="mx-auto mt-10"。(※4の倍数で用意されているため)

Vuetifyコンポーネントのmarginとpaddingの指定

m – margin
p – padding

t – margin-topおよびpadding-topの間隔を適用します。
b – margin-bottom と padding-bottom の間隔を適用します。
l – margin-left と padding-left の間隔を適用します。
r – margin-right と padding-right の間隔を適用します。
x – *-left と *-right の間隔を適用します。
y – *-top と *-bottom の間隔を適用します。
a – プロパティの間隔を、天地左右すべての方向に適用します。

Vuetifyコンポーネントのmarginとpaddingのサイズ指定

4px の間隔でプロパティの増分を制御します:

  • 0 – eliminates all margin or padding by setting it to 0
  • 1 – sets margin or padding to 4px
  • 2 – sets margin or padding to 8px
  • 3 – sets margin or padding to 12px
  • 4 – sets margin or padding to 16px
  • 5 – sets margin or padding to 20px
  • 6 – sets margin or padding to 24px
  • 7 – sets margin or padding to 28px
  • 8 – sets margin or padding to 32px
  • 9 – sets margin or padding to 36px
  • 10 – sets margin or padding to 40px
  • (省略)
  • auto – 間隔を auto に設定

ブレイクポイントも指定することができます。詳細は、Vuetify公式 Spacingをご参照ください。

今回の例では以下のスタイルをセットしています。

  • type=”success” : チェックマークのアイコンを表示
  • width=”400px” :幅400px
  • color=”green” : 背景色 緑(※文字色ではなく背景色の指定になります)
  • class=”mx-auto” : 左右中央寄せ
    <v-alert
      type="success"
      width="400px"
      color="green"
      class="mx-auto"
    >Alert created by Vuetify</v-alert>

Vuetifyをテンプレートとして呼び出す

ヘッダーテンプレートの作成

最後にVuetifyをテンプレートとして呼び出します。共通ヘッダーを作ります。

app/javascript/components配下に Header.vue ファイルを作成します。

tips

テンプレートをv-appタグの中で呼び出す場合、テンプレートにv-appタグは不要です。

つけると余計なスペースが入りレイアウトが崩れます。

<template>
  <v-card
    color="grey lighten-4"
    flat
    tile
  >
    <v-toolbar dense>
      <v-app-bar-nav-icon/>

      <v-toolbar-title>Rails-Vue-App</v-toolbar-title>

      <v-spacer/>

      <v-btn icon>
        <v-icon>mdi-magnify</v-icon>
      </v-btn>

      <v-btn icon>
        <v-icon>mdi-dots-vertical</v-icon>
      </v-btn>
    </v-toolbar>
  </v-card>
</template>

<script>
export default {

}
</script>

<style>

</style>


テンプレートの読み込み

app/javascript/app.vue で Header.vueをコンポーネントとして読み込みます。

points
  • ファイルにモジュール名をつけてインポートする(import A from B ※.vueや.jsは省略可)
  • コンポーネントとしてモジュールを読み込む(components ※複数形)
  • templateタグの中で、モジュールを読み込む( <モジュール名/>

<template>
  <v-app id="app">
    <Header/>

    <p class="page-title">{{ message }}</p>
    <Mountain/>

    <v-alert
      type="success"
      width="400px"
      color="green"
      class="mx-auto"
    >Alert created by Vuetify</v-alert>

  </v-app>
</template>

<script>
import Mountain from "./components/Mountain"
import Header from "./components/Header"

export default {
  components: {
    Mountain,
    Header
  },
  data: function () {
    return {
      message: "Hello Vue!",
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
.page-title{
  margin-top: 20px;
}
</style>


保存して読み込むといい感じに、ヘッダーナビゲーションが表示されます。


(補足)Headerテンプレートの構成

Headerテンプレートでは7つのVuerity UIコンポーネントを使っています。

  • v-card
  • v-toolbar
  • v-app-bar-nav-icon
  • v-toolbar-title
  • v-spacer
  • v-btn
  • v-icon

v-card

v-cardは外枠となるdivタグとして使われる要素です。

(参考)https://vuetifyjs.com/ja/components/cards/

v-toolbar

v-toolbarはナビゲーションなどを構成する要素を使うためのコンポーネントです。v-cardやv-navigation-drawerの中で使います。

この中に、v-app-bar-nav-iconなどの要素を設置していきます。

(参考)https://vuetifyjs.com/ja/components/toolbars/

v-app-bar-nav-icon

v-app-bar-nav-iconは三本線のアイコンになります。v-toolbar と v-app-barの中で使用します。

コンポーネントではなくサブコンポーネント(API)の位置づけになります。

(参考)https://vuetifyjs.com/ja/api/v-app-bar-nav-icon/

v-toolbar-title

v-toolbar-titleはv-toolbarの中でタイトルテキストを表示するためのサブコンポーネント(API)です。

(参考)https://vuetifyjs.com/ja/api/v-toolbar-title/

v-spacer

v-spacerを使うとその前後のコンポーネントが左右にプッシュされます。後ろの検索アイコンなどを右端に寄せたい場合に設置します。

grids systemの中で定義されるサブコンポーネント(API)です。

(参考)https://vuetifyjs.com/ja/components/grids/
(参考)https://vuetifyjs.com/ja/api/v-spacer/

v-btn

v-btnはbuttonタグをおしゃれに表示してくれるコンポーネントです。テキストを入れることで文字が表示されます。

アイコンを表示する場合もラッパーとして使います。その場合は、オプションにiconを指定します。

(参考)https://vuetifyjs.com/ja/components/buttons/

v-icon

v-iconはアイコンを表示するためのコンポーネントです。 MDIとFont Awesomeのアイコンが使えます

ボタンの中にアイコンを表示する場合はオプションにiconを指定します。

caution

ここまでの流れではFont AwesomeのCDNは読み込んでいません。Font Awsomeを使うには、app/views/layouts/application.html.erb ファイルのheadタグ内でlinkタグを使ってCDNを読み込む必要があります。

(参考)https://vuetifyjs.com/ja/components/icons/


以上で完了です。お疲れ様でした。

タイトルとURLをコピーしました