架构
TailwindPHP 是一个 1:1 移植版。代码库复现了 TailwindCSS 自身的结构——文件名和组织方式都相同——并将无法直接移植的部分隔离在 src/_tailwindphp/ 下(PHP 没有 Rust,也没有 V8)。本页将介绍编译流程、源代码布局、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 规则、声明)组成的抽象语法树。此阶段会解析并替换虚拟模块(tailwindcss、tailwindcss/preflight、…)和文件路径对应的 @import 指令。
构建设计系统。 theme.php 根据已解析的 @theme 代码块和默认值解析主题值(颜色、间距、断点)。design-system.php 是核心注册表,将主题与 utilities.php 和 variants.php 中定义的实用工具及变体查找关联起来。
扫描内容。 candidate.php 从提供的内容(HTML、模板)中提取类名候选项,并将每项解析为其组成部分:基础实用工具、变体、修饰符、任意值和重要标记。
编译。 compile.php 在设计系统中查找每个候选项,并应用其变体和修饰符,将其转换为 AST 节点。无法解析为实际实用工具的候选项会被丢弃。
序列化并优化。 ast.php 的 toCss() 遍历语法树(使用 walk.php 中的辅助函数),并生成 CSS 字符串。应用 _tailwindphp/LightningCss.php 中与 lightningcss 等效的转换,使输出与 TailwindCSS 经过 Rust 后处理后生成的内容一致。
压缩。 启用 minify 时,toCss() 会在序列化期间生成压缩后的 CSS。_tailwindphp/CssMinifier.php 为独立的 tw::minify() 字符串处理流程提供支持。请参阅缓存和压缩。
源码布局
src/ 与 TailwindCSS 保持一致。结构上的唯一变化是:TailwindCSS 的 utilities.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(…) 规则解析 & 选择器并展平嵌套规则(ast.php 中的 handleNesting(),是 TailwindCSS 处理流程的移植);transformNesting 将首个包含声明的层级以下剩余的嵌套规则降级处理 |
| 展平条件 at 规则 | 就地展平嵌套的 @media、@supports、@container 和 @starting-style,保留源码顺序,并且只合并条件相同且直接相邻的同级规则 |
| 声明排序 | 按照 lightningcss 的声明处理器链重新排序声明,使属性顺序与参考实现一致(reorderDeclarations) |
calc() 简化 |
简化 calc() 表达式(simplifyCalcExpressions) |
| 移除前导零 | 0.5 → .5(normalizeLeadingZeros) |
| 转换函数间距 | 规范化转换函数内部的间距(normalizeTransformFunctions) |
| 网格值规范化 | 在跨列值中的 / 两侧添加空格,并将 grid-template-* 的裸整数转换为 px(normalizeGridValues) |
| 颜色规范化 | 规范化颜色语法,并将 color-mix() 计算为 oklab()(normalizeColors、evaluateColorMix) |
| URL 引号处理 | url(./x.jpg) → url("./x.jpg")(normalizeUrlQuoting) |
| 厂商前缀 | 等效于 Autoprefixer 的前缀处理(addVendorPrefixes) |
此文件有意隔离在 _tailwindphp/ 下,并标记为 @port-deviation:replacement;它代表外部依赖,而非移植 TailwindCSS 源码。
移植偏差标记
每个实现文件的文档块中都带有 @port-deviation:* 标记,说明 PHP 实现与原始 TypeScript 有何差异以及原因。这样,读者对照 PHP 和 TailwindCSS 源码时,无需猜测差异是否有意为之。
| 标记 | 含义 |
|---|---|
@port-deviation:none |
直接移植 1:1,没有显著偏差 |
@port-deviation:async |
PHP 使用同步代码,而非 async/await |
@port-deviation:storage |
数据结构不同(PHP 数组,而非 JS Map/Set) |
@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 标记以及如何确保一致性,请参阅性能与测试。