Vueのeslint/stylelint設定

## .eslintrc.js

まずvue-cliで生成された`.eslintrc.js`

```
module.exports = {
  root: true,
  env: {
    node: true
  },
  extends: ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"],
  rules: {
    "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
    "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off"
  },
  parserOptions: {
    parser: "@typescript-eslint/parser"
  },
  overrides: [
    {
      files: ["**/__tests__/*.{j,t}s?(x)"],
      env: {
        jest: true
      }
    }
  ]
};
```

### extends

```
extends: ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"],
```

#### plugin:vue/essential

Vue用に拡張されたルールセット。[vuejs/eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue/tree/master/docs/rules)がインストールされている場合、`plugin:vue/essential`,`plugin:vue/strongly-recommended`,`plugin:vue/recommended `から選ぶことができます。

各ルールについては[スタイルガイド — Vue.js](https://jp.vuejs.org/v2/style-guide/#%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA)を参照してください。

#### @vue/prettier

[vuejs/eslint-config-prettier](https://github.com/vuejs/eslint-config-prettier)

vue-cliでprettierを選択しなかった方は`@vue/standard`になっています。
どちらも以下の記述があり、vue-cli以外では使わないモジュールです。

> この設定は、vue-cliセットアップで使用するように特別に設計されており、外部での使用を意図したものではありません

### @vue/typescript

[vuejs/eslint-config-typescript](https://github.com/vuejs/eslint-config-typescript)

> vue-cliセットアップで使用するように特別に設計されており、外部での使用を意図したものではありません

詳細は調べてないですが、extendsの並びによってエラー内容が変わるので注意。

```
## '@vue/typescript'を最初に記述した場合
✖ 7 problems (0 errors, 7 warnings)

## '@vue/typescript'を最後に記述した場合
✖ 11 problems (4 errors, 7 warnings)
```

### rules

extendsで指定したルールセットをさらに上書きしたい場合、こちらにルールを追記します。

```
rules: {
  "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
  "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off"
},
```

### parserOptions

eslintは通常typescriptをパースできないので、parsetOptionを指定してパースできるようにします。

```
parserOptions: {
    parser: "@typescript-eslint/parser"
  },
```

[GitHub - typescript-eslint/typescript-eslint: Monorepo for all the tooling which enables ESLint to support TypeScript](https://github.com/typescript-eslint/typescript-eslint#what-about-tslint)

## Vueのスタイルガイド

[スタイルガイド — Vue.js](https://jp.vuejs.org/v2/style-guide/)

VueのSFCのテンプレートは以下のように`template`,`script`,`style`から成り立っています。

``` XXX.vue
<template>
</template>

<script>
</script>

<style>
</style>
```

### 好みの別れるtemplate部分のスタイル

どの書き方が好きですか？

```
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
```

```
<li v-for="todo in todos" :key="todo.id">
  {{ todo.text }}
</li>
```

```
<li
  v-for="todo in todos"
  :key="todo.id"
>
  {{ todo.text }}
</li>
```

個人的には一番上の一行で書くスタイルです。
属性の数は2つまでなら一行で書きたいですね。
また一行の文字数が短い場合は`{{}}`も一行に収めたいです。

細かな調整を行いたい場合は先ほども紹介した、[スタイルガイド — Vue.js](https://jp.vuejs.org/v2/style-guide/#%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA)を参照してください。

## style部分

script部分は`stylelint`を使用してlintをかけます。
以下のモジュールをインストールしました。

`yarn add -D stylelint stylelint-config-standard stylelint-order stylelint-scss`

デフォルトでは`stylelint`の設定ファイルはないので作成します。


```
touch .stylelintrc.js
```

好みのスタイルの書き方にあわせて[Stylelint generator](https://maximgatilin.github.io/stylelint-config/)を使うと便利かもしれません。
私は以下の設定を使用しています。

``` .stylelintrc.js
module.exports = {
  extends: 'stylelint-config-standard',
  plugins: ['stylelint-order', 'stylelint-scss'],
  rules: {
    'at-rule-no-unknown': null,
    'scss/at-rule-no-unknown': true,
    'order/properties-alphabetical-order': true,
    'no-empty-source': null,
    'rule-empty-line-before': [
      'always',
      {
        except: 'inside-block',
      },
    ],
  },
};
```

``` scss
<style scoped lang="scss">
.computed {
  margin: 40px 0 0;

  &-list {
    margin-top: 20px;
    list-style: none;
  }
}
.test {
  text-align: center;
  background: #ddd;
}
</style>
```

↓

``` scss
<style scoped lang="scss">
.computed {
  margin: 40px 0 0;
  &-list {
    list-style: none;
    margin-top: 20px;
  }
}

.test {
  background: #ddd;
  text-align: center;
}
</style>
```

## 今回の設定ファイルまとめ

``` package.json
"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "test:unit": "vue-cli-service test:unit",
  "lint": "run-p fix:*",
  "lint:js": "eslint --fix \"**/*.{vue,{j,t}s?(x)}\"",
  "lint:css": "stylelint \"src/**/*.vue\" --fix"
},
```

``` .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: [
    'eslint:recommended',
    'google',
    'plugin:vue/recommended',
    '@vue/typescript',
  ],
  rules: {
    'max-len': [1, 100, 2],
    'arrow-body-style': ['error', 'always'],
    'no-console': 'error',
    'no-debugger': 'error',
    'require-jsdoc': 'off',
  },
  parserOptions: {
    parser: '@typescript-eslint/parser',
  },
  overrides: [
    {
      files: ['**/__tests__/*.{j,t}s?(x)'],
      env: {
        jest: true,
      },
    },
  ],
};
```

``` .stylelintrc.js
module.exports = {
  extends: 'stylelint-config-standard',
  plugins: ['stylelint-order', 'stylelint-scss'],
  rules: {
    'at-rule-no-unknown': null,
    'scss/at-rule-no-unknown': true,
    'order/properties-alphabetical-order': true,
    'no-empty-source': null,
    'rule-empty-line-before': [
      'always',
      {
        except: 'inside-block',
      },
    ],
  },
};
```