ファイルサイズのコントロール

生成されたCSSを小さく、かつパフォーマンスを維持するための戦略


Overview

デフォルト構成を使用するとTailwindCSSの開発ビルドは非圧縮で2413.4kB、縮小化しGzipで圧縮すると190.2kBBrotliで圧縮すると46.2kBになります。

UncompressedMinifiedGzipBrotli
2413.4kB1967.4kB190.2kB46.2kB

これはとても大きく思えるかもしれませんが、開発ビルドのサイズは設計により大きくなります

開発エクスペリエンスを可能な限り生産的にするために、 Tailwindは、何千ものユーティリティクラスを生成しますが、そのほとんどはおそらく実際には使用しません。

たとえばTailwindは、プロジェクトで使用しているすべてのブレークポイントで、スペーシングスケールのすべてのサイズ、マージンを適用する可能性のある要素のすべての(上下左右などの)側に対してマージンユーティリティを生成します。

これにより、何百もの異なる組み合わせが利用可能になることが重要ですが、すべてが必要になるとは限りません。

本番用にビルドする場合は、常にTailwindのpurgeオプションを使用して未使用のスタイルを削除し、最終的なビルドサイズを最適化する必要があります。 Tailwindで未使用のスタイルを削除する場合、10kbを超える圧縮CSSを作成することは非常に困難です。

Writing purgeable HTML

purge機能を開始する前に、それがどのように機能するかを理解し、正しいメンタルモデルを構築して、本番用に構築するときに重要なスタイルを誤って削除しないようにすることが重要です。

PurgeCSS (私達が内部で使用するライブラリ)は、HTML内のクラスを検索する方法が意図的に非常に単純になっています。 これはHTMLを解析してクラス属性を探したり、JavaScriptを動的に実行したりすることはありません — この正規表現に一致する文字列をファイル全体から検索するだけです。

