【Vue】VueCLI3に頼らずVue.jsの開発環境構築をする 【babel7, .vueファイルのeslint + prettierなど】

# Vue.jsの開発環境を手作りした話

書いた日：`18/10/19`

手動で構築した開発環境は暖かみがちがう
古事記にもそう書かれている

## 動機

環境構築手動でやるのが好きになって来たこの頃、
VueCLIを久しぶりに触ってびっくりしました  

なんやこれ！ `$ vue add @vue/eslint` って何！？
知らんところで色々起きるの！こわ！！富豪的すぎない！？
https://cli.vuejs.org/guide/plugins-and-presets.html#plugins

と思いイチから環境構築した話
単一ファイルコンポーネントのeslint/prettierにも興味があったしね！  

VueCLIはGUIもついていて、非常に優れた環境構築ツールですが
自分で構築してみるとすごく勉強になりますよ


## 対象読者
* vue.jsや.vueファイルの知識がある人
* VueCLIが裏でやってることに興味がある人
* 好きに環境構築したい人

「これいらなくない？」「今はこっちがいいよ」など気軽に編集リクエストくださいね

## package導入

まずは`vue`本体たちを導入
`vuex`, `vue-router`は必要に応じて

``` terminal
$ yarn add vue vuex vue-router
```

忘れないうちにpolyfillも入れます
babel7で名前が `@babel/polyfill`に変わっているよ  

``` terminal
$ yarn add @babel/polyfill
```

今の時点でこんな感じ

``` json:package.json
"dependencies": {
  "@babel/polyfill": "^7.0.0",
  "vue": "^2.5.17",
  "vue-router": "^3.0.1",
  "vuex": "^3.0.1"
}
```

次にdevDependenciesを入れます
開発時しか使わないので全部 -D オプションをつけてね  
まず`babel`関連から  

``` terminal
$ yarn add -D @babel/core @babel/preset-env　@babel/plugin-proposal-object-rest-spread
```

次に`webpack`たち

``` terminal
$ yarn add -D webpack webpack-cli webpack-dev-server
```

`webpack`入れたので`loader`も入れましょう

``` terminal
$ yarn add -D babel-loader css-loader file-loader vue-loader 
```

scss使いたいので`node-sass`と`sass-loader`も入れます

``` terminal
$ yarn add -D sass-loader　node-sass
```

`vue`のコンパイラも入れます

``` terminal
$ yarn add -D vue-template-compiler
```

`../../../components/atoms/hoge` とか書きたくないのでルート相対パスimport用プラグインを入れます
これは使いたかったら入れてね

``` terminal
$ yarn add -D babel-plugin-root-import
```

ここからは`eslint`まわりです
まずは本体から

``` terminal
$ yarn add -D eslint
```

今回のruleはstandardの気分なので、依存パッケージごとまとめて入れます
airbnb派の人は適宜読み替えてね  

``` terminal
$ yarn add -D eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
```

ルート相対パスでのimportをeslintに対応させましょう
そのままだとエラー吐いちゃうからね
※`babel-plugin-root-import`入れてない人は飛ばしてね

``` terminal
$ yarn add -D eslint-import-resolver-babel-plugin-root-import 
```

`vue`用のlint設定も追加します

``` terminal
$ yarn add -D eslint-plugin-vue 
```

さらに.vueファイルのlintには別のパッケージも必要になります
疲れてきた？あと少し！

``` terminal
$ yarn add -D vue-eslint-parser
```

ここから`prettier`の追加です
あと少しと言ったな？あれは嘘だ  

``` terminal
$ yarn add -D prettier
```

`prettier`はそのままだと`eslint`とぶつかるので共存させましょう
まずは`prettier`側

``` terminal
$ yarn add -D prettier-eslint
```

`eslint`側も対応させます

``` terminal
$ yarn add -D eslint-plugin-prettier eslint-config-prettier
```

おめでとう！packageの導入が終わりました！
こんな感じになってるはず

``` json:package.json
{
  "devDependencies": {
    "@babel/core": "^7.1.2",
    "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
    "@babel/preset-env": "^7.1.0",
    "babel-loader": "^8.0.4",
    "babel-plugin-root-import": "^6.1.0",
    "css-loader": "^1.0.0",
    "eslint": "^5.7.0",
    "eslint-config-prettier": "^3.1.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-import-resolver-babel-plugin-root-import": "^1.1.1",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^7.0.1",
    "eslint-plugin-prettier": "^3.0.0",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^5.0.0-beta.3",
    "file-loader": "^2.0.0",
    "node-sass": "^4.9.4",
    "prettier": "^1.14.3",
    "prettier-eslint": "^8.8.2",
    "sass-loader": "^7.1.0",
    "vue-eslint-parser": "^3.2.2",
    "vue-loader": "^15.4.2",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  },
  "dependencies": {
    "@babel/polyfill": "^7.0.0",
    "vue": "^2.5.17",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  }
}
```

