Counts the Clouds

Next.jsのビルドタイムだけtailwindcssのスタイルが消える
2021.07.15

Next.js
tailwindcss

sander-weeteling-iGDg_f_mlWo-unsplash.jpg

@tailwindディレクティブを@import文に変更する

開発中は気が付かなかったがvercelにデプロイすると、テーマで指定したスタイルの一部が消えていた。手元でビルドして見てみると、同様にスタイルが消えている。

テーマ記述はこんな感じ。

module.exports = {
  // ...
  theme: {
    extend: {
      colors: {
        danger: colors.red,
        warning: colors.amber,
        success: colors.teal,
        info: colors.blue,
        gray: colors.coolGray,
      },
    },
  },
  // ...
}

とりあえず見つかった情報で、styles/global.css@tailwindディレクティブを@importにしてみたが変化なし

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

safelistオプションを使用する

tailwindcssは全体を載せるとコードベースが巨大なのでビルド時に不要な部分を落とす機能がある。開発時には問題なくて、ビルド時に壊れるのは最適化に問題があるのかもしれない。

safelistオプションを使用すると解消できるが、使うスタイルをひとつづつ記述していくのはだいぶつらい。

module.exports = {
  purge: {
    content: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
    safelist: [
      'lots',
      'of',
      'my',
      'classes',
      // ...
    ],
  },
  // ...
}

クラス名が含まれるコードをpurge対象に指定する

問題の箇所は、コンポーネント外のユーティリティに記述したクラス名をclassnamesを使って動的に設定していた。

// ユーティリティのイメージ
export const dict = {
  item: {
    title: 'title',
    bgClass: 'bg-danger-500',
    textClass: 'text-white',
  },
  // ...
}
// コンポーネント側のイメージ
return (
  <label
    className={classNames(
      {
        [dict.bgClass]: dict.bgClass,
        [dict.textClass]: dict.textClass,
      },
    )}
  >
    {dict.title}
  </label>
)

ユーティリティに記述したクラス名がpurge対象になっていないのが問題かもしれない。

該当ファイルを含めるようにすると正しくビルドできた。

module.exports = {
  purge: {
    content: [
      './pages/**/*.{js,ts,jsx,tsx}',
      './components/**/*.{js,ts,jsx,tsx}',
      './utils/**/*.{js,ts,jsx,tsx}', // <- 追加
    ],
  },
  // ...
}

コンポーネント以外にtailwindcssのクラス名を記述したときはtailwind.config.jspurge.contentをアップデートして、正しくpurge対象に含める必要があるということがわかった。

ていうか公式に書いてあった。

This list should include any files in your project that reference any of your styles by name. For example, if you have a JS file in your project that dynamically toggles some classes in your HTML, you should make sure to include that file in this list.