【Tailwind和訳】GETTING STARTED/Optimizing for Production
この記事について
この記事は、GETTING STARTED/Optimizing for Productionの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
運用時の最適化
本番環境で使われていない CSS を削除することで、最大限のパフォーマンスを得ることができます。
概要
デフォルトの設定では、Tailwind CSS の開発ビルドは、非圧縮で 3566.2kB、Gzipで minify して圧縮すると 289.2kB、Brotliで圧縮すると 71.3kB となります。
非圧縮 | Minified | Gzip | Brotli |
---|---|---|---|
3566.2kB | 2872.2kB | 289.2kB | 71.3kB |
膨大な量に聞こえるかもしれませんが、開発用のビルドは設計上大きくなっています。
開発の生産性を高めるために、Tailwind は何千ものユーティリティクラスを生成しています。
Tailwind は、巨大なレゴの箱のようなものだと思ってください。床にすべてを捨てて、作りたいものを作り、終わったら使わなかったピースをすべて箱に戻します。
例えば、Tailwind は、スペーシングスケールのすべてのサイズ、マージンを適用したい要素のすべての側面、プロジェクトで使用しているすべてのブレークポイントに対して、マージンユーティリティを生成します。これにより、何百種類もの組み合わせが可能になりますが、これらはすべて利用可能であることが重要ですが、すべてが必要であるとは限りません。
本番環境でビルドする場合は、Tailwind のpurge
オプションを使用して、未使用のスタイルをツリーシェイクし、最終的なビルドサイズを最適化する必要があります。Tailwind で未使用のスタイルを削除した場合、10kb 以上の圧縮された CSS になることは非常に困難です。
パージ可能な HTML の記述
purge
機能を使い始める前に、その仕組みを理解し、運用時に重要なスタイルを誤って削除してしまわないように、正しいメンタルモデルを構築することが重要です。
PurgeCSS(ボンネット内で使用しているライブラリ)は、HTML 内のクラスを探す方法として、意図的に非常に素朴なものになっています。HTML を解析してクラス属性を探したり、JavaScript を動的に実行したりすることはなく、単にファイル全体から正規表現にマッチする文字列を探します。
/[^<>"'`\s]*[^<>"'`\s:]/g
これは基本的に、スペース、引用符、角括弧で区切られたあらゆる文字列にマッチするもので、HTML タグ、属性、クラス、さらにはマークアップ内の実際の記述内容も含まれます。
<div class="md:flex">
<div class="md:flex-shrink-0">
<img class="rounded-lg md:w-56" src="/img/shopping.jpg" alt="Woman paying for a purchase" />
</div>
<div class="mt-4 md:mt-0 md:ml-6">
<div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">Marketing</div>
<a
href="/get-started"
class="block mt-1 text-lg leading-tight font-semibold text-gray-900 hover:underline"
>
Finding customers for your new business
</a>
<p class="mt-2 text-gray-600">
Getting a new business off the ground is a lot of hard work. Here are five ideas you can use
to find your first customers.
</p>
</div>
</div>
つまり,テンプレート内のクラス文字列を文字列連結で動的に作らないようにすることが重要です。そうしないと,PurgeCSS はそれらのクラスを保存することができません。
クラス名の作成に文字列の連結を使用しない
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>
完全なクラス名を動的に選択する
<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
クラス名がテンプレートにそのまま表示されている限り,PurgeCSS はそれを削除しません。
未使用の CSS を削除する
基本的な使い方
まず、purge
オプションを使って、すべてのテンプレートファイルのパスの配列を指定します。
module.exports = {
purge: [
'./src/**/*.html',
'./src/**/*.vue',
'./src/**/*.jsx',
],
theme: {},
variants: {},
plugins: [],
}
このリストには、プロジェクト内でスタイルを名前で参照しているすべてのファイルを含める必要があります。例えば、プロジェクト内に HTML 内のいくつかのクラスを動的に切り替える JS ファイルがある場合、そのファイルがこのリストに含まれていることを確認する必要があります。
これで、NODE_ENV
をproduction
に設定して CSS をコンパイルすると、Tailwind は自動的に CSS から未使用のスタイルを削除します。
手動で有効にする
未使用のスタイルが削除されるかどうかを(環境変数に暗黙的に依存するのではなく)手動で制御したい場合は、オブジェクト構文を使用してenabled
オプションを指定し、content
オプションでテンプレートを指定します。
module.exports = {
purge: {
enabled: true,
content: ['./src/**/*.html'],
},
// ...
}
開発中に未使用のスタイルを削除すると、テンプレートを変更するたびに再コンパイルする必要があり、PurgeCSS を有効にしてコンパイルすると、非常に時間がかかるため、本番環境では未使用のスタイルのみを削除することをお勧めします。
特定のクラスのセーフリスト化
特定のクラスをセーフリストに登録して、CSS から誤って削除されないようにする必要がある場合 (データベースなどから取得したコンテンツで使用されている場合など)、トップレベルのsafelist
オプションを使用できます。
module.exports = {
purge: {
content: ['./src/**/*.html'],
safelist: [
'bg-blue-500',
'text-center',
'hover:opacity-100',
// ...
'lg:text-right',
]
},
// ...
}
コンテンツの変換
時には、HTML にコンパイルされるフォーマットでコンテンツをオーサリングしていて、潜在的なクラスを探す前にそのコンテンツを HTML にコンパイルした方が良い場合があります。このような例としては、マークダウンファイルでの作業が挙げられます。
transform
オプションを使用すると、クラスを検索する前に、特定の拡張子にマッチするファイルをトランスフォームするよう Tailwind に指示することができ、最も正確な結果を保証します。
let remark = require('remark')
module.exports = {
purge: {
content: ['./src/**/*.{html,md}'],
transform: {
md: (content) => {
return remark().process(content)
}
}
},
// ...
}
抽出ロジックのカスタマイズ
特定のファイルタイプのコンテンツ内のクラスを検出するために Tailwind が使用するロジックをオーバーライドする必要がある場合、extract
オプションを使用して、一致するファイル内の潜在的なクラスを検出するために使用される関数を提供することができます。
module.exports = {
purge: {
content: ['./src/**/*.{html,md}'],
extract: {
md: (content) => {
return content.match(/[^<>"'`\s]*/)
}
}
},
// ...
}
これは高度な機能であり、ほとんどのユーザーには必要ありません。Tailwind のデフォルトの抽出ロジックは、ほとんどすべてのプロジェクトで非常にうまく機能しています。
HTML 要素の保存
Tailwind はデフォルトで、html
、body
、p
、h1
などの基本的な HTML 要素のスタイルをすべて CSS に保持します。これは、例えばマークダウンのソースファイル(実際にはh1
タグが存在しない)を使用している場合や、(Next.js のように)ドキュメントシェル(html
やbody
タグを含む)をベンダーディレクトリのどこかに隠すフレームワークを使用している場合に、誤ってオーバーパージしてしまうことを最小限に抑えるためです。
この動作を無効にしたい場合は、preserveHtmlElements
を false に設定してください。
module.exports = {
purge: {
preserveHtmlElements: false,
content: ['./src/**/*.html'],
},
// ...
}
私たちは一般的にこれを推奨しませんし、リスクがメリットを上回ると考えていますが、私たちは警察ではありませんので、使用を止めることもありません。
特定のレイヤーのパージ
デフォルトでは、Tailwind はbase
、components
、utilities
の各レイヤーにあるすべてのスタイルを消去します。これを変更したい場合は、layers
オプションを使用して、パージしたいレイヤーを手動で指定してください。
module.exports = {
purge: {
layers: ['components', 'utilities'],
content: ['./src/**/*.html'],
},
// ...
}
すべての未使用のスタイルを削除する
デフォルトでは、Tailwind は自分自身で生成した未使用のクラス、または@layer
ディレクティブで明示的にラップされたクラスのみを削除します。例えばデータピッカーライブラリのように、プロジェクトに取り込んだサードパーティの CSS から未使用のスタイルを削除することはありません。
/* これらのスタイルはすべてパージされます。 */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* これらのスタイルはパージされます。 */
@layer components {
.btn { /* ... */ }
}
/* これらのスタイルはパージされません。 */
.flatpickr-innerContainer { /* ... */ }
.flatpickr-weekdayContainer { /* ... */ }
.flatpickr-weekday { /* ... */ }
これは、node_modules
フォルダの奥深くで他の依存関係の一部として参照されているだけのクラスのように、必要かもしれないがテンプレートで直接参照されていないスタイルを誤って削除してしまうことを避けるためです。
本当に使われていないスタイルをすべて削除したい場合は、mode: 'all'
とpreserveHtmlElements: false
を設定し、クラスや HTML 要素を参照している可能性のあるすべてのファイルのパスを指定するように注意してください。
module.exports = {
purge: {
mode: 'all',
preserveHtmlElements: false,
content: [
'./src/**/*.js',
'./node_modules/flatpickr/**/*.js',
],
},
// ...
}
この方法はお勧めできません。一般的には、より保守的なデフォルトのアプローチを採用することで、ファイルサイズの 99%の利点を得ることができます。
未使用のキーフレームの削除
PurgeCSS は,デフォルトでは未使用の@keyframes
ルールを削除しませんので,アニメーション関連のスタイルを使用していなくても,スタイルシートに残ってしまうことがあります。これらは,PurgeCSS のoptions
にあるkeyframes
オプションで削除できます。
module.exports = {
purge: {
content: ['./src/**/*.html'],
options: {
keyframes: true,
},
},
// ...
}
PurgeCSS オプション
他のオプションを PurgeCSS に直接渡す必要がある場合は,options
を使って渡すことができます。
module.exports = {
purge: {
content: ['./src/**/*.html'],
// これらのオプションは、PurgeCSSに直接渡されます。
options: {
safelist: ['bg-red-500', 'px-4'],
blocklist: [/^debug-/],
keyframes: true,
fontFace: true,
},
},
// ...
}
利用可能なオプションの一覧は,PurgeCSS のドキュメントに記載されています。
別のアプローチ
何らかの理由で PurgeCSS を使用できない場合は、設定ファイルから未使用の値を削除することで Tailwind のフットプリントを減らすこともできます。
デフォルトのテーマでは、色、ブレークポイント、サイズ、マージンなどが豊富に用意されており、Tailwind を使って何かを試作したり、CodePen のデモを作成したり、ワークフローを試したりする際に、できるだけ楽しく、スムーズに作業ができるようになっています。
パディングヘルパーが十分に用意されていなかったからといって、新たに CSS を書かなければならなかったり、デモでオレンジ色を使いたかったのに青色しか用意されていなかったからといって、新たに CSS を書かなければならないようなことは避けたいのです。
しかし、これにはトレードオフがあります。デフォルトのビルドは、目的に応じた設定ファイルを持つプロジェクトに比べて、かなり重くなっています。
ここでは、生成される CSS を小さくしてパフォーマンスを維持するための戦略をいくつかご紹介します。
カラーパレットの制限
デフォルトのテーマには、背景、ボーダー、テキスト、プレースホルダーに使用されるカラーがなんと84 色も含まれています。これらのカラーには、hover:
やfocus:
のバリエーションがあり、デフォルトの 6 つのスクリーンサイズではレスポンシブなバリエーションも用意されています。
デフォルトでは、これらの色に対応するために何千ものクラスが生成され、最終的なビルドサイズの半分近くを占めています。
実際には、これほど多くの色を必要とするプロジェクトはほとんどなく、必要のない色を削除することで、全体のファイルサイズに大きな影響を与えることができます。
ここでは、カラーパレットを小さくすることで、最終的なサイズにどのような影響があるのかを紹介します。
色 | オリジナル | Minified | Gzip | Brotli |
---|---|---|---|---|
84 (デフォルト) | 3566.2kB | 2872.2kB | 289.2kB | 71.3kB |
50 | 2726.9kB | 2167.5kB | 231.9kB | 57.2kB |
25 | 2098.6kB | 1639.0kB | 189.9kB | 47.1kB |
使用しないブレークポイントの削除
ほぼすべての Tailwind ユーティリティは、すべてのスクリーンサイズに対応してコピーされているため、スクリーンサイズを少なくすることで、全体のファイルサイズにも大きな影響を与えます。
ここでは、少ないスクリーンを定義することで、出力にどのような影響があるかを説明します。
色 | オリジナル | Minified | Gzip | Brotli |
---|---|---|---|---|
5 (デフォルト) | 3566.2kB | 2872.2kB | 289.2kB | 71.3kB |
3 | 2343.9kB | 1894.0kB | 192.8kB | 60.9kB |
3 | 1742.7kB | 1414.7kB | 145.0kB | 55.3kB |
1 | 1141.7kB | 935.6kB | 96.8kB | 50.7kB |
3 つのスクリーンサイズと 35 色だけが必要な場合は、何も変更せずに 44.3kB に圧縮されます。
未使用のコアプラグインとバリアントの無効化
プロジェクトで必要としないユーティリティー・プラグインは、設定ファイルのcorePlugins
セクションでfalse
に設定することで完全に無効にすることができます。
module.exports = {
// ...
corePlugins: {
float: false
}
}
一握りのユーティリティーしか必要としない場合は、残しておきたいユーティリティープラグインを配列にしてcorePlugins
に渡すことができます。
module.exports = {
// ...
corePlugins: [
'margin',
'padding'
]
}
上記は、マージンとパディング以外のすべてのユーティリティを無効にします。
ユーティリティーは必要だが、レスポンシブバージョンは必要ないという場合は、そのバリアントを空の配列に設定することで、83%少ないクラスを生成することができます。
module.exports = {
// ...
variants: {
appearance: [],
},
}
これらは、カラーパレットの制限やブレイクポイントの数を減らすことに比べれば小さな成果ですが、それでも積み重ねることができます。
Discussion