아키텍처
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 및 원시 규칙을 스타일 규칙, at-rule, 선언 노드로 이루어진 ast.php 추상 구문 트리로 읽습니다. 가상 모듈(tailwindcss, tailwindcss/preflight, …)을 위한 @import 지시문과 파일 경로도 이 단계에서 확인하고 대체합니다.
디자인 시스템 구성. theme.php는 파싱된 @theme 블록과 기본값에서 테마 값(색상, 간격, 중단점)을 확인합니다. design-system.php는 utilities.php 및 variants.php에 정의된 테마와 유틸리티 및 변형 조회를 연결하는 중앙 레지스트리입니다.
콘텐츠 스캔. candidate.php는 제공된 콘텐츠(HTML, 템플릿)에서 클래스 이름 후보를 추출하고, 각 후보를 기본 유틸리티, 변형, 수정자, 임의 값, important 플래그로 나눠 파싱합니다.
컴파일. compile.php는 각 후보를 디자인 시스템에서 조회하고 변형과 수정자를 적용해 AST 노드로 변환합니다. 실제 유틸리티에 해당하지 않는 후보는 제외합니다.
직렬화 및 최적화. ast.php의 toCss()는 트리를 순회하고(walk.php의 헬퍼 사용) CSS 문자열을 출력합니다. _tailwindphp/LightningCss.php의 lightningcss에 해당하는 변환을 적용하므로, 출력은 TailwindCSS가 Rust 후처리 단계에서 생성하는 결과와 일치합니다.
최소화. minify가 활성화되면 toCss()는 직렬화 중 최소화된 CSS를 출력합니다. 독립 실행형 tw::minify() 문자열 처리 단계는 _tailwindphp/CssMinifier.php를 기반으로 합니다. 캐싱 및 최소화를 참조하세요.
소스 구성
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-rule 평탄화 | 중첩된 @media, @supports, @container, @starting-style를 제자리에서 평탄화하고 소스 순서를 유지하며, 조건이 동일하고 바로 인접한 형제 항목만 병합합니다. |
| 선언 순서 정렬 | lightningcss의 선언 처리기 체인에 따라 선언 순서를 바꿔 속성이 참조 구현과 같은 순서(reorderDeclarations)로 출력되게 합니다. |
calc() 단순화 |
calc() 식을 단순화합니다(simplifyCalcExpressions). |
| 앞쪽 0 제거 | 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 |
TypeScript 타입 대신 PHPDoc 주석 사용 |
@port-deviation:sourcemaps |
소스 맵 추적 생략 |
@port-deviation:enum |
PHP 상수 대신 TypeScript 열거형 사용 |
@port-deviation:errors |
오류 처리 방식이 다름 |
@port-deviation:replacement |
외부 라이브러리(e.g. lightningcss)를 대체하는 PHP 구현 |
@port-deviation:helper |
원본에는 없는 PHP 전용 헬퍼 |
@port-deviation:performance |
동일한 출력을 유지하는 PHP 전용 최적화 |
@port-deviation:omitted |
포트 범위 밖이라 포트되지 않은 모듈/기능 전체 |
@port-deviation:performance 표시와 동등성 보장 방법은 성능 및 테스트를 참조하세요.