styled-components の変数名の命名を縛る ESLint Plugin を作った


メリークリスマス。

この記事は、[第二のドワンゴ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/dwango2) の25日目の記事です。

内定者アルバイトのまっきーです。 ドワンゴ第一アドベントで [ポエム](http://tonkatu05.hatenablog.com/entry/2019/12/19/123943) を書いたので今度は技術的な話をしようと思います。

ずばり styled-components の変数名の命名を縛る ESLint Plugin を作ったので紹介します。
(仕事関係ありません)

# 概要

その名も [eslint-plugin-styled-components-varname](https://github.com/macinjoke/eslint-plugin-styled-components-varname) 。

簡単に言うと、デフォルトの設定でこんな感じです。

良いとされるコード

```javascript
const _TitleDiv = styled.div`
  height: 32px;
`

const $FooComponent = styled(FooComponent)`
  display: flex;
`
```

ダメなコード

```javascript
const StyledTitleDiv = styled.div`
  height: 32px;
`

const StyledFooComponent = styled(FooComponent)`
  display: flex;
`
```

要はありがちな命名である `Styled` とかの代わりに、`_` とか `$` とか簡単なprefix をつけて見やすくしようという方針です。

`styled.div` のような通常のスタイルと、 `styled(FooComponent)` のような既存コンポーネントにCSSをオーバーライドするタイプのもの(以後、拡張スタイルと呼ぶ)で別々のprefix ( `_` と `$` )をつけているのもポイントです。これにより、コンポーネントの命名を見るだけで、どのようなコンポーネントか見分けやすくなります。

例えば以下の例だと `$FooPanel` が `FooPanel` コンポーネントを拡張スタイルしたものだとひと目でわかります。

```javascript
const App = () => {
  return (
    <_RootDiv>
      <_TitleDiv>foo title</_TitleDiv>
      <$FooPanel>
        <div>bar content</div>
      </$FooPanel>
    </_RootDiv>
  )
}
```

このルールの利点は以下のようなものです。

- jsx上で、通常のスタイルと、拡張スタイルの見分けやすい
- 命名にかけるコストが減る
- 命名が短くなる

# 詳しく命名規則を考察
まだ個人開発でしかこれを使ってないので、本当にこのルールを適用すれば良い感じの開発体験になるかはわかりません。みなさんに使っていただいて感想を聞きたいです。

想定される懸念点をここで議論したいと思います。


## `Div = styled.div` とかで良くね？
確かに、 `StyledDiv` にしなくても、単に `Div` にするという手もあると思います。 しかしそうすると、 `List = styled.ul` などは、jsx上で通常のスタイルなのか拡張スタイルなのか見分けがつきにくいというデメリットがあります。

## 適切な命名すれば良くね？ `RootDiv = styled.div` とか、 `CommentList = styled.ul` とか。
これも、jsx上で通常のスタイルなのか拡張スタイルなのか見分けがつきにくいというデメリットがあると思います。
また命名を一生懸命考えるより、 `_List = styled.ul` にしたほうが、これは 「ul(もしくはol) タグにスタイルをつけてるだけのものだな」と分かるという利点もあります。styled-components の変数名は export されるものではないので命名コストをかける必要性は低めです。

また、 [styled-components のドキュメント](https://www.styled-components.com/docs/basics) に、 以下のようなサンプルコードがあります。

```javascript
const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;
```

このように `TomatoButton` という命名をすることでjsx上で、「これはトマト色のボタンなんだなー」とわかるでしょうが、それは重要なことでしょうか？
`$Button = styled(Button)` としたほうが、 「これはButtonコンポーネントを拡張スタイルしたものだ」とわかったほうが良い気がします。

## その考え方だと同じタグやコンポーネントを複数使うとき、命名かぶるじゃん。どうすんの。

例えばこんなとき

```javascript
const TomatoButton = styled(Button)`
  color: tomato;
`;
const BlackButton = styled(Button)`
  color: black;
`;

const jsx = (
  <div>
    <TomatoButton>yes</TomatoButton>
    <BlackButton>no</BlackButton>
  </div>
)
```

これだと `$Button` って命名できないよねというお話。
しかし、 **こんな場面は非常に少ない** と思います。こういったことをしたい場合は普通は props を渡す方式でスタイルを変えることが殆どです。

もちろん、こういうのはままあるでしょう。

```javascript
const jsx = (
  <RootDiv>
    <h1>見出し</h1>
    <ContentDiv></ContentDiv>
  </RootDiv>
)
```

こういうときは `_RootDiv` , `_ContentDiv` とすれば良いと思います。複数同じタグが出てきたら `_Div` ではなく `_FooDiv` にする、という方針が良さそうです。
ここらへんの細かい命名規則は厳密に守る必要もなく、また、自然とそうなるものだと思います。
何度も言っていますが、 この場合、`_` がついていることによって通常のスタイルなのか拡張スタイルなのか見分けがつきやすいというメリットがあります。

# 技術的な話

この eslint-plugin をどうやって作ったかという話をすると、まあそんな難しいことをしていないのですが、話したいことがわりと多いので気が向いたら別記事にして上げようと思います。 (主に autofix に失敗した話...w)。

また、prefix の `_` や `$` を変えたり、suffix や正規表現で縛るオプションもつけられる設計をしているので詳しくは [README.md](https://github.com/macinjoke/eslint-plugin-styled-components-varname) を読んでください

# まとめ
styled-components の変数名の命名を縛る ESLint Plugin を作りました。
自分もまだ少ししか使ってないですが、今の所使いやすいです。
皆さんが使ってみた感想を聞きたいです。気軽にどうぞ。
使わなくても議論はコメント欄やTwitterにどうぞ。
issue, プルリク歓迎です。気に入ったらスターよろしくおねがいします。

ではクリスマスなので今から男だけでスノーボードに行ってきます。