Tailwind CSSMiddleTechnical

Как Tailwind удаляет неиспользуемый CSS в продакшне (purging/tree-shaking)?

Tailwind v3+ генерирует только те классы, которые найдены в файлах из content-конфига. В v4 анализ ещё умнее — сканируются все импортированные файлы автоматически. Итоговый CSS в продакшне составляет 5–20 КБ.

Удаление неиспользуемого CSS в Tailwind

Tailwind не включает все возможные утилиты в сборку — вместо этого он сканирует исходные файлы и генерирует CSS только для тех классов, которые там встречаются. В v2 это называлось «purging», в v3+ — «content scanning» или «JIT (Just-in-Time) mode».

Конфигурация content в v3

// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{html,js,jsx,ts,tsx,vue}',
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
    // Для Storybook
    './.storybook/**/*.{js,jsx,ts,tsx}',
    // Внешние пакеты, использующие Tailwind
    './node_modules/@my-company/ui/dist/**/*.js',
  ],
};

Как работает сканирование

Tailwind ищет в файлах строки, похожие на CSS-классы, через регулярное выражение — без разбора AST. Это значит, что класс будет найден, только если он присутствует в файле целиком в виде строки.

// ХОРОШО — класс есть целиком
const cls = 'bg-red-500';
const el = <div className="text-blue-600 font-bold"></div>;

// ПЛОХО — динамическая сборка строки
const color = 'red';
const cls = `bg-${color}-500`; // bg-red-500 НЕ будет найден!

Safelist для динамических классов

// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  safelist: [
    // Явные классы
    'bg-red-500',
    'text-green-600',
    // Паттерны для всего диапазона
    {
      pattern: /bg-(red|green|blue)-(100|500|900)/,
      variants: ['hover', 'focus', 'md'],
    },
  ],
};

Tailwind v4: автоматическое сканирование

/* globals.css — v4 */
@import "tailwindcss";

/* v4 автоматически сканирует все файлы, импортированные в сборщик.
   Явный content-конфиг не нужен для большинства проектов. */

/* Если нужно добавить дополнительные пути: */
@source "../node_modules/@my-company/ui/src";

/* Добавить классы в safelist: */
@source inline("bg-red-500 bg-green-500 bg-blue-500");

Проверка размера итогового CSS

// Сборка с анализом (Vite)
// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // Можно проверить в dist/assets/*.css
      },
    },
  },
});
// package.json — анализ через команду
{
  "scripts": {
    "build:analyze": "npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify && wc -c ./dist/output.css"
  }
}

Типичный итоговый размер

  • Среднее SPA-приложение: 8–15 КБ (gzip)
  • С типографикой (@tailwindcss/typography): +3–5 КБ
  • Для сравнения: Bootstrap full = ~22 КБ, полный Tailwind без purge = ~3 МБ

Подводные камни

  • Динамически собранные имена классов (`bg-${color}-500`) не попадают в сборку — нужен safelist или полные имена в объекте маппинга.
  • Файлы из node_modules не сканируются по умолчанию в v3 — если используете UI-библиотеку с Tailwind-классами, добавьте её путь в content.
  • Опечатка в пути glob (**.tsx вместо **/*.tsx) приведёт к тому, что файлы не сканируются — CSS будет почти пустым.
  • В v3 JIT работает по умолчанию, но в старых v2 нужно явно включать — убедитесь в версии.
  • HTML-шаблоны в PHP, Ruby ERB, Blade должны быть добавлены в content явно — иначе классы из них не попадут в сборку.
  • CSS-модули (*.module.css) тоже нужно добавлять в content, если в них используются Tailwind-классы через @apply.
  • Паттерн /bg-\w+-\d+/ в safelist может включить сотни классов — уточняйте паттерны максимально конкретно.

Common mistakes

  • Смешивать «удаление неиспользуемого CSS» с похожим механизмом без критерия выбора.
  • Игнорировать риск: неверно оценить границы применения темы «удаление неиспользуемого CSS» и получить хрупкое решение.
  • Показывать только синтаксис и не объяснять поведение в runtime или сборке.

What the interviewer is testing

  • Объясняет генерация малого CSS-бандла на основе обнаруженных utility-классов.
  • Показывает на примере, как работает: Tailwind не отправляет весь фреймворк: production CSS строится из найденных class tokens, поэтому динамические имена и внешние пакеты требуют явной стратегии.
  • Называет production-нюанс и граничный случай для темы «удаление неиспользуемого CSS».

Sources

Related topics