Nuxt開発におけるTailwindcssをv1系からv2系にアップグレードして解決した課題やそのメリット

# はじめに
株式会社じげんのユウです。
現在はチームリーダー兼フロントエンドエンジニアで不動産サービススモッカの開発を担当しております。
この度アドベントカレンダー１日目を担当することになりました。どうぞよろしくお願いします。

今回はNuxtのTailwindcssのモジュール、[@nuxtjs/tailwindcss](https://github.com/nuxt-community/tailwindcss-module)をバージョンに伴い、Tailwindcssをv1系からv2系にアップグレードすることで解決した問題とバージョンアップによるメリットを紹介します。

# 以下に当てはまる方に向けた記事です
1. nuxtjs/tailwindcssのv3.1以前を使ってる方。（v3.1以降を使ってるなら本記事の問題が起きないかもしれません）
1. nuxtjs/tailwindcssの初心者でどうやってバージョンアップすれば良いのかわからない方
1. Tailwincssのユーティリティークラスはなぜか本番環境では効かない悩みがある方。
1. 開発環境のビルド時間を短縮したい方。


# 開発環境の前提
すでに以下の環境で開発している前提
- nuxt v2.15以上
- nuxtjs/tailwindcss v3.1以下
- nuxt.config.jsには `srcDir` が設定されてる

もしnuxtjs/tailwindcssを使ったことない方なら、[公式のガイド](https://tailwindcss.nuxtjs.org/setup)通りインストールすれば今回紹介する問題は起きないはずです。

# どういう問題が起きてるのか？

### DOM要素のclassにtailindcssのクラスをそのまま書くと、開発環境ではスタイルが当たるのですが、本番環境ではスタイルが当たらないです。

まず問題を再現してみます。下記のコードはpタグにTailwindcssのユーティリティークラスをそのまま書いてます。

```js
<template>
  <div>
    <p class="text-xl text-red-600 p-10 m-10 font-bold">テスト用の文字列</p>
  <div>
<template>
```

開発環境を立ち上げて結果を確認します。

![1. 開発環境ではtailwindのクラスは当たる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/540b6f35-386c-c1b4-ed8d-673d687b1bcf.png)

chrome dev toolからスタイルを確認してみます。

![2. dev toolで当たってるクラスを確認する.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/c4a722f3-5174-ed42-202b-54e2de68a5e5.png)

スタイルはちゃんと当たってますね。

次にローカルでproduction buildして、再度確認してみます。

![3. productionではdom要素で直に書くtailwindcssが当たらない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/b74062bd-7857-7ba4-5383-816126edd317.png)

残念なことに...Tailwindcssのスタイルは当たらなかったです。

ではこの問題を解決しましょう！

# 原因＆解決方法を調査

これを解決するために色々と調べました。本番環境でTailwindcssが当たらない事例はいくつもの記事はありますが、どのケースも微妙に違うので、結局nuxt/tailwindの公式githubでissueを探すことに。

<font color="red">**githubでissueを漁ることが割と大事なのでネット記事でググっても解決策を見つからなかったら腹を括って公式githubにダイブしましょう**</font>

同じ事例のIssueが見つかりました！

[Some styles are not applied in production mode with "srcDir" nuxt.config.js option.](https://github.com/nuxt-community/tailwindcss-module/issues/114)

issueのタイトルはまさに現状環境の設定と同じでした。nuxt configファイルには srcDirを定義していて、nuxtのファイルを置くディレクトリを設定するプロパティです。
それが設定されると、本番ではsrcDirの値をうまく取れず、TailwindcssのPurge機能（ソースコード上に使われてるクラスを判断して、該当クラスだけ注入するプロセス）がうまく行われないから今回の問題を起きるわけです。

解決方法に関しては簡単です、公式ではすでにこのissueを修正してリリースしているので
nuxt/tailwindcssをバージョンアップするだけで解決できます。

公式の修正PR:
[tailwindcss-module: feat(purge): handle custom srcDir and support TS](https://github.com/nuxt-community/tailwindcss-module/pull/170)

公式のリリースノート: 上記のPRはv3.1にてリリースされてることを確認できます。
[Release Note](https://tailwindcss.nuxtjs.org/releases/#v3.1.0)

[公式の修正後のコメント](https://github.com/nuxt-community/tailwindcss-module/issues/114#issuecomment-698885369)

<font color="red">**公式コメントからの注意点としては、バージョンアップ後に下記の２点のいずれかを対応すれば解決とのことです。**</font>

1. `tailwind.config.js`ファイルを `srcDir` に定義されてるディレクトリに入れる。
2. `nuxt.config.js` ファイルに configPath: '~~/tailwind.config.js' を設定する必要があります。下記みたいに。

```js
// nuxt.config.js
export default {
  tailwindcss: {
    configPath: '~/config/tailwind.js'
  }
}
```

今回はもともと`tailwind.config.js` はすでに `srcDir` に定義されてるディレクトリに入れてるので、2の設定を追加しなくて解決できました。

ではアップグレードの手順から行きましょう。

# いざ、アップグレード

## まず現状のバージョンを確認する
バージョンを確認する方法はふたつあります

- 方法１．yarnコマンドで確認する

```terminal
yarn list --pattern @nuxtjs/tailwindcss
```

これを叩けばこんな感じに現在インストールされているバージョンが表示されます。

```terminal
yarn list v1.22.5
└─ @nuxtjs/tailwindcss@2.1.x
```
- 方法2. package.jsonの`devDependencies`を確認

```js
// package.json
"devDependencies": {
    "@nuxtjs/tailwindcss": "^2.1.x",
}
```

上記の方法でnuxt/tailwindcssのバージョンを確認できましたが、このバージョンはTailwindcssのどのバージョンに依存してるのかを確認したい場合は `yarn.lock` ファイルの `dependencies` を確認すればわかります。

```js
// yarn.lock
"@nuxtjs/tailwindcss@^2.1.0":
  version "2.1.x"
  resolved "https://registry.yarnpkg.com/@nuxtjs/tailwindcss/-/tailwindcss-2.1.1.tgz#7120a269b5a43d4a9d60947f7f734458cf86c180"
  integrity sha512-9DC7Adds1AKvxMbfW0Jd2EPpDUh3pVVE4wwiuJ45CiwOcz9EIU3Lc02h+bjnb1QFf07ZxJVO2xkN00IwQEFp8w==
  dependencies:
    consola "^2.14.x"
    fs-extra "^9.0.x"
    tailwindcss "^1.6.x"
```

`dependencies` のところは `tailwindcss` の1.6系に依存してますね。（記事上ではマイナーバージョンを隠しております）

## 次はアップグレードする

バージョンアップする前にまず確認してほしいのはnuxtのバージョンです。

[公式サイト](https://tailwindcss.nuxtjs.org/setup)にも書いた通りnuxtは最低でも2.15.3以上じゃないとだめらしいので、それ以下の場合はアップグレードしましょう。


ではアップグレードしていきます。

まず`package.json`の`nuxtjs/tailwindcss`のバージョンを変更。

今回は4.2系にしてます。

```js
// package.json
"devDependencies": {
    "@nuxtjs/tailwindcss": "^4.2.0",
}
```

あとは下記コマンドを叩けばアップグレードできます。

```terminal
yarn upgrade @nuxtjs/tailwindcss 
```

終わった後に再度下記コマンドでバージョン確認

```terminal
yarn list --pattern @nuxtjs/tailwindcss
```
```terminal
yarn list v1.22.5
└─ @nuxtjs/tailwindcss@4.2.x
```

ちゃんとアップグレードされました。

## 最後はバージョンアップ後の確認

無事にバージョンアップしたところでまずはローカルでビルドして動作確認してみます。

そしたら下記みたいにたくさんエラーが出てきました…

![バージョンアップ後のエラー_flex_no_wrapのエラー(投稿用).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/eb2bf889-200c-1410-9ec6-c17dd239ad9c.png)
![バージョンアップ後のエラー_whitespace_no_wrap(投稿用).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/a11d91d8-c3a3-73b3-4750-6fc1fade6929.png)
![バージョンアップ後のエラー_text-orange-500(投稿用).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/82dfbfb9-41d5-6cd4-09ba-eb2d203dac9c.png)


## アップグレード後のエラー対応

まず最初の２件のエラーを確認すると、`whitespace-no-wrap` と `flex-no-wrap` が存在しないと…公式サイトのv1 → v2に移行する説明にも書いてあった通り、いくつかのユーティリティークラス名は改名されていました。

![改名されたクラス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/106a85a2-6c4b-7c43-5f5a-d015d64e57b4.png)

なので合わせて修正すれば解消できます。

最後のエラーは `text-orange-500` は存在しないエラーですが、これはTailwindcssのv1ではあったカラークラスですが、v2ではorangeはデフォルトカラーから外されたので、tailwind configファイルにカスタマイズカラーとして設定する必要はあります。

[公式サイトの対策](https://tailwindcss.com/docs/customizing-colors#color-palette-reference)

v1と同じユーティリティークラスを使いたかったら下記みたいに適宜に設定すれば使えます。

```js
// tailwind.config.js
const colors = require('tailwindcss/colors')

module.exports = {
  theme: {
    colors: {
      // Build your palette here
      transparent: 'transparent',
      current: 'currentColor',
      // orange色を追加する
      orange: colors.orange,
    }
  }
}
```

これでエラーをすべて解消しました。
再度ビルド試して、完了後に結果を確認する。


![8. tailwindアップデート後のproduction環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/15bcf730-2f0c-67d7-a0fb-819d8bc830d6.png)

念の為 `NODE_ENV`も画面上に出力してみました。production環境でもちゃんとスタイルが当たってることを確認できました👍

# ついでに解決したい課題: CSSクラスを入れ子の記法で書いたらうまくCSS化されない問題。

これはtailwindのバージョンとか関係なく、nuxt/tailwindcssの初期の設定では下記コードのスタイルクラスはうまくCSS化できなかったです。

```js
<template>
  <div>
    <p class="text-xl text-red-600 p-10 m-10 font-bold">テスト用の文字列</p>
    <div class="wrapper">
      <p class="wrapper-text">テスト用の文字列</p>
      <p>テスト用の文字列</p>
      <a :href="`https://google.com/`">テスト用のリンク</a>
      <div class="innter">
        <p class="text-xl text-red-600 p-10 m-10 font-bold">テスト用の文字列</p>
        <p class="text-xl text-red-600 p-10 m-10 font-bold">テスト用の文字列</p>
        <p class="text-xl text-red-600 p-10 m-10 font-bold">テスト用の文字列</p>
        <a :href="`https://google.com/`">テスト用のリンク</a>
      </div>
    </div>
  </div>
</template>

<style lang="postcss" scoped>
.wrapper {
  @apply w-full bg-gray-500;
  .wrapper-text {
    @apply text-green-300 text-2xl p-10 font-bold;
  }
  p {
    @apply text-5xl;
  }
  a {
    @apply inline-block border border-base-gray text-secondary p-8px bg-white m-md;
    &:hover {
      @apply bg-yellow;
    }
  }
  .innter {
    a {
      &:hover {
        @apply bg-orange-base;
      }
    }
  }
}
.innter {
  @apply w-1/2 m-auto bg-red-200;
}
</style>
```

効かないスタイルを説明します。主に入れ子のスタイルが効かなくなります。

```js
.wrapper {
  // wrapper-textは効かない
  .wrapper-text {
    @apply text-green-300 text-2xl p-10 font-bold;
  }
   // aタグのスタイルもhover時のスタイルも効かない
  a {
    @apply inline-block border border-base-gray text-secondary p-8px bg-white m-md;
    &:hover {
      @apply bg-yellow;
    }
  }
  .innter {
  // aタグのhover時スタイルは効かない
    a {
      &:hover {
        @apply bg-orange-base;
      }
    }
  }
}
```

下記画像の赤い枠は効かないところです。

![入れ子の記法が効かない問題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/7406d455-59c3-24c9-2908-f075a70ca1b9.png)

dev toolで確認した結果はこれです。入れ子のスタイルは何もかも消えてしまう残念な結果に…

![入れ子のCSSは全く当たらない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/25010523-0eab-1fad-2451-91e919c85da1.png)

# 入れ子問題の解決方法

解決方法はかなり簡単で、公式のissueでも言及されてます。
[Nested CSS not compiled correctly](https://github.com/nuxt-community/tailwindcss-module/issues/348)

nuxt configファイルで下記設定を追加すればいいです。

```js
// nuxt.config.js
export default {
build: {
    postcss: {
      plugins: {
        'postcss-nested': {},
      },
    },
  },
}
```

これでpostcss-nestedの入れ子の書き方（sassを踏襲してる）ができるようになり、もう一度確認するとスタイルがちゃんと効くようになりました。

![本番環境でも入れ子のスタイルも当たる.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/dcea9abc-dcf6-4d3e-5459-7604ff658221.gif)

# アップグレードのメリットその1 - ビルドタイム改善

今回のビルド時間を解決するためではないのですが、公式サイトではv2のほうがビルドが早くなると聞いてバージョンアップ前後のビルドタイムを比較しました。

アップグレード前: 428秒 

![バージョンアップ前のローカル環境yarn build時間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/5251cc18-5c76-0c1e-2146-ba1ef83c784c.png)

アップグレード後: 203秒
![バージョンアップ後のローカル環境yarn build時間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/15eda8c7-20a5-dbee-f6f7-818eff02730c.png)

半分以上短縮できました！

# アップグレードのメリットその2 - JIT（Just-In-Time）モードで開発環境のビルドタイムを短縮

Tailwindcss v2では新たに[JITモード](https://tailwindcss.com/docs/just-in-time-mode)を搭載しました。
JITモードを使うと色んなメリットはありますが、ここでは説明を割愛します。気になる方は公式サイトを見てください。

tailwind configファイルで下記設定を追加するとJITモードを使えます。

```js
// tailwind.config.js
  module.exports = {
   mode: 'jit',
   purge: [
    `~/components/**/*.{vue,js}`,
    `~/layouts/**/*.vue`,
    `~/pages/**/*.vue`,
    `~/plugins/**/*.{js,ts}`,
    `~~/nuxt.config.{js,ts}`
  ]
}
```

JITモードはまだ`preview`段階で本番環境では使わないようにしてますが、開発環境でのビルドタイムがさらに短縮ができるのが１番いいメリットだと思います。

- JITモードOFFのビルドタイム
![JITモードをoffの開発環境のビルトタイム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/c5c30173-ee83-81f8-b2e1-5670fedb07a6.png)

- JITモードONのビルドタイム
![JITモードをonにして開発環境のビルトも早くなる（投稿用）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/8b118dda-f864-9e1a-e04d-5bea21eb4fb9.png)


# 最後に

いかがでしたか？正直アップグレードしかやってないのに、課題の解決もできた上にビルドタイムの短縮までできるなんて嬉しいです。
もしまだアップグレードしてないプロジェクトがあって、今回紹介した課題やビルドタイムが長すぎる悩みがあったらぜひv2にアップグレードしてみてください。