ゼロから見直す VSCode x ESLint x Stylelint x Prettier 環境構築 2023

VSCodeでESLintとPrettier、そしてStylelintの環境構築について改めて見直しました。

ここ最近までESLintやStylelintのフォーマット機能を使用しておりPrettierを使っていなかった残念なタイプの僕ですが、今やLintもフォーマットも分業制、餅は餅屋、というわけで、Prettierの使用の必要性を改めて理解し、今回の見直しに至った次第です。というわけで、見直したバージョンの環境構築の備忘録を兼ねて、残しておきます。

はじめに

「フォーマット?Prettier?別にESLintとかStylelintのフォーマット機能使えばいいんじゃん。Prettierをわざわざ使う理由は?カッコつけ!?」とかマジで思っていたし、いろんな文献読んでも腑に落ちませんでした。

というか、Prettierを使っていた時期もあったんですが、まぁ当時はまだESLintやStylelintとPrettierを同時に使う際の設定がややこしかったりしたのも理由のひとつです。(言いわけ)

しかし、今では完全に納得しているし、今回ゼロから設定を見直して、あらためて細かいことまで理解できて、ずーっとあったフォーマット周りのモヤモヤもすっかり晴れた感じです。

この辺の経緯については別記事にまとめたいと思います。

記事全体の流れ

今回はゼロからの見直しということで、細かいところまでしっかり理解を深める目的で、ひとつひとつを丁寧に、順序立てて進めていきます。そのため、結構まどろっこしいかもしれませんが、ご了承ください。

全体の流れはこんな感じになります。

  1. ESLintでJSをLint(解析)する
  2. PrettierでJSの整形をする
  3. StylelintでCSSをLintする
  4. PrettierでCSSの整形をする
  5. npm-scriptsで効率化する
  6. VSCodeでESLintを自動化する
  7. VSCodeでStylelintを自動化する
  8. VSCodeで整形を自動化する
  9. VSCodeで保存時にLintと整形を自動的に行う
  10. 全体のおさらい

VSCodeの設定もまっさらに

VSCodeの既存の設定が干渉しないよう、プラグインをすべて無効にし、設定ファイルも以下のように空にした状態からスタートしました。

// VSCodeの設定ファイル

{}

ESLintのLintを使うための設定

さて、ここから設定作業に入っていきます。最小構成でわかりやすくするため、ゼロから作っていきます。まずはプロジェクトを作成。

mkdir path/to/my-project
cd path/to/my-project
yarn init -y

ESLintをインストールして初期化します。

npx eslint --init

今回はこんな感じで最小構成にしてあります。ちなみにこの記事ではyarnを使っていますが、もちろんnpmでもOKです。

? How would you like to use ESLint? … 
  To check syntax only
❯ To check syntax and find problems
  To check syntax, find problems, and enforce code style

? What type of modules does your project use? … 
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

? Which framework does your project use? … 
  React
  Vue.js
❯ None of these

? Does your project use TypeScript? › No / Yes

? Where does your code run?
✔ Browser
✔ Node

? What format do you want your config file to be in? … 
❯ JavaScript
  YAML
  JSON

Local ESLint installation not found.
The config that you've selected requires the following dependencies:

eslint@latest
? Would you like to install them now? No / ❯ Yes

? Which package manager do you want to use? … 
  npm
❯ yarn
  pnpm

.eslintrc.js がこのように作成されます。

module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "rules": {
    }
}

extendseslint:recommended が指定されています。中身は ESLint Rules Reference で確認できます。ルール一覧のうち緑色のチェックマークがついているものが、eslint:recommended で使われているものです。

余談: Reactの場合

自分用。Reactの場合、こんな感じになります。

yarn add eslint-plugin-react
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
  ],
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
  },
    "rules": {
    "react/prop-types": "off", // ルールはお好みで
  },
};

余談終わり。

src/index.jsファイルを作成し、なんかビミョーにあやしいコードを書いてみます。インデントが統一されていなかったり、セミコロンが重複していたり、case の値が重複していたり、! が重複していたり、カッコの内側の空白もまちまちです。

const a = 1,
    one = 1,
two = true;

switch (a) {
    case 1:
        break;
    case 2:
        break;;
    case 1:
        break;
    default:
    break;
}



if (!!two) {
    console.log('two', two  )
}

ターミナルにコマンドを打ってlintしてみましょう。

yarn eslint src/index.js
/Users/xxxxxxx/my-project/src/index.js
   2:5   error  'one' is assigned a value but never used  no-unused-vars
   9:15  error  Unnecessary semicolon                     no-extra-semi
  10:5   error  Duplicate case label                      no-duplicate-case
  18:5   error  Redundant double negation                 no-extra-boolean-cast

