Vue-CLI3でBootstrap-Vue

# 背景
- Bootstrapが完全にVue上コンポーネントにラッピングされた[BootstrapVue](https://bootstrap-vue.js.org/)とVue CLIの同時導入に関する記事です
 - VueをCDNで導入するとBootstrapに必要なjQueryと衝突することがあるので試してみた次第．
- Vue CLI 3を使います．Vue CLIは2系の紹介サイトは多いのですが，3はまだ少ないように思うので，情報の足しになれば．

## こんな人に
- VueとBootstrapをCDNで使っていた
- Vue Componentの知識はある
- Vue CLIで初めてWebpack,Babel,ESlintに触れる

# 環境
- node v8.16.0
- Vue CLI 3.9.3
- BootstrapVue 2.6.1

# Vue CLI3導入
[Vue CLI](https://cli.vuejs.org/guide/)はnodeベースのVue webアプリケーションの開発ツール．
Vueは日本語情報あるが，Vue CLIは英語ページしかなく，またVue CLI 2系と扱いも異なるので注意．

導入は基本的には[本家ページ](https://cli.vuejs.org/guide/installation.html)を参照

```
$ npm install -g @vue/cli
+ @vue/cli@3.9.3
$ vue --version
3.9.3
```
注意点として，node v8.9以上が必要なので，nodebrewなどでインストール・使えるようにしておくこと

### プロジェクトの作成
```
$ vue create プロジェクト名
```
を実行して作成．質問はそのままEnterで問題なし．すると，現在のフォルダに "プロジェクト名" のフォルダとファイル類ができる．(以下では`project-sample`とします)

### フォルダ構成
```
project-sample/
 ├ package.json
 ├ vue.config.js : vueだけでなくwebpackに関するconfigもここ
 ├ babel.config.js : babelに関するconfig
 ├ src : ソースファイル
 |  ├ main.js : アプリのエントリ
 |  ├ App.vue : main.jsで読まれるメインページのコンポーネントファイル
 |  ├ components : App.vue以外のコンポーネントファイル
 |  ├ assets : コンポーネントで使う画像やcssなど
 |  ├ plugins : main以外のjsファイル
 ├ public : 静的ファイルとテンプレートデータ
 ├ dist : 後述のbuildするとここにできる
```

### ローカルで実行

```
$ cd project-sample
$ npm run serve
```

ブラウザで`localhost:8080`にアクセスし，Hello World的なのが表示されればOK．

Vue CLIのコマンド(`npm run`の後に`serve`,`build`,`lint`)は現在のプロジェクトルート(project-sample)下で使います．

この状態でApp.vueなどのファイルを変更すると，リアルタイムで更新されます．

私の環境(Mac OS 10.12/Safari 12.1)では更新されたりされなかったりしたため，Google Chromeを使用している．ビルドエラーやESlintのエラーがあればブラウザにも表示されます．

### ビルド
本番用ファイルにwebpackでバンドルする．

```
$ npm run build
```
distフォルダにできたファイルをサーバに入れ，

# BootstrapVue導入
プロジェクトルートで以下コマンドでインストール

```
$ npm install vue bootstrap-vue bootstrap
```

main.jsを変更

```javascript:main.js
import Vue from 'vue'
import {BootstrapVue, IconsPlugin} from 'bootstrap-vue' //追加
Vue.use(BootstrapVue) //追加
Vue.use(IconsPlugin) //追加
import 'bootstrap/dist/css/bootstrap.css' //追加
import 'bootstrap-vue/dist/bootstrap-vue.css' //追加
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

### 使い方
Vue Componentになっているものは[公式Docs](https://bootstrap-vue.js.org/docs/components)で参照できますが，基本的にはxxのコンポーネントは`<b-xx>`という形のタグで使うことになります．例えば，

```html:before
<button class="btn btn-primary">ボタン</button>
```
は

```html:after
<b-button variant="primary">ボタン</b-button>
```

というようになります．色は`variant`，サイズは`size`といったclassとは別のattributeが割り当てられています．

## 注意点
### コンポーネントへのスタイル適用
VueのComponentはcssのタグセレクタで**ヒットしない**ので，以下の使い方ができません．

```vue:vue
<template>
 <div class="test">
  <b-button>1</b-button>
  <b-button>2</b-button>
 </div>
</template>
(中略)
<style>
.test b-button {
  background-color: gray;
}
</style>
```
実際のレンダリングに対応するセレクタを使うか，それぞれクラスで指定するなりが必要です．

```css:
.test button {
  background-color: gray;
}
</style>
```

他にも，コンポーネントによってはdiv下にbuttonがあったりとどこにスタイルが適用されるかわかりにくい場合もあるのが厄介でした．

# その他設定
### ビルド後ファイルをサーバのルートに置かない場合
ビルド後のファイル(js,css)のロードは，デフォルトではルートからのディレクトリで指定される．例えば`example.com/test/`の下にdist内のファイルを配置するような場合は以下の設定が必要

```javascript:vue.config.js
module.exports = {
  publicPath : './'
}
```

### console.logを使う場合
何も設定しないとESLintに怒られるので設定．

```javascript:package.json
(中略)
"eslintConfig": {
  "rules": {
    "no-console": "off"
  }
}
```

### serveとbuildでimport先を変更
開発時はダミーで，実装時はDB読むようにしたい場合には，Webpackの際に`process.env.NODE_ENV`で切り替える必要があります．aliasで設定された名前がjsのimportで使えることを利用して切り替えてみました．

```javascript:jsもしくはvueファイル
(中略)
import SomeModule from 'moduleName'
```

```javascript:vue.config.js
const path = require('path')
let mod = 'src/plugins/dev.js'
if(process.env.NODE_ENV=='production'){
  mod = 'src/plugins/prod.js'
}
module.exports = {
  (中略)
  configureWebpack: {
    resolve: {
      alias: {
        'moduleName$': path.resolve(__dirname,mod)
      }
    }
  }
}
```

### Sass利用+全コンポーネント共通ファイル
Sass導入は以下コマンドでインストール

```
$ npm install -D sass-loader sass
```
vueファイルのstyleでlangを指定すると使える(以下の場合はscssで)

```vue:some.vue
<style lang="scss">
</style>
```
共通ファイル(例えば`src/assets/global.scss`)はvue.config.jsに以下設定

```javascript:vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      prependData: '@import "src/assets/global.scss";'
    }
  }
}
```
変数，mixinの定義に便利だが，通常のセレクタを書いてしまうと二重，三重の定義になってしまうのであまりよろしくなさそう．