Архитектура
TailwindPHP — это порт 1:1. Структура кодовой базы повторяет структуру самого TailwindCSS — те же имена файлов и та же организация. Части, которые нельзя перенести напрямую (в PHP нет Rust и V8), изолированы в src/_tailwindphp/. На этой странице описаны конвейер компиляции, структура исходного кода, реализация lightningcss и соглашение для документирования отличий.
Конвейер
Генерация CSS состоит из последовательности этапов. Отдельного шага сборки нет — каждый вызов tw::generate() выполняет весь конвейер.
CSS input (@import "tailwindcss"; @theme { … })
│
▼
┌──────────────┐
│ Parse CSS │ css-parser.php → ast.php nodes
└──────┬───────┘
▼ design system (theme, utilities, variants)
┌──────────────┐
│ Scan content │ candidate.php — extract class names from HTML
└──────┬───────┘
▼ candidates
┌──────────────┐
│ Compile │ compile.php — candidate → AST, via design-system.php
└──────┬───────┘
▼ AST
┌──────────────┐
│ Optimize │ _tailwindphp/LightningCss.php — nesting, @media, calc()
└──────┬───────┘
▼
┌──────────────┐
│ Serialize │ ast.php toCss() (minified when requested)
└──────┬───────┘
▼
CSS output
Разбор. css-parser.php читает входные данные CSS — @import, @theme, @utility, @layer и обычные правила — и создает абстрактное синтаксическое дерево из узлов ast.php (правила стилей, директивы at-rule и объявления). На этом этапе обрабатываются директивы @import для виртуальных модулей (tailwindcss, tailwindcss/preflight, …) и пути к файлам.
Построение дизайн-системы. theme.php получает значения темы (цвета, отступы, контрольные точки) из разобранных блоков @theme и значений по умолчанию. design-system.php — это центральный реестр, который связывает тему с поиском утилит и вариантов, определенным в utilities.php и variants.php.
Сканирование содержимого. candidate.php извлекает кандидаты имен классов из переданного содержимого (HTML, шаблонов) и разбирает каждый на составляющие: базовую утилиту, варианты, модификаторы, произвольные значения и флаг important.
Компиляция. compile.php преобразует каждый кандидат в узлы AST, находя его в дизайн-системе и применяя варианты и модификаторы. Кандидаты, не соответствующие существующей утилите, отбрасываются.
Сериализация и оптимизация. toCss() в составе ast.php проходит по дереву (вспомогательные функции находятся в walk.php) и формирует строку CSS. Затем применяются преобразования из _tailwindphp/LightningCss.php, эквивалентные lightningcss, чтобы результат соответствовал выводу TailwindCSS после этапа постобработки Rust.
Минификация. Когда включен minify, при сериализации toCss() формирует минифицированный CSS. Отдельная обработка строки tw::minify() выполняется с помощью _tailwindphp/CssMinifier.php. См. Кэширование и минификация.
Структура исходного кода
src/ повторяет TailwindCSS. Единственное структурное изменение: TailwindCSSutilities.ts содержит более 6,000 строк, поэтому для удобства сопровождения он разделен на src/utilities/ — по одному файлу на категорию.
src/
├── _tailwindphp/ # PHP-specific — NOT part of the TailwindCSS port
│ ├── LightningCss.php # CSS transforms (lightningcss Rust library equivalent)
│ ├── CssMinifier.php # CSS minification
│ └── lib/ # Companion library ports (TailwindPHP\Lib\*)
│ ├── clsx/ # clsx port
│ ├── tailwind-merge/ # tailwind-merge port
│ └── cva/ # CVA port
│
├── plugin/ # Plugin system
│ └── plugins/
│ ├── typography-plugin.php # @tailwindcss/typography port
│ └── forms-plugin.php # @tailwindcss/forms port
│
├── utilities/ # Split from TailwindCSS utilities.ts (one file per category)
│ ├── accessibility.php # sr-only, forced-colors
│ ├── backgrounds.php # bg-*, gradient-*, from-*, via-*, to-*
│ ├── borders.php # border-*, rounded-*, divide-*, outline-*
│ ├── effects.php # shadow-*, opacity-*, mix-blend-*
│ ├── filters.php # blur-*, brightness-*, contrast-*, …
│ ├── flexbox.php # flex-*, grid-*, gap-*, justify-*, align-*
│ ├── interactivity.php # cursor-*, scroll-*, touch-*, select-*
│ ├── layout.php # display, position, z-*, overflow-*, …
│ ├── masks.php # mask-linear-*, mask-radial-*, mask-conic-*
│ ├── sizing.php # w-*, h-*, min-*, max-*, size-*
│ ├── spacing.php # m-*, p-*, space-*
│ ├── svg.php # fill-*, stroke-*
│ ├── tables.php # border-collapse, table-layout
│ ├── transforms.php # translate-*, rotate-*, scale-*, skew-*
│ ├── transitions.php # transition-*, duration-*, ease-*, delay-*
│ └── typography.php # font-*, text-*, leading-*, tracking-*
│
├── utils/ # Helper functions (ported from utils/)
│
├── index.php # Main entry — compile(), cn(), variants(), merge(), join()
├── ast.php # AST nodes and toCss()
├── candidate.php # Candidate parsing (class name → parts)
├── compile.php # Candidate to CSS compilation
├── css-functions.php # theme(), --theme(), --spacing(), --alpha()
├── css-parser.php # CSS parsing
├── design-system.php # Central registry for utilities/variants
├── plugin.php # Plugin system (PluginInterface, PluginAPI, PluginManager)
├── theme.php # Theme value resolution
├── utilities.php # Utility registration and lookup
├── value-parser.php # CSS value parsing
├── variants.php # Variant handling (hover, focus, responsive, …)
└── walk.php # AST traversal
Аналог lightningcss
TailwindCSS делегирует CSS постобработку — обработку вложенности и медиазапросов, упрощение значений — lightningcss, парсеру, преобразователю и минификатору, написанному на Rust. PHP не может загрузить библиотеку Rust, поэтому src/_tailwindphp/LightningCss.php повторно реализует преобразования, на которые фактически полагается TailwindPHP, и выдает побайтно идентичный результат для случаев, покрытых набором тестов.
Подтвержденные преобразования:
| Преобразование | Что оно делает |
|---|---|
| Уплощение вложенности | Разрешает селекторы & по правилам :is(…) из эталонной реализации и уплощает вложенные правила (handleNesting() в ast.php — порт этапа TailwindCSS); transformNesting понижает оставшуюся вложенность ниже первого уровня, содержащего объявления |
| Уплощение условных at-правил | Уплощает вложенные @media, @supports, @container и @starting-style на месте, сохраняя исходный порядок, и объединяет только непосредственно соседние элементы с одинаковыми условиями |
| Упорядочивание объявлений | Переупорядочивает объявления согласно цепочке обработчиков объявлений lightningcss, чтобы свойства выводились в эталонном порядке (reorderDeclarations) |
Упрощение calc() |
Упрощает выражения calc() (simplifyCalcExpressions) |
| Удаление ведущего нуля | 0.5 → .5 (normalizeLeadingZeros) |
| Пробелы в функциях преобразования | Нормализует пробелы внутри функций преобразования (normalizeTransformFunctions) |
| Нормализация значений сетки | Добавляет пробелы вокруг / в значениях span, преобразует целые числа без единиц в px для grid-template-* (normalizeGridValues) |
| Нормализация цветов | Нормализует синтаксис цветов и вычисляет color-mix() в oklab() (normalizeColors, evaluateColorMix) |
| Расстановка кавычек в URL | url(./x.jpg) → url("./x.jpg") (normalizeUrlQuoting) |
| Префиксы поставщиков | Добавление префиксов, эквивалентное Autoprefixer (addVendorPrefixes) |
Этот файл намеренно изолирован в _tailwindphp/ и помечен как @port-deviation:replacement — он служит заменой внешней зависимости, а не портом исходного кода TailwindCSS.
Маркеры отклонений при портировании
Каждый файл реализации содержит в своем docblock маркеры @port-deviation:*, которые указывают, где и почему реализация PHP отличается от оригинала TypeScript. Благодаря этому читателю, сравнивающему PHP с исходным кодом TailwindCSS, не приходится гадать, намеренно ли внесено различие.
| Маркер | Значение |
|---|---|
@port-deviation:none |
Прямой порт 1:1 без существенных отклонений |
@port-deviation:async |
PHP использует синхронный код вместо async/await |
@port-deviation:storage |
Другие структуры данных (массив PHP вместо Map/Set JS) |
@port-deviation:types |
Аннотации PHPDoc вместо типов TypeScript |
@port-deviation:sourcemaps |
Отслеживание исходных карт не реализовано |
@port-deviation:enum |
Константы PHP вместо перечислений TypeScript |
@port-deviation:errors |
Другой подход к обработке ошибок |
@port-deviation:replacement |
Реализация PHP заменяет внешнюю библиотеку (e.g. lightningcss) |
@port-deviation:helper |
Вспомогательная функция для PHP, отсутствующая в оригинале |
@port-deviation:performance |
Оптимизация для PHP, сохраняющая идентичный результат |
@port-deviation:omitted |
Модуль или функция целиком не портированы (вне рамок проекта) |
О маркерах @port-deviation:performance и проверке соответствия см. раздел Производительность и тестирование.