eslint-config-airbnb利用時にdevDependenciesのimportで怒られる時の対応

## 課題

[eslint-config-aibnb](https://www.npmjs.com/package/eslint-config-airbnb)を利用している場合に、テストコードなど、devDependenciesをimport（require）するコードが怒られる。

```text:例）テストコードでdevDependenciesに含まれているavaをimportしている場合
error  'ava' should be listed in the project's dependencies, not devDependencies  import/no-extraneous-dependencies
```

## 原因

eslint-config-airbnbに含まれている[eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import)の[no-extraneous-dependencies](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md)というルールが、eslint-config-airbnb-baseの中で下記のように設定されているのが原因。（eslint-config-airbnbのバージョンが、11.2.0の場合。）

```js
'import/no-extraneous-dependencies': ['error', {
  devDependencies: false, // devDependenciesのimportを禁止
  optionalDependencies: false,
}]
```

これはちょっと厳しすぎるので、テストコードなど一部のファイルだけでdevDependenciesのimportを許可したい。

## 対応策

eslint-config-airbnbのバージョンによって依存しているeslint-plugin-import、eslint-config-airbnb-baseのバージョンが違うので、対応が異なる。

### eslint-config-airbnbの11.1.0以前

eslint-plugin-importのバージョンが、v1.14.0以前の場合。

#### コメントで一時的に無効にする

少なければこの方法で良さそう。コメントで向こうにする場合、他のルールまでもみ消さないように、どのルールを無効にするか明記した方がよい。（[eslint-plugin-eslint-comments](https://www.npmjs.com/package/eslint-plugin-eslint-comments)を使うとそのあたりも制限できてよい:+1:）

```js:eslint-disable-lineコメント
import test from 'ava'; // eslint-disable-line import/no-extraneous-dependencies
```

```js:eslint-disable-next-lineコメント
// eslint-disable-next-line import/no-extraneous-dependencies
import test from 'ava';
```

#### test/.eslintrc.jsonを置く

テストコードを`test/`以下などソースコードと隔離されたディレクトリに置いている場合は、`test/.eslintrc.json`（拡張子はお好きなやつを使う）を置いて、プロジェクトルートにある`.eslintrc.json`のルールを上書きする。

```js:test/.eslintrc.js
module.exports = {
rules: {
...

'import/no-extraneous-dependencies': ['error', {
  devDependencies: true, // devDependenciesのimportを許可
  optionalDependencies: false,
}]

...
};
```

### eslint-config-airbnbの11.2.0

#### devDependenciesの読み込みを許可するパスをルールに書く

eslint-plugin-importのv1.14.0からno-extraneous-dependenciesにbool値だけでなく、devDependenciesの読み込みを許可するファイルパスを配列で渡すことができるようになったので、それを使う。

```js:.eslintrc.js
'import/no-extraneous-dependencies': ['error', {
  devDependencies: ['**/*.spec.js'], // *.spec.jsのdevDependenciesのimportを許可
  optionalDependencies: false,
}]
```

### eslint-config-airbnbの12.0.0以降

eslint-config-airbnb-baseのv8.0.0以降では、下記のように、testディレクトリ以下ではdevDependenciesの読み込みを許可するようになっている。（[この部分](https://github.com/airbnb/javascript/blob/eslint-config-airbnb-base-v10.0.1/packages/eslint-config-airbnb-base/rules/imports.js#L67-L73)）

```js:eslint-config-airbnbの記述
    // Forbid the use of extraneous packages
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
    // paths are treated both as absolute paths, and relative to process.cwd()
    'import/no-extraneous-dependencies': ['error', {
      devDependencies: ['spec/**', 'test/**', 'tests/**', '**/__tests__/**'],
      optionalDependencies: false,
    }],
```

なので、上記以外のパスの場合は自分でルールを上書きしてあげる必要がある

```js:例）*.spec.js内でdevDependenciesの読み込みを許可する場合
'import/no-extraneous-dependencies': ['error', {
  devDependencies: ['**/*.spec.js'],
  peerDependencies: false
}]
```

## おわり

eslint-config-airbnbってあまりアップデートしないけど、今回のno-extraneous-dependenciesのように改善されているルールもあるので、古くなっていたら最新にしましょう！！！

## おまけ

eslint-config-airbnb-baseのmasterの内容を見ると、no-extraneous-dependenciesのdevDependenciesに下記のファイルパスの指定が追加されており、だいたいのパターンはカバーされていそう。（[この部分](https://github.com/airbnb/javascript/blob/master/packages/eslint-config-airbnb-base/rules/imports.js#L67-L86)）

```js:eslint-config-airbnbの記述
    // Forbid the use of extraneous packages
    // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
    // paths are treated both as absolute paths, and relative to process.cwd()
    'import/no-extraneous-dependencies': ['error', {
      devDependencies: [
        'test/**', // tape, common npm pattern
        'tests/**', // also common npm pattern
        'spec/**', // mocha, rspec-like pattern
        '**/__tests__/**', // jest pattern
        'test.js', // repos with a single test file
        'test-*.js', // repos with multiple top-level test files
        '**/*.test.js', // tests where the extension denotes that it is a test
        '**/webpack.config.js', // webpack config
        '**/webpack.config.*.js', // webpack config
        '**/rollup.config.js', // rollup config
        '**/gulpfile.js', // gulp config
        '**/Gruntfile', // grunt config
      ],
      optionalDependencies: false,
    }],
```

これがpublishされれば、本記事で設定した内容は不要になりそうなので、早くpublishしてほしい。