/[^<>"'`\s]*[^<>"'`\s:]/g

つまり、文字列を連結してテンプレートにクラス文字列を動的に作成しないようにすることが重要です。 そうしないと、PurgeCSSはそれらのクラスを保持することを知ることはありません。

クラス名の作成に文字列連結を使用しないでください

<div :class="text-{{ error ? 'red' : 'green' }}-600"></div>

完全なクラス名を動的に選択する

<div :class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

クラス名がテンプレートに全体で表示されている限り、PurgeCSSはそれを削除しません。

Removing unused CSS

基本的な使い方

使用を開始するには、purgeオプションを使用して、すべてのテンプレートファイルへのパスの配列を指定します。

// tailwind.config.js
module.exports = {
  purge: [
    './src/**/*.html',
    './src/**/*.vue',
    './src/**/*.jsx',
  ],
  theme: {},
  variants: {},
  plugins: [],
}

このリストには、プロジェクト内の任意のスタイルを名前で参照する任意のファイルを含める必要があります。 たとえば、プロジェクトにHTMLの一部のクラスを動的に切り替えるJSファイルがある場合は、そのファイルをこのリストに含める必要があります。

これで、NODE_ENVproductionに設定してCSSをコンパイルするたびに、TailwindはCSSから未使用のスタイルを自動的に削除します。

Enabling manually

(環境変数に暗黙的に依存するのではなく)未使用のスタイルを削除するかどうかを手動で制御する場合は、 オブジェクト構文を使用してenabledオプションを指定し、contentオプションを使用してテンプレートを指定できます。

// tailwind.config.js
module.exports = {
  purge: {
    enabled: true,
    content: ['./src/**/*.html'],
  },
  // ...
}

開発時に未使用のスタイルを削除すると、テンプレートを変更するたびに再コンパイルする必要があり、 PurgeCSSを有効にしてコンパイルすると非常に時間がかかるため、本番環境では未使用のスタイルのみを削除することをお勧めします。

Preserving HTML elements

デフォルトでは、TailwindはCSSのすべての基本的なHTML要素スタイルを保持します。 例えばhtml, body, p, h1タグなどです。 これは、誤った過剰除去を最小限に抑えるためです。 たとえば、マークダウンソースファイルを使用している場合(実際のh1タグが存在しない場合)、 または、ベンダーディレクトリのどこかにドキュメントシェル(htmlタグとbodyタグを含む)を隠すフレームワークを使用している場合です(Next.jsがやるように)。

この動作を無効にする場合は、preserveHtmlElementsをfalseに設定できます。

// tailwind.config.js
module.exports = {
  purge: {
    preserveHtmlElements: false,
    content: ['./src/**/*.html'],
  },
  // ...
}

私たちは一般的にこれを推奨せず、リスクが利益を上回ると信じていますが、私たちは警官ではありませんので、あなたが望むようにしてください。

Purging specific layers

デフォルトでは、Tailwindは、すべてのbase,componentsおよびutilitiesレイヤーのスタイルを削除します。 もしこれを変更したいならlayersオプションを使用してください。

// tailwind.config.js
module.exports = {
  purge: {
    layers: ['components', 'utilities'],
    content: ['./src/**/*.html'],
  },
  // ...
}

このオプションを尊重するには、modelayersに設定する必要があることに注意してください。

Removing all unused styles

デフォルトでは、Tailwindはそれ自体が生成する未使用のクラスのみを削除します。 たとえば、プルした日付ピッカーライブラリなど、プロジェクトにプルしたサードパーティのCSSから未使用のスタイルを削除することはありません。

これは、必要になる可能性があるが、テンプレートで直接参照されていないスタイルを誤って削除しないようにするためです。 たとえば、他の依存関係の一部であるnode_modulesフォルダーの奥深くでのみ参照されるクラスのようなものです。

本当にすべての未使用のスタイルを削除したい場合は、 mode:'all'オプションを使用し、非常に注意して、クラスまたはHTML要素を参照する可能性のある全てのファイルへのパスを指定します。

// tailwind.config.js
module.exports = {
  purge: {
    mode: 'all',
    content: [
      './src/**/*.js',
      './node_modules/pikaday/pikaday.js',
    ],
  },
  // ...
}

これはお勧めしません。通常、より保守的なデフォルトのアプローチを使用すると、ファイルサイズの99%のメリットが得られます。

PurgeCSS options

オプションをPurgeCSSに直接渡す必要がある場合は、optionsを使用して渡すことができます。

// tailwind.config.js
module.exports = {
  purge: {
    content: ['./src/**/*.html'],

    // These options are passed through directly to PurgeCSS
    options: {
      whitelist: ['bg-red-500', 'px-4'],
    }
  },
  // ...
}

利用可能なオプションについてはPurgeCSS documentationをご覧ください。

Setting up PurgeCSS manually

内部的には、Tailwindのpurge機能はPurgeCSSと呼ばれる素晴らしいライブラリを利用しています。

v1.4.0より前のバージョンのTailwindを使用していて、PurgeCSSを手動でセットアップする必要がある場合は、まず@fullhuman/postcss-purgecssをインストールします。

# Using npm
npm install @fullhuman/postcss-purgecss --save-dev

# Using yarn
yarn add @fullhuman/postcss-purgecss -D

次に、それをpostcss.config.jsファイルの最後のプラグインとして追加します。

// postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss')({

  // Specify the paths to all of the template files in your project
  content: [
    './src/**/*.html',
    './src/**/*.vue',
    './src/**/*.jsx',
    // etc.
  ],

  // This is the function used to extract class names from your templates
  defaultExtractor: content => {
    // Capture as liberally as possible, including things like `h-(screen-1.5)`
    const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []

    // Capture classes within other delimiters like .block(class="w-1/2") in Pug
    const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || []

    return broadMatches.concat(innerMatches)
  }
})

module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
    ...process.env.NODE_ENV === 'production'
      ? [purgecss]
      : []
  ]
}

この例では、本番環境でのみPurgeCSSを有効にしていることに注意してください。 この方法でPurgeCSSを構成することをお勧めします。 実行が遅くなる可能性があるため、開発中は、すべてのクラスを利用できるようにしておくと便利です。 したがって、HTMLを変更するたびに再構築を待つ必要はありません。

最後に、PurgeCSSをTailwindのユーティリティクラスにのみ適用することをお勧めし、base stylescomponent classesには適用しないことをお勧めします。 これを行う最も簡単な方法は、PurgeCSSのwhitelisting 機能を使用して、非ユーティリティクラスのPurgeCSSを無効にすることです。

/* purgecss start ignore */
@tailwind base;
@tailwind components;
/* purgecss end ignore */

@tailwind utilities;

これにより、Next.js, Nuxt, vue-cli, create-react-appなど、 ベースHTMLテンプレートを node_modulesディレクトリのどこかに非表示にするフレームワークを操作するときに重要なベーススタイルを誤って削除することがなくなります。

Understanding the regex

開始点として推奨される正規表現/[\w-/:]+(?<!:)/gは、:/など、Tailwindがデフォルトで使用するすべての非標準文字に一致します。

