Aller au contenu

Architecture

TailwindPHP est un portage 1:1. La base de code reprend la structure propre à TailwindCSS — mêmes noms de fichiers, même organisation — et isole sous src/_tailwindphp/ les éléments qui ne peuvent pas être portés directement (PHP n’a ni Rust ni V8). Cette page présente le pipeline de compilation, l’organisation des sources, la réimplémentation de lightningcss et la convention utilisée pour documenter les écarts.

Le pipeline

Générer CSS passe par plusieurs étapes. Il n’y a pas d’étape de build distincte : chaque appel à tw::generate() exécute l’ensemble du pipeline.

Code
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

Analyse syntaxique. css-parser.php lit l’entrée CSS — @import, @theme, @utility, @layer et règles brutes — dans un arbre syntaxique abstrait de nœuds ast.php (règles de style, règles @, déclarations). Les directives @import pour les modules virtuels (tailwindcss, tailwindcss/preflight, …) et les chemins de fichiers sont résolus et remplacés à cette étape.

Construction du système de design. theme.php résout les valeurs du thème (couleurs, espacements, points de rupture) à partir des blocs @theme analysés et des valeurs par défaut. design-system.php est le registre central qui relie le thème aux recherches d’utilitaires et de variantes définies dans utilities.php et variants.php.

Analyse du contenu. candidate.php extrait les classes candidates du contenu fourni (HTML, modèles) et décompose chacune en éléments : utilitaire de base, variantes, modificateurs, valeurs arbitraires et indicateur important.

Compilation. compile.php transforme chaque candidate en nœuds AST en la recherchant dans le système de design et en appliquant ses variantes et modificateurs. Les candidates qui ne correspondent à aucun utilitaire réel sont écartées.

Sérialisation et optimisation. Le toCss() de ast.php parcourt l’arbre (avec les fonctions d’aide de walk.php) et génère la chaîne CSS. Les transformations équivalentes à celles de lightningcss dans _tailwindphp/LightningCss.php sont appliquées afin que le résultat corresponde à celui produit par TailwindCSS après son étape de post-traitement Rust.

Minification. Lorsque minify est activé, toCss() génère du CSS minifié pendant la sérialisation. _tailwindphp/CssMinifier.php assure le passage autonome de la chaîne tw::minify(). Voir Mise en cache et minification.

Organisation des sources

src/ reprend la structure de TailwindCSS. La seule modification structurelle : le utilities.ts de TailwindCSS fait plus de 6,000 lignes ; il est donc réparti dans src/utilities/, avec un fichier par catégorie pour faciliter la maintenance.

Code
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

L’équivalent de lightningcss

TailwindCSS délègue le post-traitement CSS — imbrication, gestion des requêtes média, simplification des valeurs — à lightningcss, un analyseur, transformateur et minificateur écrit en Rust. PHP ne peut pas charger de bibliothèque Rust ; src/_tailwindphp/LightningCss.php réimplémente donc les transformations dont TailwindPHP dépend réellement, en produisant une sortie identique octet pour octet dans les cas couverts par la suite de tests.

Les transformations confirmées comprennent :

Transformation Effet
Aplatissement de l’imbrication Résout les sélecteurs & avec les règles :is(…) de référence et aplatit les règles imbriquées (handleNesting() dans ast.php, portage de la passe TailwindCSS) ; transformNesting rétrograde le niveau des imbrications restantes sous le premier niveau contenant des déclarations
Aplatissement des règles conditionnelles Aplatit sur place les @media, @supports, @container et @starting-style imbriqués, en préservant l’ordre source, et ne fusionne que les éléments frères directement adjacents ayant des conditions identiques
Ordre des déclarations Réordonne les déclarations selon la chaîne de gestion des déclarations de lightningcss, afin que les propriétés suivent l’ordre de référence (reorderDeclarations)
Simplification de calc() Simplifie les expressions calc() (simplifyCalcExpressions)
Suppression des zéros initiaux 0.5 → .5 (normalizeLeadingZeros)
Espacement des fonctions de transformation Normalise les espaces dans les fonctions de transformation (normalizeTransformFunctions)
Normalisation des valeurs de grille Ajoute des espaces autour de / dans les valeurs span ; convertit les entiers seuls en px pour grid-template-* (normalizeGridValues)
Normalisation des couleurs Normalise la syntaxe des couleurs et évalue color-mix() en oklab() (normalizeColors, evaluateColorMix)
Mise entre guillemets de URL url(./x.jpg) → url("./x.jpg") (normalizeUrlQuoting)
Préfixes vendeurs Ajout de préfixes équivalents à Autoprefixer (addVendorPrefixes)

Ce fichier est volontairement isolé dans _tailwindphp/ et marqué @port-deviation:replacement : il représente une dépendance externe au lieu de porter le code source de TailwindCSS.

Marqueurs d’écart du portage

Chaque fichier d’implémentation comporte des marqueurs @port-deviation:* dans son bloc de documentation, qui indiquent où et pourquoi l’implémentation PHP s’écarte de la version originale TypeScript. Ainsi, en comparant PHP au code source de TailwindCSS, le lecteur sait toujours si une différence est intentionnelle.

Marqueur Signification
@port-deviation:none Portage direct 1:1 sans écart notable
@port-deviation:async PHP utilise du code synchrone au lieu de async/await
@port-deviation:storage Structures de données différentes (tableau PHP contre Map/Set JS)
@port-deviation:types Annotations PHPDoc au lieu des types TypeScript
@port-deviation:sourcemaps Suivi des source maps omis
@port-deviation:enum Constantes PHP au lieu des énumérations TypeScript
@port-deviation:errors Approche différente de la gestion des erreurs
@port-deviation:replacement Implémentation PHP remplaçant une bibliothèque externe (e.g. lightningcss)
@port-deviation:helper Fonction auxiliaire propre à PHP, absente de l’original
@port-deviation:performance Optimisation propre à PHP qui préserve une sortie identique
@port-deviation:omitted Module/fonctionnalité entièrement non porté (hors périmètre)

Pour consulter les marqueurs @port-deviation:performance et savoir comment la parité est assurée, voir Performances et tests.