RailsはWebpackでVue.jsを使うことができます。ですが、Ruby用の.erbとvueファイル用の.jsが混在し、かつ、コンパイルも行われるので、どの順番でファイルを表示しているのかが分かりにくいです。
ここでは、RailsでWebpackerとVue.jsの理解を深めるため、処理の流れをまとめています。
RailsでVue.jsを使う方法については以下をご参考ください。
(参考)Docker上に構築したRails6でVue.jsを表示する方法
ファイルの構成
localhost:3000/home/index にアクセスした時に、Vue.jsで作成した、 main.js を開いてブラウザに表示する例を用います。
使用しているファイル
ファイルの構成は次のようになっています。
app
|- assets
| ┗ stylesheets
| ┗ application.css
|
|- javascript
| ┗ app.vue
| ┗ packs
| ┗ main.js
|
|- views
| ┗ home
| ┗ index.html.erb
| ┗ layouts
| ┗ application.html.erb
|
|- controllers
| ┗ home_controller.rb
|
config
┗ routes.rb
- スタイルシート: app/assets/stylesheets/application.css
- VueとVuetifyの読み込み: app/javascript/packs/main.js
- Vue.jsで作成したページ: app/javascript/app.vue
- ビューファイル: app/views/home/index.html.erb
- 全体共通のレイアウト: app/views/layouts/application.html.erb
- コントローラ: app/controllers/home_controller.rb
- ルーティング: config/routes.rb
ブラウザのアクセスからページ表示までの流れ
ルーティング
localhost:3000/home/indexにアクセスすると、まずルーティングが参照されます。
・ルーティング: config/routes.rb
Rails.application.routes.draw do
get 'home/index'
end
get 'home/index'
の記述に沿って、Homeコントローラのindexアクションが実行されます。
ルーティングの内容についてはこちらをご参考ください。
コントローラ
コントローラのindexアクションはデフォルトの状態です。
- コントローラ: app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
end
end
この場合、viewsディレクトリ配下にある、コントローラ名のディレクトリのアクション名.erb ファイルを開きます。
ビューファイル
開くのはhome/index.html.erbです。
- ビューファイル: app/views/home/index.html.erb
<%= javascript_packs_with_chunks_tag 'main' %>
ビューファイルの中には、javascript_packs_with_chunks_tagでmainを指定しています。
この場合、app/javascript/packs 配下にある指定したファイル名のJavaScriptファイルにアクセスします。(正確にはそのファイルをコンパイルしたもの)
JavaScriptファイル
javascript_packs_with_chunks_tagで指定したmainは次のファイルになります。
- VueとVuetifyの読み込み: app/javascript/packs/main.js
このファイルは、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)
})
importでVueやVuetifyを読み込んでいます。
const app = new Vue({ })
Vueのインスタンスを生成し、変数appに代入しています。
カッコの中で、どういった内容でVueインスタンスを生成するかを指定しています。ここでは、render関数で生成したHTMLタグと、Vuetifyのインスタンスを渡しています。
render: h => h(App)
指定したファイルをHTMLに変換(レンダリング)します。
Appはimport App from '../app.vue'
で定義しています。つまり、app/javascript/app.vue を読み込んでいます。
document.body.appendChild
対象.appendChild(要素)は、指定した対象のタグの子要素に新たにタグを追加する時に使います。
document.body.appendChild(app) は、生成したVueインスタンス(HTMLタグ)をbodyタグの中に子要素として追加する処理です。
Vueファイルの読み込み
app/javascript/packs/main.js にアクセスし、その処理の中で、app/javascript/app.vue をHTMLにレンダリングしています。
ここでようやく、Vueファイルにたどりつきました。
- Vue.jsで作成したページ: app/javascript/app.vue
内容は重要ではないのですが、参考までに記載しておきます。
<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>
bodyタグはどこか?
先ほどの、VueとVuetifyをインスタンス化していた、app/javascript/packs/main.jsの中で、document.body.appendChildを使って、HTMLタグに変換ごのVueファイルをbodyタグに追加していました。
このbodyタグは、app/views/layouts/application.html.erbに記載されています。application.html.erbはビュー全体で共通となるheadタグなどのHTMLです。
- 全体共通のレイアウト: app/views/layouts/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>
bodyタグの中にある、<%= yield %>
にコントローラで指定したページの内容が表示されます。
headタグの中では、stylesheet_link_tagを使っています。
スタイルシートの読み込み
app/views/layouts/application.html.erbの中でstylesheet_link_tagを使ってスタイルシートを読み込んでいます。
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
対象のスタイルシートは、app/assets/stylesheets/application.css です。これをlinkタグのhref属性で指定しています。
また、属性として、media=”all” と、data-turbolinks-track=reload も合わせて指定しています。
stylesheet_link_tagやmain, data-turbolinks-trackについては下記で詳しく説明しています。
以上が、ブラウザでURLを叩いてから、画面にVueで作成したページが表示されるまでの流れになります。
まとめ
最後に流れをまとめると次のようになります。
リクエスト localhost:3000/home/index
↓
ルーティング: config/routes.rb
↓
コントローラ: app/controllers/home_controller.rb
↓
ビューファイル: app/views/home/index.html.erb
↓
VueとVuetifyの読み込み: app/javascript/packs/main.js
↓
Vue.jsで作成したページ: app/javascript/app.vue
↓
全体共通のレイアウト: app/views/layouts/application.html.erb
↓
スタイルシート: app/assets/stylesheets/application.css
↓
ブラウザでページ表示