GatsbyにTailwind CSSを導入する最短手順(CSS-in-JS)

この投稿では、GatsbyにTailwind CSSを導入する最も手軽な手順を紹介します。

本稿で紹介する手順を適用したGatsbyプロジェクトのソースコードはGitHubにありますので、完成形のコードを確認する場合はご覧ください: https://github.com/suin/gatsby-demo-tailwind-css-01

## この投稿で実現すること

大まかなスタイリングはTailwind CSSのユーティリティクラスを使い、Tailwind CSSがカバーできない細かいスタイリングは、素のCSS(CSS-in-JS)で対応できるようにします。

例えば、Tailwind CSSだけで完結するスタイリングは次のように書けるようになります:

```react
(
  <h1 tw="text-3xl font-bold py-2">タイトル</h1>
)
```

例えば、Tailwind CSSに素のCSSを加える場合は、次のように書けるようになります:

```react
(
  <pre css={[
    tw`p-4 bg-gray-900 text-white rounded`, // Tailwind CSS
    css`tab-size: 2;`, // 素のCSS (タブ文字幅を2文字に設定している)
  ]}>{'foo:\n\tbar:\n\t\tbuz: true'}</pre>
)
```

↓描画結果

<img width="433" alt="CleanShot 2020-06-04 at 09.26.09@2x.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/dd1dddf9-af10-cb1c-3441-5fcd2075d206.png">

## 扱わない技術

できるだけ最低限の手順にしたかったので、他の解説記事で扱っている以下の技術は扱いません。

* PostCSS
* emotion (CSS-in-JSライブラリ)
* styled-component (CSS-in-JSライブラリ)
* PurgeCSS
* SCSS

これらは後々知っておいたほうがいいと考えられますが、GatsbyでTailwind CSSを当座使う当たっては後回しにしても良いと考えました。本稿で説明する手順では、emotionについては内部的に使われますが、気にならない程度になってます。本稿はCSS-in-JSでスタイリングすることを目的にするのでSCSSは扱いません。

また、本稿ではtwin.macroというTailwind CSSをReactで扱うライブラリを使うため、その競合となる[tailwind.macro](https://github.com/bradlc/babel-plugin-tailwind-components)については扱いません。

## GatsbyにTailwind CSSを導入する手順

### パッケージにインストール

まず必要なパッケージをインストールします。

```
yarn add twin.macro @emotion/core @emotion/styled gatsby-plugin-emotion
```

twin.macroは、Tailwind CSSのユーティリティクラスをCSS-in-JSとして扱えるようにするライブラリです。なので、React上でTailwind CSSを使うには、`className`プロパティではなく、`tw`プロパティなどを使います。使い方の詳細は後述します。

tailwindcssパッケージはtwin.macroを入れれば入ってくるので、明示的に入れる必要はありません。

### Tailwind CSSの基本スタイルを当てる

gatsby-browser.jsに次の1行を追記して、Tailwind CSSの基本スタイルを当てます。

```gatsby-browser.js
import "tailwindcss/dist/base.css"
```

### emotionプラグインを有効にする

gatsby-config.jsに`gatsby-plugin-emotion`を追加して、CSS-in-JSが使えるようにします。

```gatsby-config.js
module.exports = {
  plugins: [`gatsby-plugin-emotion`],
}
```

### Tailwind CSSの設定ファイルを生成する

プロジェクトルートにTailwind CSSの設定ファイルtailwind.config.jsを作っておきます。中身は変更しなくて構いません。

```
npx tailwindcss init
```

上のコマンドを実行する次のファイルが生成されます:

```tailwind.config.js
module.exports = {
  purge: [],
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}
```

### Babelマクロの設定を追加する

Babelマクロの設定をpackage.jsonに追加して、twin.macroを使えるようにします。

```package.json
{
  "babelMacros": {
    "twin": {
      "config": "./tailwind.config.js",
      "preset": "emotion",
      "hasSuggestions": true,
      "debug": false
    }
  }
}
```

ちなみに、babel-plugin-macrosパッケージは別途インストールする必要はありません。twin.macroを入れると勝手に入るため。

### 作成・変更したファイルの確認

ここまでの手順で以下のファイルが作成・変更されたことを確認します。

```
.
├── gatsby-browser.js → Tailwind CSSの基本スタイルをimportしているか？
├── gatsby-config.js → emotionプラグインが有効になっているか？
├── package.json → Babelマクロの設定が追加されているか？
└── tailwind.config.js → Tailwind CSSの設定ファイルが生成されているか？
```

以上がGatsbyにTailwind CSSを導入する手順です。

## twin.macroをReactで使うには

twin.macroをReactで使う最もシンプルな書き方は`tw`プロパティにTailwind CSSのクラスを書いていく方法です:

```jsx

import "twin.macro"

const Title = ({ children }) => 
  <h1 tw="text-3xl font-bold py-2">{children}</h1>
```

上の書き方は、`tw`を使って更に簡潔に書くこともできます:

```jsx
import tw from "twin.macro"

const Title = tw.p`text-3xl font-bold py-2`
```

Tailwind CSSのクラスを使いつつ、素のスタイル(CSS-in-JS)を当てるには、`css`プロパティと`css`タグを使います:

```jsx
import tw, { css } from "twin.macro"

const Code = ({ children }) => (
  <pre css={[
    tw`p-4 bg-gray-900 text-white rounded`,
    css`tab-size: 2;`,
  ]}>{children}</pre>
)
```

条件に応じてスタイルを切り替えるには、`styled`を使います:

```jsx
import tw, { styled } from "twin.macro"

const Link = styled.a(({ small }) => [
  tw`text-white bg-black px-8 py-2 rounded`,
  small ? tw`text-sm` : tw`text-lg`,
])

const Links = () => (
  <>
    <Lin href="#">大きい文字のリンク</Link>
    <Link small href="#">小さい文字のリンク</Link>
  </>
)
```

以上のすべての使い方を組み合わせた例が以下になります:

```jsx:src/index.js
import React from "react"
import tw, { css, styled } from "twin.macro"

// Using `tw` prop:
const Title = ({ children }) => <h1 tw="text-3xl font-bold py-2">{children}</h1>

// Using `css` prop:
const Description = ({ children }) => (
  <p
    css={[
      tw`py-2 italic`,
      css`
        text-decoration: underline;
      `,
    ]}
  >
    {children}
  </p>
)

// Conditional styles:
const Link = styled.a(({ small }) => [
  tw`text-white bg-black px-8 py-2 rounded`,
  small ? tw`text-sm` : tw`text-lg`,
])

// Create and style new elements using tw
const Quote = tw.p`border-l-2 border-gray-400 text-gray-600 pl-4 ml-2 my-4`

const IndexPage = () => (
  <>
    <Title>Tailwind CSS + Gatsby demo</Title>
    <Description>
      This demo uses twin.macro and gatsby-plugin-emotion.
    </Description>
    <Quote>twin - Use Tailwind classes within css-in-js libraries</Quote>
    <Link small href="https://github.com/suin/gatsby-demo-tailwind-css-01">
      See GitHub
    </Link>
  </>
)

export default IndexPage
```

↓ 描画結果

![CleanShot 2020-06-04 at 10.23.01@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/cb878fb9-851d-0bff-92b2-5fc680cac526.png)

描画結果のHTMLがどうなるのか気になる方は、デモページをご覧ください。

デモページ: https://suin.github.io/gatsby-demo-tailwind-css-01/

ビルド後のpublicディレクトリの中身がどうなるか見てみたい方は、GitHubをご覧ください。

GitHub: https://github.com/suin/gatsby-demo-tailwind-css-01/tree/gh-pages