SCSSとstyled-componentsの勉強と比較のための環境を作った

[Make IT Advent Calendar 2019](https://qiita.com/advent-calendar/2019/make_it) 24日目の記事です。

今年も危うくクリぼっちになりかけましたが、サークルの仲間とクリパすることになりました。
皆様も良いクリスマスをお過ごしください。

今年は、マイCSSブーム到来というやつです。[5日目](https://qiita.com/haduki1208/items/de385e129ad47dcb9310)にもCSS関連の記事を投稿しました。
ゼミやインターンでSCSSを使っていますが、少し前からstyled-componentsに興味が湧いたので、勉強がてらどっちも書いてみようという旨です。

差分が発生する箇所について、コードを書いた感想を述べていくだけですので、実行環境だけ欲しい方は 環境 > リポジトリ(github) をクリックして `git clone` してください。

# 環境

- [リポジトリ(github)](https://github.com/haduki1208/learn-css)
  - 投稿時現在では、矢印アイコン・メニューボタン・クレジットカードコンポーネント(作り途中)が含まれています。
- 言語・ライブラリ
  - typescript(v3.7.2)
  - react(v16.12.0)
  - storybook/react(v5.2.8)
  - scss(v4.13.0)
  - styled-components(v4.4.1)
- 実行環境
  - macbook pro 2015 catalina
  - google chrome
- エディタ
  - visual studio code
- vscode plugin
  - vscode-styled-components
      - テンプレートリテラル内でcssの補完が効きます
  - color highlight(他にオススメあればご教授ください)
      - テンプレートリテラル内でカラーコードの背景に色が出なかったので導入しました

# 差分

## webpack.config.js

```js:SCSS
module.exports = {
  /* 一部省略 */
  module: {
    rules: [
      {
        test: /\.(ts|tsx)?$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env", "@babel/react"]
            }
          },
          "ts-loader"
        ]
      },
      {
        test: /\.css?$/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.scss?$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              url: false,
              sourceMap: true,
              importLoaders: 2,
              modules: true
            }
          },
          {
            loader: "postcss-loader",
            options: {
              sourceMap: true,
              plugins: [require("autoprefixer")({ grid: true })]
            }
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new TypedCssModulesPlugin({
      globPattern: "src/**/*.scss"
    })
  ],
  /* 一部省略 */
};
```

scssのために4つのloaderを通しています。おかげでconfigが縦に長い!
autoprefixerしか使っていないので良いですが、今後を考えるとpostcss.config.jsとして別ファイルにした方が良いですね。

[TypedCssModulesPlugin](https://github.com/dropbox/typed-css-modules-webpack-plugin) はscss保存時、自動でd.tsを生成します。dropbox製というのが好きです。

私は、フォルダをコンポーネント名にして、中にindex.tsxを作成する方法を使います。
これは、コンポーネントに関係する style.scss, style.d.ts, react custom hooksをまとめてフォルダ内に置けるので気に入っています。

```js:styled-components
module.exports = {
  /* 一部省略 */
  module: {
    rules: [
      {
        test: /\.(ts|tsx)?$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env", "@babel/react"],
              plugins: ["babel-plugin-styled-components"]
            }
          },
          "ts-loader"
        ]
      }
    ]
  },
  /* 一部省略 */
};
```

スッキリしました。
autoprefixer・TypedCssModulesPluginの役割は、styled-componentsが全て担ってくれます。
[babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components) について、[こちらの記事が参考になりました。](https://blog.yuhiisk.com/archive/2018/12/09/add-display-name-styled-components.html)

## reset.css

```jsx
// for SCSS
import 'reset-css';

// for styled-components
import React from 'react';
import { Reset } from 'styled-reset';

const App = () => (
  <>
    <Reset />
    <div>Hello world!</div>
  </>
);
```

SCSSでは [shannonmoeller/reset-css](https://github.com/shannonmoeller/reset-css) を使用します。
styled-componentsでは [zacanger/styled-reset](https://github.com/zacanger/styled-reset) を使用します。

## ソースコード比較(buttonコンポーネント)

<p class="codepen" data-height="500" data-theme-id="default" data-default-tab="css,result" data-user="haduki1208" data-slug-hash="wvBdbEP" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="menu button scss">
  <span>See the Pen <a href="https://codepen.io/haduki1208/pen/wvBdbEP">
  menu button scss</a> by haduki1208 (<a href="https://codepen.io/haduki1208">@haduki1208</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

マウスホバーでアニメーションするボタンです。
これをstyled-componentsで置き換えます。

<p class="codepen" data-height="500" data-theme-id="default" data-default-tab="js,result" data-user="haduki1208" data-slug-hash="QWwvRZr" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="menu button styled">
  <span>See the Pen <a href="https://codepen.io/haduki1208/pen/QWwvRZr">
  menu button styled</a> by haduki1208 (<a href="https://codepen.io/haduki1208">@haduki1208</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

scssがなくなったことでフォルダ内がスッキリしますが、scssの内容がtsxに移動するのでファイルが縦に長くなります。
私はvscodeのエディタを分割してtsxとscssを並べながらコードを書くので、辛さがあります。
↓こんな感じ
[![Image from Gyazo](https://i.gyazo.com/84c544b7cc0d822ab256eb0aedec81b9.png)](https://gyazo.com/84c544b7cc0d822ab256eb0aedec81b9)

解決策として、
1. atomic designを意識してコンポーネントを小さくしていく
2. style.tsx のようなファイルを用意してstyledの要素を宣言する
を考えました。基本的に1番の方法を実践していきたいと思います。

# おわりに

趣味で何かコーディングするとき、この[リポジトリ(github)](https://github.com/haduki1208/learn-css)を使っていこうかなと思っています。
storybookも始めて導入してみたのですが、どんなコンポーネントがあるか一通り見れるので便利です。

scss(css)で培ってきた技術がそのままstyled-componentsに活用できるため、
新規プロジェクトはstyled-componentsだったらいいなぁと思っています。