Vai al contenuto

Architettura

TailwindPHP è una portabilità 1:1. La codebase rispecchia la struttura originale di TailwindCSS: stessi nomi di file e stessa organizzazione; le parti che non possono essere portate direttamente (PHP non ha Rust né V8) sono isolate sotto src/_tailwindphp/. Questa pagina illustra la pipeline di compilazione, l'organizzazione dei sorgenti, la reimplementazione di lightningcss e la convenzione usata per documentare le differenze.

La pipeline

La generazione di CSS è una sequenza di fasi. Non c'è un passaggio di build separato: ogni chiamata a tw::generate() esegue l'intera pipeline.

Codice
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

Analisi. css-parser.php legge l'input CSS: @import, @theme, @utility, @layer, regole raw; e lo trasforma in un albero sintattico astratto composto da nodi ast.php (regole di stile, at-rule, dichiarazioni). In questa fase vengono risolte e sostituite le direttive @import per i moduli virtuali (tailwindcss, tailwindcss/preflight, …) e i percorsi dei file.

Costruzione del sistema di design. theme.php risolve i valori del tema (colori, spaziatura, breakpoint) dai blocchi @theme analizzati e dai valori predefiniti. design-system.php è il registro centrale che collega il tema alle definizioni di utilità e varianti in utilities.php e variants.php.

Scansione dei contenuti. candidate.php estrae i candidati per i nomi delle classi dai contenuti forniti (HTML, template) e scompone ciascuno nelle sue parti: utilità di base, varianti, modificatori, valori arbitrari e flag important.

Compilazione. compile.php converte ogni candidato in nodi AST cercandolo nel sistema di design e applicando varianti e modificatori. I candidati che non corrispondono a un'utilità reale vengono scartati.

Serializzazione e ottimizzazione. ast.php percorre l'albero con il suo toCss() (helper in walk.php) e genera la stringa CSS. Vengono applicate in _tailwindphp/LightningCss.php le trasformazioni equivalenti a lightningcss, così l'output corrisponde a quello prodotto da TailwindCSS dopo il passaggio di post-elaborazione Rust.

Minificazione. Quando minify è abilitato, toCss() genera CSS minificato durante la serializzazione. _tailwindphp/CssMinifier.php gestisce il passaggio autonomo sulla stringa tw::minify(). Consultate Cache e minificazione.

Organizzazione dei sorgenti

src/ rispecchia TailwindCSS. L'unica modifica strutturale: TailwindCSSutilities.ts contiene più di 6,000 righe, quindi è suddiviso in src/utilities/, con un file per categoria, per facilitarne la manutenzione.

Codice
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'equivalente di lightningcss

TailwindCSS delega a lightningcss, un parser/trasformatore/minificatore scritto in Rust, la post-elaborazione di CSS: annidamento, gestione delle media query e semplificazione dei valori. PHP non può caricare una libreria Rust, quindi src/_tailwindphp/LightningCss.php reimplementa le trasformazioni su cui TailwindPHP fa effettivamente affidamento, producendo un output identico byte per byte nei casi coperti dalla suite di test.

Trasformazioni confermate:

Trasformazione Cosa fa
Appiattimento dell'annidamento Risolve i selettori & con le regole :is(…) di riferimento e appiattisce le regole annidate (handleNesting() in ast.php, port dell'elaborazione TailwindCSS); transformNesting riduce il livello delle regole annidate rimaste sotto il primo livello che contiene dichiarazioni
Appiattimento delle regole at-rule condizionali Appiattisce sul posto le regole @media, @supports, @container e @starting-style annidate, mantenendo l'ordine del sorgente e unendo solo i fratelli direttamente adiacenti con condizioni identiche
Ordinamento delle dichiarazioni Riordina le dichiarazioni secondo la catena di gestione delle dichiarazioni di lightningcss, così le proprietà seguono l'ordine di riferimento (reorderDeclarations)
Semplificazione di calc() Semplifica le espressioni calc() (simplifyCalcExpressions)
Rimozione degli zeri iniziali 0.5 → .5 (normalizeLeadingZeros)
Spaziatura delle funzioni di trasformazione Normalizza gli spazi all'interno delle funzioni di trasformazione (normalizeTransformFunctions)
Normalizzazione dei valori della griglia Aggiunge spazi intorno a / nei valori span; converte gli interi senza unità in px per grid-template-* (normalizeGridValues)
Normalizzazione dei colori Normalizza la sintassi dei colori e valuta color-mix() in oklab() (normalizeColors, evaluateColorMix)
Virgolette per URL url(./x.jpg) → url("./x.jpg") (normalizeUrlQuoting)
Prefissi dei vendor Aggiunge prefissi equivalenti a Autoprefixer (addVendorPrefixes)

Questo file è intenzionalmente isolato sotto _tailwindphp/ e contrassegnato come @port-deviation:replacement: funge da dipendenza esterna invece di portare il sorgente di TailwindCSS.

Marcatori delle differenze del port

Ogni file di implementazione contiene marcatori @port-deviation:* nel docblock che indicano dove e perché l'implementazione PHP si discosta dall'originale TypeScript. L'obiettivo è consentire a chi confronta PHP con il sorgente di TailwindCSS di capire subito se una differenza è intenzionale.

Marcatore Significato
@port-deviation:none Port diretto 1:1 senza differenze significative
@port-deviation:async PHP usa codice sincrono invece di async/await
@port-deviation:storage Strutture dati diverse (array PHP invece di Map/Set JS)
@port-deviation:types Annotazioni PHPDoc invece dei tipi TypeScript
@port-deviation:sourcemaps Tracciamento delle source map omesso
@port-deviation:enum Costanti PHP invece di enum TypeScript
@port-deviation:errors Approccio diverso alla gestione degli errori
@port-deviation:replacement Implementazione PHP che sostituisce una libreria esterna (e.g. lightningcss)
@port-deviation:helper Helper specifico di PHP, non presente nell'originale
@port-deviation:performance Ottimizzazione specifica di PHP che mantiene un output identico
@port-deviation:omitted Modulo/funzionalità non portato/a (fuori ambito)

Per i marcatori @port-deviation:performance e il modo in cui viene garantita la parità, consultate Prestazioni e test.