単一ファイルコンポーネントの原則
コンポーネントごとにvueファイルを作成する開発の進め方のこと。つまりパーツ単位でHTMLをまとめてコンポーネントとして扱いどこでも呼び出せるようにすること、を指すと考えて良さそう。
これの反対をグローバルコンポーネント、といい
new Vue({ el: '#container '})
といった形でcontainerをターゲットにしたvueファイルを作り、各ページで読み込む。この書き方は小規模開発では優れているが、大規模な開発になるといくつか不具合が生じる。中でも全てのコンポーネントの変数定義が共通になるのはちょっと避けたい。よって使用するHTMLごとにコンポーネント化する単一ファイルコンポーネントの原則に従って開発するのがベター。
単一コンポーネントでvueファイルを書くとこんな感じ
<template>
<div class="side_bar">SideBar</div>
</template>
<script>
</script>
<style>
.side_bar {
width: 300px;
background-color: green;
}
</style>
templateの部分にHTML、scriptでjs、styleでcssを指定する。これをHTML部品ごとに作る。こうすると部品ごとに一つのファイルで扱えるのでやり直しがしやすい。またこのクラスにあたってるcssどれ?みたいな疑問もなくなる。
作ったコンポーネントをrailsアプリで読み込むわけだが今回は
各コンポーネントを読み込む親のjsがエントリーファイルとなっている。こいつをbuildしてrailsアプリで読み込むと各コンポーネントの設定がアプリに反映される仕組み。
main.js(エントリーファイル)
import Vue from 'vue';
import App from './App.vue';
// App.vueをエントリとしてレンダリング
new Vue({
el: '#app',
render: h => h(App)
})
App.vue(親コンポーネント)
<template>
<div class="container">
<sidebar></sidebar>
<chat-container></chat-container>
</div>
</template>
<script>
import Sidebar from './components/Sidebar.vue'
import ChatContainer from './components/ChatContainer.vue'
export default {
components:{
Sidebar,
ChatContainer
}
}
</script>
<style>
.container {
display: flex;
margin: auto;
width: 70%;
height: 100vh;
}
</style>
こいつをwebpackでコンパイルする。webpack.config.jsは以下の通り
module: {
rules: [
{
test: /\.vue$/,
exclude: /node_modules/,
loader: 'vue-loader'
},
{
test: /\.css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},
]
},
(省略)
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
}
},
plugins: [new VueLoaderPlugin()]
重要なのはloaderとresolveオプションかなと思うので関係ないところ
は省略。ちょっとハマったのはcss-loaderとstyle-loaderを読み込む際にはなぜかloaderオプションじゃなくてuseオプションにしないといけなかったこと。複数loaderを読み込むからなのかな?
コンパイル後にrailsサーバーを立ち上げると画像のように別々のファイルに書いたhtmlとcssがきっちり反映されて一つのビューにまとまっていることがわかる。
参考
・単一ファイルコンポーネントについての公式ドキュメント
・単一ファイルコンポーネントをwebpackを使って実現する方法について