This page introduces weapp-tailwindcss: what it is, the problems it solves, and a high-level map of the repository. For detailed coverage of specific subsystems, refer to the child pages linked throughout.
weapp-tailwindcss is a build-time transformation system that adapts Tailwind CSS for Chinese mini-program platforms. Mini-programs are lightweight app containers distributed through super-apps like WeChat, Alipay, Baidu, ByteDance (Douyin), and QQ. They use custom template languages (WXML, AXML, TTML) and CSS dialects (WXSS, ACSS, TTSS) instead of standard HTML and CSS.
The system operates as plugins for Webpack 4/5, Vite, Gulp, and Rollup, and provides a Node.js API for custom build tools.
The Core Problem
Tailwind CSS generates standard CSS that mini-program runtimes reject. Specifically:
| Standard Tailwind Output | Mini-program Constraint | Result |
|---|---|---|
text-[#fff] (arbitrary values) | WXSS selectors cannot contain [, ], # | Parsing error |
w-1/2 (fractional widths) | WXSS selectors cannot contain / | Parsing error |
.hover:bg-blue-500 | Mini-programs do not support :hover pseudo-class | Selector ignored |
rem units | Mini-programs use rpx (responsive pixels) | Layout breaks |
html, body selectors | Mini-programs use page root selector | Styles not applied |
* { margin: 0 } (universal selector) | Performance issues in WXSS engines | Avoided by convention |
weapp-tailwindcss automatically rewrites CSS selectors, template class attributes, and JavaScript string literals to escape special characters and convert units before the mini-program toolchain processes them.
For the escape mechanism and rpx unit support, see Core Concepts. For all configuration options, see Configuration Reference.
Sources: README.md49-68 packages/weapp-tailwindcss/src/types.ts1-50
The system applies three coordinated transformations to CSS, template, and JavaScript files:
Transformation Pipeline
| Asset Type | Handler | Input Example | Output Example |
|---|---|---|---|
| CSS / WXSS | styleHandler | .text-\[#fff\] { color: #fff } | .text-_h_fff_B { color: #fff } |
| Templates | templateHandler | <view class="text-[#fff]"> | <view class="text-_h_fff_B"> |
| JavaScript | jsHandler | const c = "text-[#fff]" | const c = "text-_h_fff_B" |
The Escape Map
All three handlers share a unified escape dictionary defined in packages/shared/src/escapeMap.ts Common mappings:
| Character | Escaped Form | Example |
|---|---|---|
[ | _h_ | text-[#fff] → text-_h_fff_B |
] | _B | (closing bracket) |
/ | _s_ | w-1/2 → w-1_s_2 |
. | _d_ | text-[1.5rem] → text-_h_1_d_5rem_B |
% | _p_ | w-[50%] → w-_h_50_p__B |
! | _i_ | !important → _i_important |
The escape mapping is bidirectional: runtime packages like @weapp-tailwindcss/merge use the inverse map to unescape classes before conflict resolution, then re-escape the result.
Class Name Validation
To avoid escaping non-Tailwind strings (like "hello world" in JavaScript), the system maintains a classNameSet — a Set<string> of all valid Tailwind classes extracted by tailwindcss-patch during the build. Only strings matching this set are transformed.
See Transformation Pipeline Architecture for the full processing flow. See Class Name Decision Logic for the matching algorithm. See Tailwind CSS Runtime Integration for how
classNameSetis populated.
Sources: packages/shared/src/escapeMap.ts1-100 packages/weapp-tailwindcss/src/compiler/styleHandler.ts1-50 packages/weapp-tailwindcss/src/compiler/templateHandler.ts1-50 packages/weapp-tailwindcss/src/compiler/jsHandler.ts1-50
The repository is a pnpm monorepo managed with Turborepo. The workspace layout is defined in pnpm-workspace.yaml
weapp-tailwindcss/
├── packages/ # Core publishable packages
│ ├── weapp-tailwindcss/ # Main transformation engine
│ ├── shared/ # Internal shared utilities
│ ├── cli/ # weapp-tw CLI
│ ├── postcss/ # Standalone PostCSS plugin
│ ├── mangle/ # Class name mangling (optional)
│ ├── logger/ # Shared logging
│ └── ...
├── packages-runtime/ # Runtime packages (used in mini-program apps)
│ ├── merge/ # @weapp-tailwindcss/merge (tw v4)
│ ├── merge-v3/ # @weapp-tailwindcss/merge-v3 (tw v3)
│ ├── variants/ # @weapp-tailwindcss/variants
│ ├── cva/ # @weapp-tailwindcss/cva
│ ├── ui/ # @weapp-tailwindcss/ui
│ └── ...
├── apps/ # Internal app workspaces (demos, test apps)
├── demo/ # Framework-specific integration demos
├── templates/ # Starter project templates
├── website/ # Docusaurus documentation site
├── benchmark/ # Performance benchmarks
└── e2e/ # End-to-end HMR regression tests
Sources: pnpm-workspace.yaml package.json scripts/readme/write.ts
Diagram: Published Packages and Their NPM Names
Sources: pnpm-workspace.yaml packages-runtime/ui/package.json scripts/readme/write.ts
The following diagram shows how the major subsystems connect during a build.
Diagram: Transformation Pipeline Architecture
Sources: packages/weapp-tailwindcss/src/index.ts1-100 packages/weapp-tailwindcss/src/compiler/getCompilerContext.ts1-50 packages/weapp-tailwindcss/src/compiler/styleHandler.ts1-50 packages/weapp-tailwindcss/src/compiler/templateHandler.ts1-50 packages/weapp-tailwindcss/src/compiler/jsHandler.ts1-50
Each supported build tool gets a dedicated plugin entry point. The plugins delegate all transformation logic to the shared compiler context.
Diagram: Build Tool Plugin Entry Points
Sources: packages/weapp-tailwindcss/src/webpack/index.ts1-50 packages/weapp-tailwindcss/src/vite/index.ts1-50 packages/weapp-tailwindcss/src/gulp/index.ts1-50 packages/weapp-tailwindcss/src/core/index.ts1-50 website/docs/quick-start/frameworks/rax.md34-44
weapp-tailwindcss integrates with all major mini-program development frameworks through the plugin layer above.
| Framework | Build Tool | Plugin Used |
|---|---|---|
| uni-app (Vue 3) | Vite | UnifiedViteWeappTailwindcssPlugin |
| uni-app (Vue 2) | Webpack | UnifiedWebpackPluginV4 / V5 |
| uni-app x | Vite | UnifiedViteWeappTailwindcssPlugin + uniAppX preset |
| Taro (React / Vue 3) | Webpack 5 | UnifiedWebpackPluginV5 |
| Taro (React) | Vite | UnifiedViteWeappTailwindcssPlugin |
| mpx | Webpack | UnifiedWebpackPluginV5 |
| Rax | Webpack | UnifiedWebpackPluginV5 |
| Native WeChat | Gulp / weapp-vite | createPlugins() / Vite plugin |
Sources: README.md pnpm-workspace.yaml demo/mpx-tailwindcss-v4/package.json demo/taro-app-vite/package.json
Mini-program JavaScript environments lack DOM APIs, so libraries like tailwind-merge (which expects browser CSS parsing) must be wrapped. The packages-runtime/* packages provide escape-aware wrappers:
Runtime Package Exports
| NPM Package | Wraps | Tailwind Version | Key Export |
|---|---|---|---|
@weapp-tailwindcss/runtime | (core utilities) | any | escape(), unescape(), clsx() |
@weapp-tailwindcss/merge | tailwind-merge v3 | v4 | twMerge(), twJoin() |
@weapp-tailwindcss/merge-v3 | tailwind-merge v2 | v3 | twMerge(), twJoin() |
@weapp-tailwindcss/variants | tailwind-variants | v4 | tv(), cn() |
@weapp-tailwindcss/variants-v3 | tailwind-variants | v3 | tv(), cn() |
@weapp-tailwindcss/cva | class-variance-authority | any | cva(), cx() |
@weapp-tailwindcss/ui | (component library) | v4 | CSS + variant definitions |
Example: Using twMerge at Runtime
The escape/unescape cycle happens transparently: build-time transformations escape classes in source files, runtime utilities unescape for merging/composition, then re-escape the result.
See Runtime Packages for API details. See Runtime Core Package for
escape()andunescape()implementations.
Sources: packages-runtime/runtime/src/index.ts1-50 packages-runtime/merge/src/index.ts1-50 packages-runtime/variants/src/index.ts1-50 packages-runtime/ui/package.json1-50 apps/vite-native/package.json32-35
Version Compatibility Matrix
weapp-tailwindcss Version | Tailwind v4 | Tailwind v3 | Tailwind v2 JIT | Runtime Package Suffix |
|---|---|---|---|---|
| 4.x | ✅ | ✅ | ✅ | v4: none, v3: -v3, v2: -v3 |
| 3.x | ❌ | ✅ | ✅ | n/a |
Key Differences by Tailwind Version
| Feature | Tailwind v4 | Tailwind v3 |
|---|---|---|
| Import syntax | @import "tailwindcss" in CSS | @tailwind base/components/utilities |
| PostCSS setup | @tailwindcss/postcss plugin | tailwindcss + autoprefixer |
| Runtime merge package | @weapp-tailwindcss/merge | @weapp-tailwindcss/merge-v3 |
| Config file | tailwind.config.js (optional) | tailwind.config.js (required) |
The rpx Unit Patch
Mini-programs use rpx (responsive pixel) as their layout unit, but Tailwind CSS v3/v4 do not recognize it as a valid length unit. The tailwindcss-patch package (version ^8.7.3 in catalog) modifies Tailwind's runtime to accept rpx in arbitrary values like w-[100rpx].
The patch is applied via a postinstall script that runs weapp-tw patch after npm install:
This modifies the installed tailwindcss package in node_modules/. The patch is idempotent and safe to run multiple times.
See Tailwind CSS Version Support for migration guides. See CLI Tools for
weapp-tw patchcommand details. See Tailwind CSS Runtime Integration for theTailwindcssPatcherimplementation.
Sources: pnpm-workspace.yaml70-73 packages/weapp-tailwindcss/README.md62-68 apps/vite-native/package.json29 demo/uni-app-tailwindcss-v4/package.json46
The project requires Node.js ^20.19.0 || >=22.12.0, as declared in the root package.json44-46
| Topic | Page |
|---|---|
| Core concepts: rpx, class escaping, patch mechanism | Core Concepts |
| Monorepo directory layout | Monorepo Structure |
| How subsystems connect end-to-end | System Architecture |
| Main package exports and API surface | Core Transformation Engine |
| Webpack, Vite, and Gulp plugins | Build Tool Plugins |
| Framework-specific setup guides | Framework Integration |
| Runtime utility packages | Runtime Packages |
| All configuration options | Configuration Reference |
CLI weapp-tw patch command | CLI Tools |