✖ 4 problems (4 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

error Command failed with exit code 1.

Lintの結果がバッチリ表示されました( ¨̮ )

ESLintのエラーをコマンドで修正する

ESLint のエラーのうち --fix オプションを使うことで修正できるものもあります。上記の例では no-extra-semi(不要なセミコロンがある)と no-extra-boolean-cast(打ち消し表記が重複している)が自動修正できる部分です。

というわけで --fix をつけてやってみましょう。

yarn eslint src/index.js --fix
const a = 1,
    one = 1,
two = true;

switch (a) {
    case 1:
        break;
    case 2:
        break;
    case 1:
        break;
    default:
    break;
}



if (two) {
    console.log('two', two  )
}

自動修正できる部分が直っています( ¨̮ )(9行目、17行目)

さて、ここで重要なポイントをひとつ。修正されたのはあくまで構文的な部分であり、インデントやスペースなどの見た目の整形(フォーマット)は修正されていないことに注目してください。行末セミコロンもある部分とない部分があります。

実は、現在の eslint:recommended ではインデントやクォーテーション、スペースなどの整形に関する設定は一切入っていないんです。今後、見た目の整形(フォーマット)はPrettierと完全分業していく、というわけですね。

さて、お次はお待ちかねの整形(フォーマット)です。フォーマットの餅屋ことPrettierさんにお出ましいただきます。

まずはPrettierをインストール。

yarn add -D prettier

先ほどの src/index.js から、Lintで指摘されていた箇所を直しました。インデントやスペースなどの整形はしておらずそのままです。

const a = 1,
two = true;

switch (a) {
    case 1:
        break;
    case 2:
        break;
    default:
    break;
}



if (two) {
    console.log('two', two  )
}

整形を実行してみます。 --write で整形を上書き保存してくれます。

yarn prettier src/index.js --write

美しく整形されましたね( ¨̮ )

const a = 1,
  two = true;

switch (a) {
  case 1:
    break;
  case 2:
    break;
  default:
    break;
}

if (two) {
  console.log("two", two);
}

シングルクォーテーションがダブルクォーテーションに変わったりもしていますが、これは、Prettierのデフォルト設定に従って整形されているためです。この設定は、下記のように変更できます。

Prettierのオプション設定

Prettierの設定ファイル .prettierrc.json をプロジェクトフォルダ直下に作成します。

必要に応じて設定を記述しましょう。こちらは設定の一例です。

{
  "semi": true,
  "trailingComma": "all",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2
}

設定の詳細は公式サイトをご覧ください。

また、意図しないファイルの整形をしないよう除外ファイルも設定しておきましょう。

.prettierignore ファイルに除外内容を書いておきます。

dist/

ちなみに、下記はデフォルトで除外されているようです。

**/.git
**/.svn
**/.hg
**/node_modules

eslint-config-prettierはもう使わない

かつて、ESLintとPrettierを同時に使いたい場合に便利だった eslint-config-prettier というプラグインがあります。EslintとPrettierどちらにもあるルール、たとえばインデント数などが競合する問題を解決してくれる役割がありました。

しかし、現在のESLint x Prettierではこの競合は起こらないようにアップデートされており、必要がなくなりました。

また、もうひとつのメリットとして、PrettierをESLintの機能として合体して使えたので、--fix コマンドでLintするだけで整形も同時に賄ってくれていたのですが、今後はこのプラグインを使わず、シンプルにLintと整形を別々に行うスタイルになります。

とはいっても、npm scriptsの活用や後述のVSCodeとの連携で自動化することで、実質的な作業コストは変わりません。

その辺は記事の後半のほうでまとめて解説をしています。

StylelintのLintを使うための設定

さて、JSは一段落し、お次はCSSです。まずはStylelintと基本となる設定ファイルをインストールします。

yarn add --dev stylelint stylelint-config-standard

Stylelintの設定ファイル .stylelintrc.js を作成し、下記を記述します。

{ "extends": ["stylelint-config-standard"] }

src/style.css を作成し、なんかビミョーなコードを書いておきます。

.fuga   {
  font-size: 1.5rem;
    color: orange;
  background-color : #f8f8fb ;
  font-size: 1.25rem;
  }


.piyo:after {
  margin: 10px 20px 30px  20px ;
}

Stylelintをかけてみます。

yarn stylelint src/index.js
src/style.css
  5:3  ✖  Unexpected duplicate "font-size"                        declaration-block-no-duplicate-properties
  9:6  ✖  Expected double colon pseudo-element notation           selector-pseudo-element-colon-notation
 10:3  ✖  Expected "10px 20px 30px  20px" to be "10px 20px 30px"  shorthand-property-no-redundant-values

3 problems (3 errors, 0 warnings)

error Command failed with exit code 2.

3つの問題が指摘されました。というわけで無事CSSのLintを実行できるようになりました。

lint部分の自動修正を行うには --fix オプションを使います。

yarn stylelint src/style.css --fix

構文の修正をしてくれました。しかし、こちらもまたインデントなど見た目の整形に関する部分は一切考慮されていません。修正されたのは、あくまで構文の表記法についてのみです。

.fuga   {
    color: orange;
  background-color : #f8f8fb ;
  font-size: 1.25rem;
  }


.piyo::after {
  margin: 10px 20px 30px;
}

PrettierでCSSを整形するための設定

というわけで、同じようにPrettierを使って整形します。

yarn prettier src/style.css --write

美しく整形されました( ¨̮ )

.fuga {
  color: orange;
  background-color: #f8f8fb;
  font-size: 1.25rem;
}

.piyo::after {
  margin: 10px 20px 30px;
}

stylelint-prettierはもう使わない

stylelint-prettierは、StylelintとPrettierを連携させるためのライブラリですが、eslint-config-prettier 同様、こちらももう使う必要はありません。Stylelintも整形(フォーマット)に関する一切をPrettierなどのフォーマッタに完全分業を宣言したためです。ESLint同様、今後はStylelintも構文チェックと整形はそれぞれ別々に行います。

Stylelintのおすすめライブラリ2つ

これはあくまで個人的なおすすめですが、以下の2つのライブラリが便利です。いずれも、可読性、保守性、レビューの効率化などに役立ちます。

stylelint-declaration-block-no-ignored-properties

特定のCSSプロパティが他のプロパティによって無視される可能性がある場合に警告を出します。このプラグインがチェックするのは、一緒に使われた場合に一方のプロパティがもう一方に影響を与えるようなプロパティの組み合わせです。

たとえば、下のサンプルのように display: inline の場合は width が無視されてしまうので、書く必要がありません。こういった場合に警告が出ます。

.example {
  display: inline;
  width: 100px; /* 効かない */
  margin: 10px;
}

下記の手順でインストール・設定します。

yarn add -D stylelint-declaration-block-no-ignored-properties

.stylelintrc.json に下記を追加します。

{
  "plugins": ["stylelint-declaration-block-no-ignored-properties"],
  "rules": {
    "plugin/declaration-block-no-ignored-properties": true
  }
}

stylelint-config-resess-order

もうひとつは、CSSプロパティを特定の順序に基づいて並べ替えてくれるこちらのプラグイン。

これはRECESS(Twitterが開発したCSSの品質をチェックするツール)のプロパティ順序に基づいています。具体的には、関連するプロパティが一緒になるように、また特定の種類のプロパティ(例:位置やボックスモデルに関するプロパティ)が他より先にくるようにプロパティを整理します。

下記の手順でインストール・設定します。

yarn add -D stylelint-config-recess-order

.stylelintrc.json に下記を追記します。

{
  "extends": ["stylelint-config-recess-order"]
}

ここまでのを統合した .stylelintrc.json はこんな感じになっています。

{ 
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-recess-order"
  ],
  "plugins": ["stylelint-declaration-block-no-ignored-properties"],
  "rules": {
    "plugin/declaration-block-no-ignored-properties": true
  }
}