ついでなのでnpm scripts追加しときましょう
`$ yarn start` `$ yarn build` でローカルサーバーもビルドも一発です

``` json:package.json
{
  "scripts": {
    "start": "webpack-dev-server --hot --open",
    "build": "webpack -p"
  },
  "devDependencies": {
  …
```

## babelの設定

`.babelrc`を作成します  
  
babelのトランスパイル対象設定を記述します
`"targets": "> 0.25%, not dead"` で市場シェアが0.25％を超えるブラウザだけ対応できるらしいよ すごいね
https://babeljs.io/docs/en/babel-preset-env

``` json:.babelrc
{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }]
  ]
}
```

次にプラグインの設定を追加します
`babel-plugin-root-import`は入れた人だけ！設定内容もお好みで

``` json:.babelrc
{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }]
  ],
  "plugins": [
    "@babel/plugin-proposal-object-rest-spread",
    [
      "babel-plugin-root-import",{
        "rootPathPrefix": "~",
        "rootPathSuffix": "src"
      }
    ]
  ]
```

## eslintの設定

さあ正念場です `.eslintrc`を作成しましょう
まずブラウザ環境なのを明示

``` json:.eslintrc
"env": {
  "browser": true
}
```

`parser`を追加
これで.vueファイルにeslintを適用できます
https://github.com/mysticatea/vue-eslint-parser

``` json:.eslintrc
"parser": "vue-eslint-parser",
"parserOptions": {
  "ecmaVersion": 2018
},
```

eslintの設定を追加
vue用のlint > prettier > 最後にstandard の順番でlintします

``` json:.eslintrc
"extends": [
  "standard",
  "plugin:prettier/recommended",
  "plugin:vue/recommended"
],
```

eslint用のプラグインを記述します
eslint-plugin-prettier, eslint-plugin-vueを見に行きます

``` json:.eslintrc
"plugins": [
  "prettier",
  "vue"
],
```

eslintのルールを追加します
セミコロンなし、コンマ制限、シングルクォートにしました
ここは各自のお好みで

``` json:.eslintrc
"rules": {
  "comma-dangle": ["error", "never"],
  "quotes": ["error", "single"],
  "prettier/prettier": [
    "error",
    {
      "semi": false,
      "singleQuote": true,
      "trailingComma": "none"
    }
  ]
},
```

最後に`babel-plugin-root-import`の設定です
これは入れた人だけ！いいね？

``` json:.eslintrc
"settings": {
  "import/resolver": {
    "babel-plugin-root-import" : {
      "rootPathPrefix": "~",
      "toorPathSuffix": "src"
    }
  }
}
```

最後に完成形を貼っておきます

``` json:.eslintrc
{
  "env": {
    "browser": true
  },
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "ecmaVersion": 2018
  },
  "extends": [
    "standard",
    "plugin:prettier/recommended",
    "plugin:vue/recommended"
  ],
  "plugins": [
    "prettier",
    "vue"
  ],
  "rules": {
    "comma-dangle": ["error", "never"],
    "quotes": ["error", "single"],
    "prettier/prettier": [
      "error",
      {
        "semi": false,
        "singleQuote": true,
        "trailingComma": "none"
      }
    ]
  },
  "settings": {
    "import/resolver": {
      "babel-plugin-root-import" : {
        "rootPathPrefix": "~",
        "toorPathSuffix": "src"
      }
    }
  }
}
```

## webpack.config.js

適宜やってください！
localhostのポートは3000にしてみました

``` javascript:webpack.config.js
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
  mode: 'development',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, './dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            js: ['babel-loader']
          }
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        options: {
          presets: ['@babel/preset-env']
        }
      },
      {
        test: /\.css$/,
        use: ['css-loader']
      }
    ]
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.esm.js'
    },
    extensions: ['*', '.js', '.vue', '.json']
  },
  plugins: [new VueLoaderPlugin()],
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    port: 3000
  }
}
```



## 感想

reactに比べると一筋縄で行きませんでした… リッチなフレームワークだものね
vueの書き味は好きなので、reactと合わせて学んで幸せな実装をやっていきましょう