VSCodeへのStylelint導入をちゃんと理解する

VSCodeはビルドインの設定や拡張機能が豊富なおかげで、カスタマイズしていくとどの自動整形が働いているのか分かりづらくなってくると思います。
ゆえに「なんとなくそれっぽく整形が効いているけど、カスタマイズのやり方はわからない」という状態だったりするのではないでしょうか。筆者もそれっぽく整形が効けばいいかな程度だったこともありました。

今回手元のプロジェクトでStylelintにおける特定のルールの有効・無効をしっかりカスタマイズする必要がでたので、改めて設定にチャレンジしてみました。

※執筆中にStylelint14.0.0と拡張v1.0.3がリリースされ、一部の仕様が変更になりましたので、要所要所にて加筆しています。お試しになる際にはお気をつけてください。

<!-- ${toc} -->

## Stylelintとは

[List of rules | Stylelint](https://stylelint.io/user-guide/rules/list/)
[stylelintのルール簡単説明（v5.4.0）](https://gist.github.com/konitter/d86c16b13da4debf33555f8299270d3d)

「スタイルを記述中や保存する時にいい感じにエラーを出してくれたり自動整形してくれるツール」くらいの認識の方が多いと思いますが、認識としてはそんな感じでいいと思います。

### もともとは書式などの間違いを「チェック」するツール

現在ではStylelintにも自動整形機能は実装されていますが、その名前の通りもともとはLinterなので基本的にはチェックするツールであることは忘れないようにしましょう。
[ルールの一覧](https://stylelint.io/user-guide/rules/list/)を確認すればわかりますが、自動整形可能（Autofixable）なルールは半分程度です。
Autofixableではないルールは有効にしてもVSCode上の`Problems（問題）`パネルに表示されるだけとなります。

### もともとはCLI（Command Line Interface）

本来Stylelintは「さーてそろそろ書いたスタイルのチェックしておきますか！」っていうタイミングで下記のようなコマンドを実行し、

```
npx stylelint "**/*.css"
```

そしてチェックから出力されたエラーコードを元にソースコードをちまちまと修正していく、というようなイメージだったのではないかと思います。

しかし、エンジニアの性でしょうか、「保存時に都度チェックしたほうが良くね？直せるものは直しちゃった方が良くね？っていうか、IDEに組み込んじゃったほうが楽じゃね？」っていうみんなの発想から進化したんだと妄想しています。

### VSCode拡張で簡単に実行できる

ということで、Stylelint公式も、有志のエンジニアも、フォーマッター関連の拡張開発者も巻き込んで、現在のように「VSCodeでスタイルを書きながら、保存時に自動的にチェックが実行され、可能な場合自動的にフォーマットも行う」ことができるようになっています。

## インストール
### Stylelint公式のVSCode拡張をインストール

ベースになる拡張です。必須。

[stylelint - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)

### npmのstylelintをインストール

上記拡張はVSCodeとStylelintをつなぐ役割を果たすもののようです。なので、そのStylelintの本体のインストールになります。
~~必ずしも必要ではないようですが、拡張の説明文に以下のように記されています。~~

> If not in the global installed stylelint, the extension uses the stylelint embedded in the extension. (However, using stylelint embedded in the extension is not recommended.)
[stylelint - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)

~~この拡張の説明文ではglobalとなっていますが、npmのglobalである必要はありません。~~

---

※2021 / 11 追記

Stylelint拡張v1.xより必須になりました。
インストール先も`workspace`へのインストールが推奨となり、`global`はきっちり非推奨になりました。

> vscode-stylelint will depend on having a copy of Stylelint installed in the open workspace (recommended) or globally (not recommended)
[Stylelint - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint#stylelint-is-no-longer-bundled)

---

stylelintのGetting startedに従ってインストールしておきます。
[Getting started | Stylelint](https://stylelint.io/user-guide/get-started/)

```sh
npm install --save-dev stylelint stylelint-config-standard
```

#### Configとは

上記で２つ目にインストールしている`stylelint-config-standard`というのは、お勧め設定のようなものになります。
内容としてはこの様に説明がなされています。
> Extends stylelint-config-recommended.
> Turns on additional rules to enforce the common stylistic conventions found within a handful of CSS styleguides, including: The Idiomatic CSS Principles, Google's CSS Style Guide, Airbnb's Styleguide, and @mdo's Code Guide.
[stylelint/stylelint-config-standard: The standard shareable config for stylelint](https://github.com/stylelint/stylelint-config-standard)

この説明にある`stylelint-config-recommended`というのも公開されているので、追って説明を見てみると、
> It turns on all the possible errors rules within stylelint.
Use it as is or as a foundation for your own config.
[stylelint/stylelint-config-recommended: The recommended shareable config for stylelint](https://github.com/stylelint/stylelint-config-recommended)

と説明されています。が、まだ良くわかりませんので、内容を確認してみます。

```js
rules: {
	'at-rule-no-unknown': true,
	'block-no-empty': true,
	'color-no-invalid-hex': true,
	'comment-no-empty': true,
	'declaration-block-no-duplicate-custom-properties': true,
	'declaration-block-no-duplicate-properties': [
		true,
		{
			ignore: ['consecutive-duplicates-with-different-values'],
		},
	],
	'declaration-block-no-shorthand-property-overrides': true,
	'font-family-no-duplicate-names': true,
	'font-family-no-missing-generic-family-keyword': true,
	'function-calc-no-invalid': true,
	'function-calc-no-unspaced-operator': true,
	'function-linear-gradient-no-nonstandard-direction': true,
	'keyframe-declaration-no-important': true,
	'media-feature-name-no-unknown': true,
	'named-grid-areas-no-invalid': true,
	'no-descending-specificity': true,
	'no-duplicate-at-import-rules': true,
	'no-duplicate-selectors': true,
	'no-empty-source': true,
	'no-extra-semicolons': true,
	'no-invalid-double-slash-comments': true,
	'no-invalid-position-at-import-rule': true,
	'no-irregular-whitespace': true,
	'property-no-unknown': true,
	'selector-pseudo-class-no-unknown': true,
	'selector-pseudo-element-no-unknown': true,
	'selector-type-no-unknown': [
		true,
		{
			ignore: ['custom-elements'],
		},
	],
	'string-no-newline': true,
	'unit-no-unknown': true,
},
```
[stylelint-config-recommended/index.js at master · stylelint/stylelint-config-recommended](https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js)

なるほど。シンプルなルールが記載されていました。
一見たくさんのルールが設定されているように見えるかもしれませんが、一つずつ見ていくと多くの人が（ほぼ）無意識に行っているものだと思います。

前述のようにStylelint公式としてはこの`recommended`を拡張した`standard`（[stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard/blob/master/index.js)を使うことを推奨しているのでもっと盛り込んだ内容の設定になるということになります。

（個人的には命名が逆な気がしなくもないですが…）

#### これらのConfig設定は本当に必要？

**Stylelint単体では何も行いません。**

> No rules are turned on by default and there are no default values. You must explicitly configure each rule to turn it on.
[Configuration | Stylelint](https://stylelint.io/user-guide/configure/#rules)

なので、Stylelintを動作させるためには、上記のようなConfigを読み込むか、これから説明するような独自に必要なルールを記載した設定ファイルを作成しStylelintに読み込む必要があります。

プロジェクトの開発開始前であれば、プロジェクト規定として「スタイルの記述は`stylelint-config-standard`準拠とし、必要が出た部分をカスタマイズのうえ、設定ファイルで共有する」などとするのが一番楽だと思います。
すでに開発の進んだプロジェクトの場合には導入を慎重に行うべきで、今までLinterを使っていなかった場合、まとまったConfigを導入し自動整形を有効にすると、不要に思える差分を発生させる可能性があります。そのような場合はConfigを読み込まず一つずつルールを記述したり、プロジェクト全体まとめて整形してしまうタイミングを設ける方がいいかもしれません。

## 設定ファイルを用意する

Stylelintを動作させるには様々な手法がありますが、今回は「スタイルのチェック・自動整形にはStylelintのみを利用し保存時に自動で動作させる」という一番シンプルな手法を紹介します。他のLinterと組み合わせる手法などは発展型になると思いますしVSCodeの制御の基礎を触れるのでスタートとしてはベターだと思います。

### 基本は2ファイル

├.vscode
│└ settings.json //①
└ .stylelintrc //②

①の`settings.json`はVSCodeのUser設定（所謂グローバル設定）にしてしまうことも可能ですが、実際の案件ではプロジェクトごとに設定内容を変えることも多いのでWorkspace内の設定に留めることをお勧めします。そのためにこの`.vscode`ディレクトリ内に作成しておきます。

②の`.stylelintrc`に関しては先述したルールを記載するファイルになり、公式によると幾つかのルール管理の方法があり`package.json`に記述するほうが順位が高そうですが、バージョン管理などの観点からファイルを分けて管理することをお勧めします。
[Configuration | Stylelint](https://stylelint.io/user-guide/configure/)

#### .vscode/settings.jsonを作成・編集する

もしまだ、そのファイルが無い場合でも大丈夫です。
`COMMAND + SHIFT + p`にてCommand paletteを開き、`settings.json`と入力します。

そうすると3項目表示されますので、`Preferences: Open Workspace Settings(JSON)`を選択すると、ファイルがない場合でも自動的に作成されファイルが開きます。

![スクリーンショット 2021-09-13 12.21.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/3b63b00e-863b-4546-d8a0-b0113a6b79f1.png)


Stylelintのために必要な内容ですが、まずはvscode-stylelintのInstallationにてOptionalとなっている設定を見てみます。
[stylelint - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)

```json
"css.validate": false,
"less.validate": false,
"scss.validate": false
```
この様に書かれているので、このあたりを触るのが初めての方には少しわかりにくいかもしれませんが、ファイル全体ではこの様に記述することになります。他の記述が既に存在する場合、一番外の波括弧の中ならどこでもいいですが、わかりやすくまとめておきましょう。

```json
{
	// 中略
	"css.validate": false,
	"less.validate": false,
	"scss.validate": false
	// 中略
}
```
これはVSCode内蔵のlinterを動作させないための設定になります。
> To prevent both the editor built-in linters [css] [less] [scss]

この説明の続きにもありますが、Stylelintと内蔵のlinterが同時に働くと、VSCode上に2重でエラーが表示されます。今回はStylelintが綺麗に働くことを目指すので、指示通りこの設定を入れておきましょう。

これに続くその他の設定項目が[VSCode Stylelint公式](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)に記載がありますが、筆者の手元の設定ファイルは以下のように記述してみました。

 - .vscode/settings.json

```json
{
  "scss.validate": false,
  "[scss]": {
    "editor.formatOnSave": false,
    "editor.codeActionsOnSave": {
      "source.fixAll.stylelint": true
    },
  },
  "stylelint.configFile": "./.stylelintrc",
  "stylelint.validate" : ["css", "scss"]
}
```

これはSCSSのための設定のみとなります。（CSSやlessに対して設定が必要ならその分増やします。）
`"[SCSS]"`のブロックで、SCSSファイルに対しての設定を記述しています。
`"editor.formatOnSave"`の部分はバージョンアップで要らなくなっているかもしれませんが、確実に内蔵フォーマッタの働きを抑制するために保険としておいています。
`"editor.codeActionsOnSave"`部分が少し前に実装されたファイル保存時の動作を記述する部分となり、ここでは「stylelintに自動整形させる（`true`）」という設定になっています。
`"stylelint.validate" : ["css", "scss"]`の部分にて、stylelintによるvalidateを有効化しています。

#### .stylelintrcを作成・編集する

実際のStylelintのルールを記載しておくファイルになります。
Stylelintはこのファイルを読み込み、その内容に従ってエラー出力なり整形を行ってくれます。

複数の形式をサポートしており、`.stylelintrc`はJSONもしくはYAML形式になります。それ以外だと公式にあるような.jsファイルや.cjsファイルも可能です。
[Configuration | Stylelint](https://stylelint.io/user-guide/configure/)

またファイル名も自由に設定が可能で、独自の命名を行いたい場合は、前述の`settings.json`の`"stylelint.configFile"`にファイルへのパスを記述しておくと読み込まれるようになります。

```json
{
  "rules": {
    "block-no-empty": true,
    "no-duplicate-selectors": null,
    "number-leading-zero": "always"
  }
}
```

今回は基礎的なものになりますが、3つに限定してルールを設定しておきます。
- 空のブロックを許可しない
- 重複したセレクターを許可しない
- １未満の数値で頭の0を省略しない

ここで、true / false, null, stringと出てきましたが、どのような項目があるか、どのような値が設定できるかは公式で確認が可能です。
少し癖のあるプロパティ名になりますが、いくつか眺めてみるとどのように検索すればよいか分かってくると思います。
[List of rules | Stylelint](https://stylelint.io/user-guide/rules/list/)


## 実際に自動でチェック・修正が行われるか確認

Stylelintは基本的にVSCodeのプラグインが、node_modulesにインストールされているStylelint本体を利用して、設定ファイルに基づいたチェック・修正を行ってくれるものなので、例えばWebpackなどのタスクランナー・バンドラーなどとは関係なく動作します。

![スクリーンショット 2021-12-06 13.58.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/e8087f79-3fe7-cd5e-5040-0e84e3b034ee.png)

こちらのように、SCSSをタイプしているそばからエラーが表示されること。このファイルをセーブしたら、fixableなエラーが自動的に修正されること、を確認できればバッチリだということになります。（この例は多めにStylelintルールが設定されています）

一応基礎的なおさらいをしておくと、エラーの確認は以下の部分で可能です。

- ファイル名が赤くなり、エラー数が表示されている
- エディター内においてエラー箇所に赤い波線がひかれる
- その赤い波線にカーソルを合わせるとエラーが表示される
- VSCodeのProblemsパネルにリストで表示される
- ファイルツリー内の該当ファイルのファイル名が赤く表示される

などとなります。ふと気づいたときにエラーがいっぱいで修正が大変、なんてことにはならないように、エラーが出ていないか日頃からなんとなく確認・修正する癖をつけておくといいと思います。



## その他のVSCodeの設定

### Problemsパネル

Autofixableではないルールで違反した場合、ファイル一覧の`Explorer（エクスプローラー）`に赤く表示されますが、手動での修正が必要になるので、常に前述した`Problems`パネルも表示しておくようにしましょう。修正するためにも早道になります。

![スクリーンショット 2021-09-13 15.54.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/533568d7-249a-d3c0-2fb1-368b2af83f3b.png)


この例では`block-no-empty`のルールに違反しているので、エラーが報告されていますが、自動整形は行われません（そのままセーブできてしまう）。`Problems`パネル内の該当行をクリックすると、ファイルが開かれ該当部分がアクティブになります。

Problemsパネルは`メニューバーView（表示？） - Problems`から表示が可能です。

![スクリーンショット 2021-09-13 15.51.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/c7714523-d61e-cbaa-dcf7-38507bd4c301.png)

こちらにあるように、キーボードショートカットでも表示が可能です。

### プラスアルファ設定

前述の通りVSCodeにてStylelintを動作させるためには拡張機能を利用することになります。ベーシックなVSCodeの使い方としては、拡張機能は各々がインストールしていくことになりますが、そのプロジェクト（リポジトリ）において、「この拡張機能を使いませんか？」というような表示をする機能があります。

├.vscode
│├ **extensions.json** //③
│└ settings.json //①
└ .stylelintrc //②

この位置に`extensions.json`を配置する形になりますが、拡張の正式名称が必要になり面倒かつヒューマンエラーの可能性があるので、GUI的に設定を行います。

![スクリーンショット 2021-12-06 14.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/f8f7b2fe-9fda-3e40-3868-e3fa03fc73ab.png)

Extensions（拡張）パネルから`歯車アイコン`をクリック、`Add to Workspace Recommendations`をクリック
とすることでファイルが生成されます。
（ちなみに、逆に推奨から外す際もこのメニューからとなります）


- .vscode/extensions.json

```json
{
  "recommendations": [
    "stylelint.vscode-stylelint"
  ]
}

```

この設定が行われている＋まだその中の拡張（の一部）がインストールされていない、という状態の場合に、このようなダイアログが表示されるようになります。

![スクリーンショット 2021-12-06 14.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546514/bf910bf4-9858-a508-80a3-0ad1e3a46357.png)

これで、プロジェクトメンバーへの周知・共有事項が一つ減ることになります。