npm-scriptsで作業を効率化する

これまでは、説明上手動で逐一コマンド入力してきましたが、実作業でこれやっていては日が暮れてしまいますね。というわけで npm-scripts で効率化していきましょう。

これは一例ですが、package.json に以下のコマンドを記述します。

{
  "scripts": {
    "lint:js": "yarn eslint --fix 'src/**/*.{js,jsx}'",
    "lint:css": "yarn stylelint --fix 'src/**/*.css'",
    "lint": "yarn lint:js & yarn lint:css",
    "format": "yarn prettier --write 'src/**/*'",
    "fix": "yarn lint; yarn format"
  }
}

npm-scriptsの使い方についてはここでは割愛しますが、たとえば yarn fix コマンドで指定したすべてのファイルをLint、かつフォーマットできます。

VSCodeでESLint, Stylelintを自動化する

お次は、Lintの自動化。まずはESLintの自動化から行ってみましょう。

ESLintを自動化する

VSCode ESLintプラグイン をインストールして有効化します。

こちらは、リアルタイムにファイルを監視し、ESLintを自動的に表示してくれたり、保存時にFixを実行できるようにしたりしてくれる、イケプラグインです。

有効化するだけで、コマンドを実行しなくても自動的にLint結果を表示してくれます。便利!

次は、ファイルを保存したときにLintのFixが自動的に実行されるようにします。

VSCodeの setting.json に下記を追記します。

  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }

たったこれだけで、保存時にLintのFixを勝手にやってくれるようになりました( ¨̮ ) ただし、これはあくまで構文チェックの部分のみ。Prettierによる整形はまた別の設定が必要です。

Stylelint を自動化する

VSCode Stylelintプラグイン をインストールして有効化します。

こちらは、リアルタイムにファイルを監視し、Stylelintを自動的に表示してくれたり、保存時にFixを実行できるようにしたりしてくれる、イケプラグインその2です。

有効化すると、コマンドを実行しなくても自動的にLint結果を表示してくれます。便利!

次は、ファイルを保存したときにLintのFixが自動的に実行されるようにします。

VSCodeの setting.json に下記を追記します。

  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true
  }

たったこれだけで、保存時にLintのFixを勝手にやってくれるようになりました( ¨̮ ) ただし、何度でも言いますが、これはあくまで構文チェックの部分のみ。Prettierによる整形はまた別の設定が必要です。

VSCodeでPrettierによるフォーマットを自動化する

お次は、Prettierによるフォーマットの自動化です。

VSCode Prettierプラグインをインストールし有効化します。

こちらは、VSCodeのフォーマット機能でPrettierを使えるようにしてくれるイケプラグインその3となります。

VSCodeにはあらかじめHTMLやCSSなどのフォーマッタが搭載されていますが、それらに代わってPrettierを使うために必要なプラグイン、というあんばいです。

VSCode全体に設定する場合

言語を問わずPrettierで自動フォーマットを実現したい場合は、setting.json に下記を追記します。

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true
}

“editor.defaultFormatter”: “esbenp.prettier-vscode”
VSCodeのデフォルトのフォーマッタとしてPrettierを指定

“editor.formatOnSave”: true
保存時にフォーマットを実行

たったこれだけで、Prettierが対応する形式のファイルを保存するときに自動フォーマットしてくれるようになります( ¨̮ )

JavaScriptのみ、CSSのみなどファイル形式を限定して設定する

ファイル形式を限定する場合はこんな感じにします。全体設定と併記した場合は、ファイル形式を限定したこちらの設定が優先されます。

{
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "[css]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  }
}

さて、ここまでで設定は完了です!保存時にLintとフォーマットが自動的に実行できるようになりました!ニンニン( ¨̮ )

全体のおさらい

設定ファイルのうち .eslintrc.js だけJSONじゃないのは特に意味はありません。JSONに変更してもらっても大丈夫です。

package.json

{
  "name": "my-project",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "lint:js": "yarn eslint --fix 'src/**/*.{js,jsx}'",
    "lint:css": "yarn stylelint --fix 'src/**/*.css'",
    "lint": "yarn lint:js & yarn lint:css",
    "format": "yarn prettier --write 'src/**/*'",
    "fix": "yarn lint; yarn format"
  },
  "devDependencies": {
    "eslint": "^8.48.0",
    "prettier": "3.0.3",
    "stylelint": "^15.10.3",
    "stylelint-config-recess-order": "^4.3.0",
    "stylelint-config-standard": "^34.0.0",
    "stylelint-declaration-block-no-ignored-properties": "^2.7.0"
  }
}

.eslintrc.js

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: "eslint:recommended",
  overrides: [],
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
  },
  rules: {},
};

.stylelintrc.json

{ 
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-recess-order"
  ],
  "plugins": ["stylelint-declaration-block-no-ignored-properties"],
  "rules": {
    "plugin/declaration-block-no-ignored-properties": true
  }
}

VSCodeの設定ファイル

{
  // 保存時にアクションを実行する
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,  // 保存時にESLintのFixを実行
    "source.fixAll.stylelint": true // 保存時にStylelintのFixを実行
  },
  // VSCode全体に
  "editor.defaultFormatter": "esbenp.prettier-vscode", // デフォルトフォーマッタにPrettierを指定
  "editor.formatOnSave": true, // 保存時にフォーマットを実行
  // JavaScriptのみに設定
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  // CSSのみに設定
  "[css]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  }
}

.prettierrc.json

お好きなようにどうぞ( ¨̮ ) 何も書かなくても(このファイルなしでも)いい感じかと思います。

{
  "singleQuote": true,
  "printWidth": 90
}

.prettierignore

環境に合わせて変更してください。

dist/

まとめ

最近まではESLintのフォーマット機能、Stylelintのフォーマット機能、HTMLその他はまた別で…とやっていたところを、フォーマットをPrettierに一元化することで設定ファイルもシンプルになり、構築も楽になりました。

VSCodeの設定も、ゼロから考えていくことで自動Lint & 自動フォーマットに必要な最小設定をあぶり出すことができました。

というわけで、今さらではありますが今後はこのスタイルでやっていこうと思います。同じことで悩んでいる方へ、少しでも参考になれば嬉しいです。それではよきVSCode生活を!