跳转到正文

架构

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 标记以及如何确保一致性,请参阅性能与测试。