🫠

Tailwind CSS の safelist 設定をミスって Next.js のビルドが激重になっていた話

に公開

だいたいタイトル通り。

Tailwind CSS にはソースコードからクラス名を検出、必要な設定だけを抽出した CSS で無駄のないビルドをする機能が入っています。

デプロイする成果物のサイズを削減、最適化できるという意味では優れた機能なのですが、一方で「Tailwind が自動検出できないクラス名があるとスタイルの適用漏れが発生する」という問題が発生します。これはクラス名を動的に生成するようなコードを書いているときに直面することが多いです。

こういった、自動でクラス名が検出できないようなケースでも特定のクラスを強制的にビルド対象に入れるための仕組みとして、 Tailwind CSS には safelist という機能があります。
(あるんですが公式のドキュメントに全然記載がない…)

例えば以下のような設定を書くと、 w-, h- が含まれるようなクラスは全てビルド対象に含まれるようになるため、クラス自動検出に引っ掛からなくてもちゃんとスタイルが当たるようになります。

module.exports = {
  ...
  safelist: [
    {
      pattern: /(w|h)-.*/,
    },
  ],
};

さて、今回自分のプロジェクトではもともと以下のようなセーフリストを定義していました。

  safelist: [
    {
      pattern: /((min|max)\-)?(w|h)-.*/,
    },
  ],

width, height 関連のクラスを動的に定義してレイアウト調整をしていたため、これらはセーフリストに入れて常に効くようにしておきたかった…という感じです。
この時点でもまぁまぁビルドは重かったのですが、致命的なレベルでもなかったので特段気にすることなく開発を続けていました。

さて、ここに最近以下のような変更を加えました。

  safelist: [
    {
      pattern: /((min|max)\-)?(w|h|m.?|p.?|)-.*/,
    },
  ],

…そうです、 (w|h|m.?|p.?|) のところに余計な | が入っています。
これによってこの正規表現は - を含む任意のクラスという条件になってしまい、
膨大な数のクラスが引っかかる状態になってしまった結果、ビルドが激重になってしまった…という形でした。

ちなみに解決策というか、本来あるべき状態は以下のような形になります。

  safelist: [
    {
      pattern: /^((min|max)\-)?(w|h|m.?|p.?)-.*/,
    },
  ],

ポイントとしては2つ、「先頭にちゃんと ^ を付ける」、「意図しない | を消す」です。
特に前者が地味に重要で、これを守っていれば後者が入ってもそこまで致命的な重さにはなりませんでした。

正規表現はゆるふわで使わないでしっかり考えて書きましょうというお話でした。

Discussion