본문으로 건너뛰기

아키텍처

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 표시와 동등성 보장 방법은 성능 및 테스트를 참조하세요.