
# Кэширование и минификация

На заключительном этапе конвейера возникают три задачи, связанные с использованием в production: избежать повторной компиляции одинаковых входных данных, не создавать компилятор при каждом запросе и уменьшить размер сгенерированного CSS. Для решения всех трех задач служат вспомогательные средства на стороне PHP, работающие с компилятором.

## Кэширование

При каждой генерации CSS весь конвейер выполняется заново. Если содержимое не меняется между запросами, файловый кэш сохраняет результат на диске и при последующих вызовах отдает его оттуда.

Передайте `cache` в `tw::generate()` — `true` для каталога по умолчанию или строку с путем для другого каталога:

```php
use TailwindPHP\tw;

// Cache to the default directory: sys_get_temp_dir() . '/tailwindphp'
$css = tw::generate([
    'content' => '<div class="flex p-4">Hello</div>',
    'cache' => true,
]);

// Cache to a custom directory
$css = tw::generate([
    'content' => '<div class="flex p-4">Hello</div>',
    'cache' => '/path/to/cache',
]);

// With a time-to-live (seconds)
$css = tw::generate([
    'content' => '<div class="flex p-4">Hello</div>',
    'cache' => true,
    'cacheTtl' => 3600, // expire after 1 hour
]);
```

Если каталога кэша еще нет, он будет создан автоматически.

### Ключ кэша

Ключ вычисляется на основе **содержимого**, **конфигурации CSS** и флага **minify** — затем хешируется в имя файла `tailwind_<hash>.css`. Любое изменение разметки, входных данных CSS или состояния минификации приводит к созданию другого ключа и, следовательно, другого файла.

В ключ включена конфигурация CSS: встроенный `css` и содержимое файлов, указанных в `importPaths`. Два вида данных в ключ не входят: файлы, подключенные вложенным `@import` внутри этих файлов, и версия TailwindPHP. После изменения вложенного импорта или обновления пакета очистите кэш, иначе продолжит выдаваться старый результат.

### Срок хранения

`cacheTtl` задает срок хранения в секундах. При попадании в кэш время изменения файла сравнивается с текущим временем. Если файл старше `cacheTtl`, кэш считается промахом и выполняется повторная компиляция. Если `cacheTtl` не задан, записи не устаревают — удалите их вручную.

### Очистка кэша

`tw::clearCache()` (или функция `clearCache()`) удаляет файлы `tailwind_*.css` из каталога кэша и возвращает количество удаленных файлов.

```php
use TailwindPHP\tw;
use function TailwindPHP\clearCache;

$deleted = tw::clearCache();                  // default directory
$deleted = tw::clearCache('/path/to/cache');  // custom directory
clearCache('/path/to/cache');                 // function form
```

## Кэш состояния компилятора

Кэш вывода помогает только при повторном использовании того же содержимого. Если оно меняется при каждом вызове, больше всего времени занимает создание самого компилятора: разрешение `@import "tailwindcss"`, разбор встроенных ресурсов и накопление темы. Этот этап зависит только от входных данных CSS, поэтому его можно сохранить и использовать повторно.

Передайте `stateCacheFile` в `tw::compile()` (или `new TailwindCompiler($css, $options)`):

```php
use TailwindPHP\tw;

$compiler = tw::compile($themeCss, [
    'stateCacheFile' => __DIR__ . '/cache/tailwind-state.php',
]);

$css = $compiler->generateExact($html, true);
```

При первом создании состояние записывается по этому пути в виде обычного файла PHP, которым OPcache может пользоваться в нескольких запросах. При следующих созданиях оно загружается вместо повторного разбора. Вывод побайтно идентичен результату компилятора без кэша.

- Файл проверяется по отпечатку движка (размеру и времени изменения исходников и ресурсов TailwindPHP), ключу, вычисленному на основе входных данных CSS, параметров `base` и `importSearchPaths`, а также размеру и времени изменения каждого файла, импортированного входными данными. При несовпадении файл пересоздается и сохраняется заново. Поэтому после обновления TailwindPHP или изменения импортированного файла ничего делать вручную не нужно.
- Вы сами задаете путь: используйте отдельный файл для каждого набора входных данных CSS в каталоге, доступном веб-серверу для записи. Запись выполняется атомарно (во временный файл с последующей операцией `rename()`).
- Для входных данных с пользовательским `importResolver` кэш не используется, так как поведение резолвера нельзя проверить по отпечатку.
- Тот же кэш можно использовать с низкоуровневым массивом `compile()` API через `TailwindPHP\StateCache\compileCssCached($css, $cacheFile, $options)`.

`tw::generate()` не принимает `stateCacheFile`: при каждом вызове он создает новый компилятор. Если важны затраты на создание, используйте экземпляр компилятора.

## Минификация

Минификация уменьшает размер вывода для использования в production. Флаг `minify` создает минифицированный CSS непосредственно во время сериализации. Это самый быстрый и точный способ; `tw::minify()` запускает основанный на строках минификатор (`src/_tailwindphp/CssMinifier.php`) для уже готовой строки CSS:

```php
use TailwindPHP\tw;

// Minify during generation (serializer path, preferred)
$css = tw::generate([
    'content' => '<div class="flex p-4">Hello</div>',
    'minify' => true,
]);

// Or minify an existing string (string-based post-pass)
$css = tw::generate('<div class="flex p-4">Hello</div>');
$minified = tw::minify($css);
```

Эти два способа дают одинаковую структуру, но байты не совпадают. При сериализации сохраняются дочерние селекторы `:not()`, которые строковый проход объединяет, поэтому для сгенерированного вывода предпочтителен флаг `minify`, а `tw::minify()` следует использовать для CSS, полученного в виде строки.

### Что делает минификация

Оба способа выполняют одинаковый набор сокращений:

| Шаг | Результат |
|------|--------|
| Удаление комментариев | Удаляет блоки `/* … */` |
| Схлопывание пробелов | Схлопывает последовательности пробелов и убирает пробелы вокруг `{ } ; : ,` и комбинаторов селекторов |
| Сокращение шестнадцатеричных цветов | `#ffffff` → `#fff`, `#aabbcc` → `#abc` |
| Удаление нулевых единиц измерения | `0px` → `0` (сохраняет значения времени `0s`/`0ms`) |
| Сокращение начертания шрифта | `font-weight:normal` → `400`, `font-weight:bold` → `700` |
| Удаление пустых правил | Удаляет селекторы с пустыми блоками объявлений |

По замыслу минификатор **не** объединяет дублирующиеся селекторы и сокращенные свойства — и то и другое затрудняет отладку и может повлиять на каскад.

### CLI: `--minify` и `--optimize`

[CLI](https://tailwindphp.inline0.dev/ru/docs/cli) предоставляет доступ к режиму минификации сериализатора через два флага:

```bash
# Optimize and minify (smallest output)
tailwindphp -i ./src/app.css -o ./dist/styles.css --minify   # or -m

# Meant to optimize without minifying
tailwindphp -i ./src/app.css -o ./dist/styles.css --optimize
```

В текущем выпуске `--optimize` также выполняет минификацию, поэтому обе команды записывают одинаковые байты ([#9](https://github.com/inline0/tailwindphp/issues/9)). Эквивалентные lightningcss преобразования выполняются при каждой сборке, поэтому обычный вывод (без флага) уже оптимизирован и удобен для чтения.

Остальные публичные API — `tw::generate()`, `tw::compile()`, методы проверки и форматы ввода — см. в [справочнике](https://tailwindphp.inline0.dev/ru/docs/api)API.