また、否定先読みを使用して、文字列が :で終わる場合、:が文字列の一部と見なされないようにします。 これは、VueおよびReactのClassnamesライブラリでサポートされているクラスオブジェクト構文との互換性を確保するためです。

<!-- Match `hidden`, not `hidden:` -->
<div :class="{ hidden: !isOpen, ... }"><!-- ... --></div>

この正規表現では否定先読みがあるため、Node.js9.11.2以降とのみ互換性があることに注意することが重要です。 アセットを構築するために古いバージョンのNode.jsを使用する必要がある場合は、代わりに次の正規表現を使用できます。

- /[\w-/:]+(?<!:)/g
+ /[\w-/:]*[\w-/]/g

Customizing the regex

クラス名に他の特殊文字を使用している場合は、それらも含めるように正規表現を更新してください。

たとえば、Tailwindをカスタマイズしてw-50%のようなクラスを作成した場合、正規表現にを追加する必要があります。

- /[\w-/:]+(?<!:)/g
+ /[\w-/:%]+(?<!:)/g

Alternate approaches

何らかの理由でPurgeCSSを使用できない場合は、your configuration fileから未使用の値を削除することで、Tailwindの専有領域を減らすこともできます。

デフォルトのテーマは、非常に豊富な色、ブレークポイント、サイズ、マージンなどのセットを提供します。 Tailwindをプルダウンして何かのプロトタイプを作成したり、CodePenデモを作成したり、ワークフローを試したりするときに、エクスペリエンスが同じように楽しく、 可能な限り流動的にします。

私達がデフォルトで十分なパディングヘルパーを提供していなかった、またはデモにオレンジ色の配色を使用したいのに青しか提供しなかったために、あなたに新しいCSSを作成してほしくはありません。

ただし、これにはトレードオフが伴います: デフォルトのビルドは、専用の構成ファイルを使用するプロジェクトよりも大幅に大きくなります。

生成されたCSSを小さく、パフォーマンスを維持するために使用できるいくつかの戦略を次に示します。

Limiting your color palette

デフォルトのテーマには、背景、境界線、テキスト、プレースホルダーに使用されるなんと93 colorsが含まれています。これらはすべてhover:focusのバリアントに加えて、 5つのデフォルトの画面サイズのレスポンシブバリアントも含まれています。

デフォルトでは、これらの色に対応するために数千のクラスが生成され、最終的なビルドサイズの半分近くを占めます。

実際にこれほど多くの色を必要とするプロジェクトはほとんどなく、不要な色を削除すると、ファイル全体のサイズに大きな影響を与える可能性があります。

小さいカラーパレットを使用すると、最終的なサイズにどのように影響するかを次に示します。

ColorsOriginalMinifiedGzipBrotli
93 (default)2413.4kB1967.4kB190.2kB46.2kB
501584.7kB1273.7kB127.3kB34.3kB
251108.8kB875.3kB98.8kB28.0kB

Removing unused breakpoints

ほとんどすべてのTailwindユーティリティはすべての画面サイズにコピーされるため、使用する画面サイズが少ないと、ファイル全体のサイズにも大きな影響を与える可能性があります。

より少ない画面を定義すると、出力にどのように影響するかを次に示します。

BreakpointsOriginalMinifiedGzipBrotli
4 (default)2413.4kB1967.4kB190.2kB46.2kB
31922.4kB1570.9kB152.6kB42.8kB
21431.7kB1174.5kB114.6kB39.1kB
1941.3kB778.3kB76.7kB35.9kB

3つの画面サイズと35色だけが必要な場合, 何も変更しなくてもファイルサイズがgzip後に88.1kBになります。(Brotli後だと28.7kB!)

Disabling unused utilities and variants

プロジェクトに特定のユーティリティプラグインがまったく必要ない場合は、設定ファイルのcorePluginsセクションでfalseに設定することで、完全に無効にすることができます。

// tailwind.config.js
module.exports = {
  // ...
  corePlugins: {
    float: false
  }
}

ユーティリティは必要だがレスポンシブバージョンは必要ない場合は、そのバリアントを空の配列に設定して、生成するクラスを80%少なくします。

module.exports = {
  // ...
  variants: {
    appearance: []
  }
}

これらは、カラーパレットを制限したり、使用するブレークポイントを少なくしたりする場合と比較して、ほとんどの場合小さなメリットですが、それでも考慮すべきことです。


Translated by T.Arai @ Entap,Inc. / スマホアプリ開発会社

Tailwind UI is now in early access!