@cwcss/crosswind 0.1.5 ā 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +52 -0
- package/dist/bin/cli.js +14615 -0
- package/dist/build.d.ts +24 -0
- package/dist/config.d.ts +5 -0
- package/dist/generator.d.ts +31 -0
- package/dist/index.d.ts +10 -0
- package/dist/parser.d.ts +42 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/preflight-forms.d.ts +5 -0
- package/dist/preflight.d.ts +2 -0
- package/dist/rules-advanced.d.ts +27 -0
- package/dist/rules-effects.d.ts +25 -0
- package/dist/rules-forms.d.ts +7 -0
- package/dist/rules-grid.d.ts +13 -0
- package/dist/rules-interactivity.d.ts +41 -0
- package/dist/rules-layout.d.ts +26 -0
- package/dist/rules-transforms.d.ts +33 -0
- package/dist/rules-typography.d.ts +41 -0
- package/dist/rules.d.ts +39 -0
- package/dist/scanner.d.ts +18 -0
- package/dist/src/index.js +12848 -0
- package/dist/transformer-compile-class.d.ts +37 -0
- package/{src/types.ts ā dist/types.d.ts} +17 -86
- package/package.json +2 -16
- package/PLUGIN.md +0 -235
- package/benchmark/framework-comparison.bench.ts +0 -850
- package/bin/cli.ts +0 -365
- package/bin/crosswind +0 -0
- package/bin/headwind +0 -0
- package/build.ts +0 -8
- package/crosswind.config.ts +0 -9
- package/example/comprehensive.html +0 -70
- package/example/index.html +0 -21
- package/example/output.css +0 -236
- package/examples/plugin/README.md +0 -112
- package/examples/plugin/build.ts +0 -32
- package/examples/plugin/src/index.html +0 -34
- package/examples/plugin/src/index.ts +0 -7
- package/headwind +0 -2
- package/src/build.ts +0 -101
- package/src/config.ts +0 -529
- package/src/generator.ts +0 -2173
- package/src/index.ts +0 -10
- package/src/parser.ts +0 -1471
- package/src/plugin.ts +0 -118
- package/src/preflight-forms.ts +0 -229
- package/src/preflight.ts +0 -388
- package/src/rules-advanced.ts +0 -477
- package/src/rules-effects.ts +0 -461
- package/src/rules-forms.ts +0 -103
- package/src/rules-grid.ts +0 -241
- package/src/rules-interactivity.ts +0 -525
- package/src/rules-layout.ts +0 -385
- package/src/rules-transforms.ts +0 -412
- package/src/rules-typography.ts +0 -486
- package/src/rules.ts +0 -809
- package/src/scanner.ts +0 -84
- package/src/transformer-compile-class.ts +0 -275
- package/test/advanced-features.test.ts +0 -911
- package/test/arbitrary.test.ts +0 -396
- package/test/attributify.test.ts +0 -592
- package/test/bracket-syntax.test.ts +0 -1133
- package/test/build.test.ts +0 -99
- package/test/colors.test.ts +0 -934
- package/test/flexbox.test.ts +0 -669
- package/test/generator.test.ts +0 -597
- package/test/grid.test.ts +0 -584
- package/test/layout.test.ts +0 -404
- package/test/modifiers.test.ts +0 -417
- package/test/parser.test.ts +0 -564
- package/test/performance-regression.test.ts +0 -376
- package/test/performance.test.ts +0 -568
- package/test/plugin.test.ts +0 -160
- package/test/scanner.test.ts +0 -94
- package/test/sizing.test.ts +0 -481
- package/test/spacing.test.ts +0 -394
- package/test/transformer-compile-class.test.ts +0 -287
- package/test/transforms.test.ts +0 -448
- package/test/typography.test.ts +0 -632
- package/test/variants-form-states.test.ts +0 -225
- package/test/variants-group-peer.test.ts +0 -66
- package/test/variants-media.test.ts +0 -213
- package/test/variants-positional.test.ts +0 -58
- package/test/variants-pseudo-elements.test.ts +0 -47
- package/test/variants-state.test.ts +0 -62
- package/tsconfig.json +0 -18
|
@@ -1,850 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { bench, group, run } from 'mitata'
|
|
3
|
-
import { CSSGenerator } from '../src/generator'
|
|
4
|
-
import { defaultConfig } from '../src/config'
|
|
5
|
-
|
|
6
|
-
// UnoCSS setup
|
|
7
|
-
import { createGenerator } from '@unocss/core'
|
|
8
|
-
import presetWind from '@unocss/preset-wind'
|
|
9
|
-
|
|
10
|
-
// Tailwind CSS v3 setup
|
|
11
|
-
import postcss from 'postcss'
|
|
12
|
-
import tailwindcss from 'tailwindcss'
|
|
13
|
-
|
|
14
|
-
// Tailwind CSS v4 setup
|
|
15
|
-
import tailwindcssV4 from '@tailwindcss/postcss'
|
|
16
|
-
|
|
17
|
-
// Initialize UnoCSS generator
|
|
18
|
-
const unoGen = await createGenerator({
|
|
19
|
-
presets: [presetWind()],
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
// Initialize Tailwind CSS v3 processor
|
|
23
|
-
const tailwindV3Processor = postcss([
|
|
24
|
-
tailwindcss({
|
|
25
|
-
content: [{ raw: '', extension: 'html' }],
|
|
26
|
-
corePlugins: { preflight: false },
|
|
27
|
-
}),
|
|
28
|
-
])
|
|
29
|
-
|
|
30
|
-
// Initialize Tailwind CSS v4 processor
|
|
31
|
-
const tailwindV4Processor = postcss([tailwindcssV4()])
|
|
32
|
-
|
|
33
|
-
// =============================================================================
|
|
34
|
-
// VALID UTILITY CLASS SETS
|
|
35
|
-
// All classes below are valid Tailwind CSS classes
|
|
36
|
-
// =============================================================================
|
|
37
|
-
|
|
38
|
-
// Simple utilities - basic layout, spacing, colors
|
|
39
|
-
const simpleUtilities = [
|
|
40
|
-
'w-4', 'h-4', 'p-4', 'm-4', 'text-lg', 'bg-blue-500',
|
|
41
|
-
'flex', 'items-center', 'justify-between', 'rounded-lg',
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
// Complex utilities with responsive and state variants
|
|
45
|
-
const complexUtilities = [
|
|
46
|
-
'sm:w-full', 'md:w-1/2', 'lg:w-1/3', 'xl:w-1/4',
|
|
47
|
-
'hover:bg-blue-600', 'focus:ring-2', 'active:scale-95',
|
|
48
|
-
'dark:bg-gray-800', 'dark:text-white',
|
|
49
|
-
'sm:hover:bg-blue-500', 'md:dark:text-gray-200',
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
// Arbitrary values - bracket notation
|
|
53
|
-
const arbitraryValues = [
|
|
54
|
-
'w-[123px]', 'h-[456px]', 'text-[#ff0000]', 'p-[2rem]',
|
|
55
|
-
'bg-[#1a1a1a]', 'm-[10%]', 'shadow-[0_4px_6px_rgba(0,0,0,0.1)]',
|
|
56
|
-
'top-[50%]', 'left-[calc(100%-2rem)]', 'grid-cols-[1fr_2fr_1fr]',
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
// Real-world component class combinations (as arrays for proper testing)
|
|
60
|
-
const realWorldComponents = [
|
|
61
|
-
// Card component
|
|
62
|
-
['flex', 'items-center', 'justify-between', 'p-4', 'bg-white', 'dark:bg-gray-800', 'rounded-lg', 'shadow-md'],
|
|
63
|
-
// Container
|
|
64
|
-
['w-full', 'max-w-md', 'mx-auto', 'space-y-4', 'sm:space-y-6'],
|
|
65
|
-
// Heading
|
|
66
|
-
['text-lg', 'font-semibold', 'text-gray-900', 'dark:text-white', 'tracking-tight'],
|
|
67
|
-
// Grid layout
|
|
68
|
-
['grid', 'grid-cols-1', 'md:grid-cols-2', 'lg:grid-cols-3', 'gap-4', 'p-6'],
|
|
69
|
-
// Interactive button
|
|
70
|
-
['px-4', 'py-2', 'bg-blue-500', 'hover:bg-blue-600', 'text-white', 'rounded-md', 'transition-colors', 'duration-200'],
|
|
71
|
-
// Form input
|
|
72
|
-
['w-full', 'px-3', 'py-2', 'border', 'border-gray-300', 'rounded-md', 'focus:ring-2', 'focus:ring-blue-500', 'focus:border-transparent'],
|
|
73
|
-
// Navigation item
|
|
74
|
-
['flex', 'items-center', 'gap-2', 'px-4', 'py-2', 'text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100', 'rounded-lg'],
|
|
75
|
-
// Badge
|
|
76
|
-
['inline-flex', 'items-center', 'px-2', 'py-1', 'text-xs', 'font-medium', 'bg-green-100', 'text-green-800', 'rounded-full'],
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
// Valid spacing values (Tailwind's actual spacing scale)
|
|
80
|
-
const validSpacingValues = [
|
|
81
|
-
'0', 'px', '0.5', '1', '1.5', '2', '2.5', '3', '3.5', '4', '5', '6', '7', '8', '9', '10',
|
|
82
|
-
'11', '12', '14', '16', '20', '24', '28', '32', '36', '40', '44', '48', '52', '56', '60',
|
|
83
|
-
'64', '72', '80', '96',
|
|
84
|
-
]
|
|
85
|
-
|
|
86
|
-
// Valid width/height values (includes fractions and special values)
|
|
87
|
-
const validSizeValues = [
|
|
88
|
-
...validSpacingValues,
|
|
89
|
-
'auto', 'full', 'screen', 'min', 'max', 'fit',
|
|
90
|
-
'1/2', '1/3', '2/3', '1/4', '2/4', '3/4',
|
|
91
|
-
'1/5', '2/5', '3/5', '4/5',
|
|
92
|
-
'1/6', '2/6', '3/6', '4/6', '5/6',
|
|
93
|
-
]
|
|
94
|
-
|
|
95
|
-
// Valid color shades
|
|
96
|
-
const validShades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950']
|
|
97
|
-
|
|
98
|
-
// Color names
|
|
99
|
-
const colorNames = ['slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose']
|
|
100
|
-
|
|
101
|
-
// Typography utilities
|
|
102
|
-
const typographyUtilities = [
|
|
103
|
-
// Font sizes
|
|
104
|
-
'text-xs', 'text-sm', 'text-base', 'text-lg', 'text-xl', 'text-2xl', 'text-3xl', 'text-4xl',
|
|
105
|
-
// Font weights
|
|
106
|
-
'font-thin', 'font-light', 'font-normal', 'font-medium', 'font-semibold', 'font-bold', 'font-extrabold',
|
|
107
|
-
// Letter spacing
|
|
108
|
-
'tracking-tighter', 'tracking-tight', 'tracking-normal', 'tracking-wide', 'tracking-wider', 'tracking-widest',
|
|
109
|
-
// Line height
|
|
110
|
-
'leading-none', 'leading-tight', 'leading-snug', 'leading-normal', 'leading-relaxed', 'leading-loose',
|
|
111
|
-
// Text alignment
|
|
112
|
-
'text-left', 'text-center', 'text-right', 'text-justify',
|
|
113
|
-
// Text decoration
|
|
114
|
-
'underline', 'overline', 'line-through', 'no-underline',
|
|
115
|
-
// Text transform
|
|
116
|
-
'uppercase', 'lowercase', 'capitalize', 'normal-case',
|
|
117
|
-
// Whitespace
|
|
118
|
-
'whitespace-normal', 'whitespace-nowrap', 'whitespace-pre', 'whitespace-pre-line', 'whitespace-pre-wrap',
|
|
119
|
-
// Word break
|
|
120
|
-
'break-normal', 'break-words', 'break-all',
|
|
121
|
-
]
|
|
122
|
-
|
|
123
|
-
// Flexbox utilities
|
|
124
|
-
const flexboxUtilities = [
|
|
125
|
-
// Display
|
|
126
|
-
'flex', 'inline-flex',
|
|
127
|
-
// Direction
|
|
128
|
-
'flex-row', 'flex-row-reverse', 'flex-col', 'flex-col-reverse',
|
|
129
|
-
// Wrap
|
|
130
|
-
'flex-wrap', 'flex-wrap-reverse', 'flex-nowrap',
|
|
131
|
-
// Flex values
|
|
132
|
-
'flex-1', 'flex-auto', 'flex-initial', 'flex-none',
|
|
133
|
-
// Grow/Shrink
|
|
134
|
-
'grow', 'grow-0', 'shrink', 'shrink-0',
|
|
135
|
-
// Justify content
|
|
136
|
-
'justify-start', 'justify-end', 'justify-center', 'justify-between', 'justify-around', 'justify-evenly',
|
|
137
|
-
// Align items
|
|
138
|
-
'items-start', 'items-end', 'items-center', 'items-baseline', 'items-stretch',
|
|
139
|
-
// Align content
|
|
140
|
-
'content-start', 'content-end', 'content-center', 'content-between', 'content-around', 'content-evenly',
|
|
141
|
-
// Align self
|
|
142
|
-
'self-auto', 'self-start', 'self-end', 'self-center', 'self-stretch',
|
|
143
|
-
// Gap
|
|
144
|
-
'gap-0', 'gap-1', 'gap-2', 'gap-4', 'gap-6', 'gap-8',
|
|
145
|
-
'gap-x-4', 'gap-y-4',
|
|
146
|
-
]
|
|
147
|
-
|
|
148
|
-
// Grid utilities
|
|
149
|
-
const gridUtilities = [
|
|
150
|
-
// Display
|
|
151
|
-
'grid', 'inline-grid',
|
|
152
|
-
// Grid template columns
|
|
153
|
-
'grid-cols-1', 'grid-cols-2', 'grid-cols-3', 'grid-cols-4', 'grid-cols-5', 'grid-cols-6',
|
|
154
|
-
'grid-cols-12', 'grid-cols-none',
|
|
155
|
-
// Grid template rows
|
|
156
|
-
'grid-rows-1', 'grid-rows-2', 'grid-rows-3', 'grid-rows-4', 'grid-rows-5', 'grid-rows-6', 'grid-rows-none',
|
|
157
|
-
// Grid column span
|
|
158
|
-
'col-auto', 'col-span-1', 'col-span-2', 'col-span-3', 'col-span-4', 'col-span-6', 'col-span-12', 'col-span-full',
|
|
159
|
-
// Grid row span
|
|
160
|
-
'row-auto', 'row-span-1', 'row-span-2', 'row-span-3', 'row-span-4', 'row-span-6', 'row-span-full',
|
|
161
|
-
// Grid flow
|
|
162
|
-
'grid-flow-row', 'grid-flow-col', 'grid-flow-row-dense', 'grid-flow-col-dense',
|
|
163
|
-
// Auto columns/rows
|
|
164
|
-
'auto-cols-auto', 'auto-cols-min', 'auto-cols-max', 'auto-cols-fr',
|
|
165
|
-
'auto-rows-auto', 'auto-rows-min', 'auto-rows-max', 'auto-rows-fr',
|
|
166
|
-
// Place content/items/self
|
|
167
|
-
'place-content-center', 'place-content-start', 'place-content-end',
|
|
168
|
-
'place-items-center', 'place-items-start', 'place-items-end',
|
|
169
|
-
'place-self-center', 'place-self-start', 'place-self-end',
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
// Stacked/chained variants (multiple variants combined)
|
|
173
|
-
const stackedVariants = [
|
|
174
|
-
// Responsive + state
|
|
175
|
-
'sm:hover:bg-blue-500', 'md:hover:bg-blue-600', 'lg:hover:bg-blue-700',
|
|
176
|
-
'sm:focus:ring-2', 'md:focus:ring-4', 'lg:focus:ring-8',
|
|
177
|
-
// Responsive + dark mode
|
|
178
|
-
'sm:dark:bg-gray-800', 'md:dark:bg-gray-900', 'lg:dark:bg-black',
|
|
179
|
-
'sm:dark:text-white', 'md:dark:text-gray-100', 'lg:dark:text-gray-200',
|
|
180
|
-
// Dark mode + state
|
|
181
|
-
'dark:hover:bg-gray-700', 'dark:focus:ring-blue-400', 'dark:active:bg-gray-600',
|
|
182
|
-
// Triple stacked: responsive + dark + state
|
|
183
|
-
'sm:dark:hover:bg-gray-600', 'md:dark:hover:bg-gray-700', 'lg:dark:hover:bg-gray-800',
|
|
184
|
-
'sm:dark:focus:ring-2', 'md:dark:focus:ring-4',
|
|
185
|
-
// Group variants
|
|
186
|
-
'group-hover:opacity-100', 'group-hover:visible', 'group-hover:scale-105',
|
|
187
|
-
'group-focus:ring-2', 'group-focus:border-blue-500',
|
|
188
|
-
// Peer variants
|
|
189
|
-
'peer-focus:ring-2', 'peer-checked:bg-blue-500', 'peer-invalid:border-red-500',
|
|
190
|
-
// First/last/odd/even
|
|
191
|
-
'first:pt-0', 'last:pb-0', 'odd:bg-gray-50', 'even:bg-white',
|
|
192
|
-
'first:rounded-t-lg', 'last:rounded-b-lg',
|
|
193
|
-
// Responsive + first/last
|
|
194
|
-
'sm:first:pt-0', 'md:last:pb-0', 'lg:odd:bg-gray-100',
|
|
195
|
-
]
|
|
196
|
-
|
|
197
|
-
// Transform and transition utilities
|
|
198
|
-
const transformUtilities = [
|
|
199
|
-
// Scale
|
|
200
|
-
'scale-0', 'scale-50', 'scale-75', 'scale-90', 'scale-95', 'scale-100', 'scale-105', 'scale-110', 'scale-125', 'scale-150',
|
|
201
|
-
'scale-x-100', 'scale-y-100',
|
|
202
|
-
// Rotate
|
|
203
|
-
'rotate-0', 'rotate-1', 'rotate-2', 'rotate-3', 'rotate-6', 'rotate-12', 'rotate-45', 'rotate-90', 'rotate-180',
|
|
204
|
-
'-rotate-1', '-rotate-2', '-rotate-3', '-rotate-6', '-rotate-12', '-rotate-45', '-rotate-90', '-rotate-180',
|
|
205
|
-
// Translate
|
|
206
|
-
'translate-x-0', 'translate-x-1', 'translate-x-2', 'translate-x-4', 'translate-x-full', '-translate-x-full',
|
|
207
|
-
'translate-y-0', 'translate-y-1', 'translate-y-2', 'translate-y-4', 'translate-y-full', '-translate-y-full',
|
|
208
|
-
// Skew
|
|
209
|
-
'skew-x-0', 'skew-x-1', 'skew-x-2', 'skew-x-3', 'skew-x-6', 'skew-x-12',
|
|
210
|
-
'skew-y-0', 'skew-y-1', 'skew-y-2', 'skew-y-3', 'skew-y-6', 'skew-y-12',
|
|
211
|
-
// Origin
|
|
212
|
-
'origin-center', 'origin-top', 'origin-top-right', 'origin-right', 'origin-bottom-right',
|
|
213
|
-
'origin-bottom', 'origin-bottom-left', 'origin-left', 'origin-top-left',
|
|
214
|
-
]
|
|
215
|
-
|
|
216
|
-
const transitionUtilities = [
|
|
217
|
-
// Transition property
|
|
218
|
-
'transition-none', 'transition-all', 'transition', 'transition-colors', 'transition-opacity', 'transition-shadow', 'transition-transform',
|
|
219
|
-
// Duration
|
|
220
|
-
'duration-75', 'duration-100', 'duration-150', 'duration-200', 'duration-300', 'duration-500', 'duration-700', 'duration-1000',
|
|
221
|
-
// Timing function
|
|
222
|
-
'ease-linear', 'ease-in', 'ease-out', 'ease-in-out',
|
|
223
|
-
// Delay
|
|
224
|
-
'delay-75', 'delay-100', 'delay-150', 'delay-200', 'delay-300', 'delay-500', 'delay-700', 'delay-1000',
|
|
225
|
-
// Animation
|
|
226
|
-
'animate-none', 'animate-spin', 'animate-ping', 'animate-pulse', 'animate-bounce',
|
|
227
|
-
]
|
|
228
|
-
|
|
229
|
-
// Border and ring utilities
|
|
230
|
-
const borderUtilities = [
|
|
231
|
-
// Border width
|
|
232
|
-
'border', 'border-0', 'border-2', 'border-4', 'border-8',
|
|
233
|
-
'border-t', 'border-r', 'border-b', 'border-l',
|
|
234
|
-
'border-t-0', 'border-r-0', 'border-b-0', 'border-l-0',
|
|
235
|
-
'border-t-2', 'border-r-2', 'border-b-2', 'border-l-2',
|
|
236
|
-
// Border style
|
|
237
|
-
'border-solid', 'border-dashed', 'border-dotted', 'border-double', 'border-none',
|
|
238
|
-
// Border radius
|
|
239
|
-
'rounded-none', 'rounded-sm', 'rounded', 'rounded-md', 'rounded-lg', 'rounded-xl', 'rounded-2xl', 'rounded-3xl', 'rounded-full',
|
|
240
|
-
'rounded-t-lg', 'rounded-r-lg', 'rounded-b-lg', 'rounded-l-lg',
|
|
241
|
-
'rounded-tl-lg', 'rounded-tr-lg', 'rounded-br-lg', 'rounded-bl-lg',
|
|
242
|
-
// Ring
|
|
243
|
-
'ring-0', 'ring-1', 'ring-2', 'ring-4', 'ring-8', 'ring',
|
|
244
|
-
'ring-inset',
|
|
245
|
-
// Ring offset
|
|
246
|
-
'ring-offset-0', 'ring-offset-1', 'ring-offset-2', 'ring-offset-4', 'ring-offset-8',
|
|
247
|
-
]
|
|
248
|
-
|
|
249
|
-
// Shadow and opacity utilities
|
|
250
|
-
const effectUtilities = [
|
|
251
|
-
// Box shadow
|
|
252
|
-
'shadow-sm', 'shadow', 'shadow-md', 'shadow-lg', 'shadow-xl', 'shadow-2xl', 'shadow-inner', 'shadow-none',
|
|
253
|
-
// Opacity
|
|
254
|
-
'opacity-0', 'opacity-5', 'opacity-10', 'opacity-20', 'opacity-25', 'opacity-30', 'opacity-40', 'opacity-50',
|
|
255
|
-
'opacity-60', 'opacity-70', 'opacity-75', 'opacity-80', 'opacity-90', 'opacity-95', 'opacity-100',
|
|
256
|
-
// Mix blend mode
|
|
257
|
-
'mix-blend-normal', 'mix-blend-multiply', 'mix-blend-screen', 'mix-blend-overlay',
|
|
258
|
-
// Background blend mode
|
|
259
|
-
'bg-blend-normal', 'bg-blend-multiply', 'bg-blend-screen', 'bg-blend-overlay',
|
|
260
|
-
]
|
|
261
|
-
|
|
262
|
-
// =============================================================================
|
|
263
|
-
// BENCHMARK HELPERS
|
|
264
|
-
// =============================================================================
|
|
265
|
-
|
|
266
|
-
async function benchmarkUnoCSS(classes: string[]): Promise<void> {
|
|
267
|
-
await unoGen.generate(classes.join(' '))
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
async function benchmarkTailwindV3(classes: string[]): Promise<void> {
|
|
271
|
-
const classString = classes.join(' ')
|
|
272
|
-
const css = `
|
|
273
|
-
@tailwind utilities;
|
|
274
|
-
@layer utilities {
|
|
275
|
-
.test { @apply ${classString}; }
|
|
276
|
-
}
|
|
277
|
-
`
|
|
278
|
-
await tailwindV3Processor.process(css, { from: undefined })
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async function benchmarkTailwindV4(classes: string[]): Promise<void> {
|
|
282
|
-
const selectors = classes.map(cls =>
|
|
283
|
-
`.${cls.replace(/:/g, '\\:').replace(/\[/g, '\\[').replace(/]/g, '\\]').replace(/\//g, '\\/').replace(/\./g, '\\.').replace(/-\\/g, '-\\\\')}`
|
|
284
|
-
).join(',\n')
|
|
285
|
-
|
|
286
|
-
const css = `
|
|
287
|
-
@tailwind utilities;
|
|
288
|
-
|
|
289
|
-
${selectors} {
|
|
290
|
-
/* Trigger utility generation */
|
|
291
|
-
}
|
|
292
|
-
`
|
|
293
|
-
await tailwindV4Processor.process(css, { from: undefined })
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function benchmarkCrosswind(classes: string[]): void {
|
|
297
|
-
const gen = new CSSGenerator(defaultConfig)
|
|
298
|
-
for (const cls of classes) {
|
|
299
|
-
gen.generate(cls)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function benchmarkCrosswindWithOutput(classes: string[]): string {
|
|
304
|
-
const gen = new CSSGenerator(defaultConfig)
|
|
305
|
-
for (const cls of classes) {
|
|
306
|
-
gen.generate(cls)
|
|
307
|
-
}
|
|
308
|
-
return gen.toCSS(false)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// =============================================================================
|
|
312
|
-
// BENCHMARKS
|
|
313
|
-
// =============================================================================
|
|
314
|
-
|
|
315
|
-
// 1. Simple utilities benchmark
|
|
316
|
-
group('Simple Utilities (10 classes)', () => {
|
|
317
|
-
bench('Crosswind', () => {
|
|
318
|
-
benchmarkCrosswind(simpleUtilities)
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
bench('UnoCSS', async () => {
|
|
322
|
-
await benchmarkUnoCSS(simpleUtilities)
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
bench('Tailwind CSS v3', async () => {
|
|
326
|
-
await benchmarkTailwindV3(simpleUtilities)
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
bench('Tailwind CSS v4', async () => {
|
|
330
|
-
await benchmarkTailwindV4(simpleUtilities)
|
|
331
|
-
})
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
// 2. Complex utilities with variants benchmark
|
|
335
|
-
group('Complex Utilities with Variants (11 classes)', () => {
|
|
336
|
-
bench('Crosswind', () => {
|
|
337
|
-
benchmarkCrosswind(complexUtilities)
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
bench('UnoCSS', async () => {
|
|
341
|
-
await benchmarkUnoCSS(complexUtilities)
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
bench('Tailwind CSS v3', async () => {
|
|
345
|
-
await benchmarkTailwindV3(complexUtilities)
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
bench('Tailwind CSS v4', async () => {
|
|
349
|
-
await benchmarkTailwindV4(complexUtilities)
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
// 3. Arbitrary values benchmark
|
|
354
|
-
group('Arbitrary Values (10 classes)', () => {
|
|
355
|
-
bench('Crosswind', () => {
|
|
356
|
-
benchmarkCrosswind(arbitraryValues)
|
|
357
|
-
})
|
|
358
|
-
|
|
359
|
-
bench('UnoCSS', async () => {
|
|
360
|
-
await benchmarkUnoCSS(arbitraryValues)
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
bench('Tailwind CSS v3', async () => {
|
|
364
|
-
await benchmarkTailwindV3(arbitraryValues)
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
bench('Tailwind CSS v4', async () => {
|
|
368
|
-
await benchmarkTailwindV4(arbitraryValues)
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
// 4. Real-world component classes (FIXED: properly splits class strings)
|
|
373
|
-
group('Real-world Components (8 components, ~60 classes)', () => {
|
|
374
|
-
const allClasses = realWorldComponents.flat()
|
|
375
|
-
|
|
376
|
-
bench('Crosswind', () => {
|
|
377
|
-
const gen = new CSSGenerator(defaultConfig)
|
|
378
|
-
for (const cls of allClasses) {
|
|
379
|
-
gen.generate(cls)
|
|
380
|
-
}
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
bench('UnoCSS', async () => {
|
|
384
|
-
await unoGen.generate(allClasses.join(' '))
|
|
385
|
-
})
|
|
386
|
-
|
|
387
|
-
bench('Tailwind CSS v3', async () => {
|
|
388
|
-
await benchmarkTailwindV3(allClasses)
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
bench('Tailwind CSS v4', async () => {
|
|
392
|
-
await benchmarkTailwindV4(allClasses)
|
|
393
|
-
})
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
// 5. Large scale with VALID classes
|
|
397
|
-
group('Large Scale: Valid Utilities (500 classes)', () => {
|
|
398
|
-
const largeSet: string[] = []
|
|
399
|
-
|
|
400
|
-
// Width utilities with valid values
|
|
401
|
-
for (const size of validSizeValues.slice(0, 25)) {
|
|
402
|
-
largeSet.push(`w-${size}`)
|
|
403
|
-
}
|
|
404
|
-
// Height utilities with valid values
|
|
405
|
-
for (const size of validSizeValues.slice(0, 25)) {
|
|
406
|
-
largeSet.push(`h-${size}`)
|
|
407
|
-
}
|
|
408
|
-
// Padding utilities with valid values
|
|
409
|
-
for (const size of validSpacingValues) {
|
|
410
|
-
largeSet.push(`p-${size}`)
|
|
411
|
-
}
|
|
412
|
-
// Margin utilities with valid values
|
|
413
|
-
for (const size of validSpacingValues) {
|
|
414
|
-
largeSet.push(`m-${size}`)
|
|
415
|
-
}
|
|
416
|
-
// Gap utilities
|
|
417
|
-
for (const size of validSpacingValues.slice(0, 20)) {
|
|
418
|
-
largeSet.push(`gap-${size}`)
|
|
419
|
-
}
|
|
420
|
-
// Padding x/y
|
|
421
|
-
for (const size of validSpacingValues.slice(0, 20)) {
|
|
422
|
-
largeSet.push(`px-${size}`, `py-${size}`)
|
|
423
|
-
}
|
|
424
|
-
// Margin x/y
|
|
425
|
-
for (const size of validSpacingValues.slice(0, 20)) {
|
|
426
|
-
largeSet.push(`mx-${size}`, `my-${size}`)
|
|
427
|
-
}
|
|
428
|
-
// Top/right/bottom/left
|
|
429
|
-
for (const size of validSpacingValues.slice(0, 15)) {
|
|
430
|
-
largeSet.push(`top-${size}`, `right-${size}`, `bottom-${size}`, `left-${size}`)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
bench('Crosswind', () => {
|
|
434
|
-
benchmarkCrosswind(largeSet)
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
bench('UnoCSS', async () => {
|
|
438
|
-
await benchmarkUnoCSS(largeSet)
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
bench('Tailwind CSS v3', async () => {
|
|
442
|
-
await benchmarkTailwindV3(largeSet)
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
bench('Tailwind CSS v4', async () => {
|
|
446
|
-
await benchmarkTailwindV4(largeSet)
|
|
447
|
-
})
|
|
448
|
-
})
|
|
449
|
-
|
|
450
|
-
// 6. CSS output generation benchmark
|
|
451
|
-
group('CSS Output Generation (1000 arbitrary values)', () => {
|
|
452
|
-
const utilities: string[] = []
|
|
453
|
-
for (let i = 0; i < 1000; i++) {
|
|
454
|
-
utilities.push(`w-[${i}px]`)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
bench('Crosswind', () => {
|
|
458
|
-
benchmarkCrosswindWithOutput(utilities)
|
|
459
|
-
})
|
|
460
|
-
|
|
461
|
-
bench('UnoCSS', async () => {
|
|
462
|
-
const result = await unoGen.generate(utilities.join(' '))
|
|
463
|
-
result.css
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
bench('Tailwind CSS v3', async () => {
|
|
467
|
-
await benchmarkTailwindV3(utilities)
|
|
468
|
-
})
|
|
469
|
-
|
|
470
|
-
bench('Tailwind CSS v4', async () => {
|
|
471
|
-
await benchmarkTailwindV4(utilities)
|
|
472
|
-
})
|
|
473
|
-
})
|
|
474
|
-
|
|
475
|
-
// 7. Color utilities benchmark (VALID shades)
|
|
476
|
-
group('Color Utilities (330 classes)', () => {
|
|
477
|
-
const colorUtilities: string[] = []
|
|
478
|
-
|
|
479
|
-
// Use subset of colors to keep benchmark reasonable
|
|
480
|
-
const colors = ['gray', 'red', 'blue', 'green', 'yellow', 'purple', 'pink', 'indigo', 'cyan', 'emerald']
|
|
481
|
-
|
|
482
|
-
for (const color of colors) {
|
|
483
|
-
for (const shade of validShades) {
|
|
484
|
-
colorUtilities.push(`bg-${color}-${shade}`)
|
|
485
|
-
colorUtilities.push(`text-${color}-${shade}`)
|
|
486
|
-
colorUtilities.push(`border-${color}-${shade}`)
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
bench('Crosswind', () => {
|
|
491
|
-
benchmarkCrosswind(colorUtilities)
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
bench('UnoCSS', async () => {
|
|
495
|
-
await benchmarkUnoCSS(colorUtilities)
|
|
496
|
-
})
|
|
497
|
-
|
|
498
|
-
bench('Tailwind CSS v3', async () => {
|
|
499
|
-
await benchmarkTailwindV3(colorUtilities)
|
|
500
|
-
})
|
|
501
|
-
|
|
502
|
-
bench('Tailwind CSS v4', async () => {
|
|
503
|
-
await benchmarkTailwindV4(colorUtilities)
|
|
504
|
-
})
|
|
505
|
-
})
|
|
506
|
-
|
|
507
|
-
// 8. Responsive utilities with VALID values
|
|
508
|
-
group('Responsive Utilities (500 classes)', () => {
|
|
509
|
-
const breakpoints = ['sm', 'md', 'lg', 'xl', '2xl']
|
|
510
|
-
const responsiveUtilities: string[] = []
|
|
511
|
-
|
|
512
|
-
// Valid width values with responsive prefixes
|
|
513
|
-
for (const bp of breakpoints) {
|
|
514
|
-
for (const size of validSizeValues.slice(0, 20)) {
|
|
515
|
-
responsiveUtilities.push(`${bp}:w-${size}`)
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
// Valid padding values with responsive prefixes
|
|
519
|
-
for (const bp of breakpoints) {
|
|
520
|
-
for (const size of validSpacingValues.slice(0, 15)) {
|
|
521
|
-
responsiveUtilities.push(`${bp}:p-${size}`)
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// Text sizes with responsive prefixes
|
|
525
|
-
const textSizes = ['xs', 'sm', 'base', 'lg', 'xl', '2xl', '3xl', '4xl']
|
|
526
|
-
for (const bp of breakpoints) {
|
|
527
|
-
for (const size of textSizes) {
|
|
528
|
-
responsiveUtilities.push(`${bp}:text-${size}`)
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
bench('Crosswind', () => {
|
|
533
|
-
benchmarkCrosswind(responsiveUtilities)
|
|
534
|
-
})
|
|
535
|
-
|
|
536
|
-
bench('UnoCSS', async () => {
|
|
537
|
-
await benchmarkUnoCSS(responsiveUtilities)
|
|
538
|
-
})
|
|
539
|
-
|
|
540
|
-
bench('Tailwind CSS v3', async () => {
|
|
541
|
-
await benchmarkTailwindV3(responsiveUtilities)
|
|
542
|
-
})
|
|
543
|
-
|
|
544
|
-
bench('Tailwind CSS v4', async () => {
|
|
545
|
-
await benchmarkTailwindV4(responsiveUtilities)
|
|
546
|
-
})
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
// 9. Interactive states with VALID color shades
|
|
550
|
-
group('Interactive States (440 classes)', () => {
|
|
551
|
-
const states = ['hover', 'focus', 'active', 'disabled', 'first', 'last', 'odd', 'even', 'dark', 'group-hover', 'peer-focus']
|
|
552
|
-
const stateUtilities: string[] = []
|
|
553
|
-
|
|
554
|
-
// Colors with valid shades
|
|
555
|
-
const colors = ['blue', 'gray', 'red', 'green']
|
|
556
|
-
for (const state of states) {
|
|
557
|
-
for (const color of colors) {
|
|
558
|
-
for (const shade of validShades) {
|
|
559
|
-
stateUtilities.push(`${state}:bg-${color}-${shade}`)
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
bench('Crosswind', () => {
|
|
565
|
-
benchmarkCrosswind(stateUtilities)
|
|
566
|
-
})
|
|
567
|
-
|
|
568
|
-
bench('UnoCSS', async () => {
|
|
569
|
-
await benchmarkUnoCSS(stateUtilities)
|
|
570
|
-
})
|
|
571
|
-
|
|
572
|
-
bench('Tailwind CSS v3', async () => {
|
|
573
|
-
await benchmarkTailwindV3(stateUtilities)
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
bench('Tailwind CSS v4', async () => {
|
|
577
|
-
await benchmarkTailwindV4(stateUtilities)
|
|
578
|
-
})
|
|
579
|
-
})
|
|
580
|
-
|
|
581
|
-
// 10. Duplicate handling benchmark
|
|
582
|
-
group('Duplicate Handling (6 classes x 1000 times)', () => {
|
|
583
|
-
const duplicates = ['w-4', 'h-4', 'p-4', 'm-4', 'text-lg', 'bg-blue-500']
|
|
584
|
-
const manyDuplicates: string[] = []
|
|
585
|
-
for (let i = 0; i < 1000; i++) {
|
|
586
|
-
manyDuplicates.push(...duplicates)
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
bench('Crosswind', () => {
|
|
590
|
-
benchmarkCrosswind(manyDuplicates)
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
bench('UnoCSS', async () => {
|
|
594
|
-
await benchmarkUnoCSS(manyDuplicates)
|
|
595
|
-
})
|
|
596
|
-
|
|
597
|
-
bench('Tailwind CSS v3', async () => {
|
|
598
|
-
await benchmarkTailwindV3(manyDuplicates)
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
bench('Tailwind CSS v4', async () => {
|
|
602
|
-
await benchmarkTailwindV4(manyDuplicates)
|
|
603
|
-
})
|
|
604
|
-
})
|
|
605
|
-
|
|
606
|
-
// 11. Typography utilities benchmark (NEW)
|
|
607
|
-
group('Typography Utilities (50 classes)', () => {
|
|
608
|
-
bench('Crosswind', () => {
|
|
609
|
-
benchmarkCrosswind(typographyUtilities)
|
|
610
|
-
})
|
|
611
|
-
|
|
612
|
-
bench('UnoCSS', async () => {
|
|
613
|
-
await benchmarkUnoCSS(typographyUtilities)
|
|
614
|
-
})
|
|
615
|
-
|
|
616
|
-
bench('Tailwind CSS v3', async () => {
|
|
617
|
-
await benchmarkTailwindV3(typographyUtilities)
|
|
618
|
-
})
|
|
619
|
-
|
|
620
|
-
bench('Tailwind CSS v4', async () => {
|
|
621
|
-
await benchmarkTailwindV4(typographyUtilities)
|
|
622
|
-
})
|
|
623
|
-
})
|
|
624
|
-
|
|
625
|
-
// 12. Flexbox utilities benchmark (NEW)
|
|
626
|
-
group('Flexbox Utilities (50 classes)', () => {
|
|
627
|
-
bench('Crosswind', () => {
|
|
628
|
-
benchmarkCrosswind(flexboxUtilities)
|
|
629
|
-
})
|
|
630
|
-
|
|
631
|
-
bench('UnoCSS', async () => {
|
|
632
|
-
await benchmarkUnoCSS(flexboxUtilities)
|
|
633
|
-
})
|
|
634
|
-
|
|
635
|
-
bench('Tailwind CSS v3', async () => {
|
|
636
|
-
await benchmarkTailwindV3(flexboxUtilities)
|
|
637
|
-
})
|
|
638
|
-
|
|
639
|
-
bench('Tailwind CSS v4', async () => {
|
|
640
|
-
await benchmarkTailwindV4(flexboxUtilities)
|
|
641
|
-
})
|
|
642
|
-
})
|
|
643
|
-
|
|
644
|
-
// 13. Grid utilities benchmark (NEW)
|
|
645
|
-
group('Grid Utilities (55 classes)', () => {
|
|
646
|
-
bench('Crosswind', () => {
|
|
647
|
-
benchmarkCrosswind(gridUtilities)
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
bench('UnoCSS', async () => {
|
|
651
|
-
await benchmarkUnoCSS(gridUtilities)
|
|
652
|
-
})
|
|
653
|
-
|
|
654
|
-
bench('Tailwind CSS v3', async () => {
|
|
655
|
-
await benchmarkTailwindV3(gridUtilities)
|
|
656
|
-
})
|
|
657
|
-
|
|
658
|
-
bench('Tailwind CSS v4', async () => {
|
|
659
|
-
await benchmarkTailwindV4(gridUtilities)
|
|
660
|
-
})
|
|
661
|
-
})
|
|
662
|
-
|
|
663
|
-
// 14. Stacked/chained variants benchmark (NEW)
|
|
664
|
-
group('Stacked Variants (40 classes)', () => {
|
|
665
|
-
bench('Crosswind', () => {
|
|
666
|
-
benchmarkCrosswind(stackedVariants)
|
|
667
|
-
})
|
|
668
|
-
|
|
669
|
-
bench('UnoCSS', async () => {
|
|
670
|
-
await benchmarkUnoCSS(stackedVariants)
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
bench('Tailwind CSS v3', async () => {
|
|
674
|
-
await benchmarkTailwindV3(stackedVariants)
|
|
675
|
-
})
|
|
676
|
-
|
|
677
|
-
bench('Tailwind CSS v4', async () => {
|
|
678
|
-
await benchmarkTailwindV4(stackedVariants)
|
|
679
|
-
})
|
|
680
|
-
})
|
|
681
|
-
|
|
682
|
-
// 15. Transform utilities benchmark (NEW)
|
|
683
|
-
group('Transform Utilities (55 classes)', () => {
|
|
684
|
-
bench('Crosswind', () => {
|
|
685
|
-
benchmarkCrosswind(transformUtilities)
|
|
686
|
-
})
|
|
687
|
-
|
|
688
|
-
bench('UnoCSS', async () => {
|
|
689
|
-
await benchmarkUnoCSS(transformUtilities)
|
|
690
|
-
})
|
|
691
|
-
|
|
692
|
-
bench('Tailwind CSS v3', async () => {
|
|
693
|
-
await benchmarkTailwindV3(transformUtilities)
|
|
694
|
-
})
|
|
695
|
-
|
|
696
|
-
bench('Tailwind CSS v4', async () => {
|
|
697
|
-
await benchmarkTailwindV4(transformUtilities)
|
|
698
|
-
})
|
|
699
|
-
})
|
|
700
|
-
|
|
701
|
-
// 16. Transition utilities benchmark (NEW)
|
|
702
|
-
group('Transition & Animation (30 classes)', () => {
|
|
703
|
-
bench('Crosswind', () => {
|
|
704
|
-
benchmarkCrosswind(transitionUtilities)
|
|
705
|
-
})
|
|
706
|
-
|
|
707
|
-
bench('UnoCSS', async () => {
|
|
708
|
-
await benchmarkUnoCSS(transitionUtilities)
|
|
709
|
-
})
|
|
710
|
-
|
|
711
|
-
bench('Tailwind CSS v3', async () => {
|
|
712
|
-
await benchmarkTailwindV3(transitionUtilities)
|
|
713
|
-
})
|
|
714
|
-
|
|
715
|
-
bench('Tailwind CSS v4', async () => {
|
|
716
|
-
await benchmarkTailwindV4(transitionUtilities)
|
|
717
|
-
})
|
|
718
|
-
})
|
|
719
|
-
|
|
720
|
-
// 17. Border utilities benchmark (NEW)
|
|
721
|
-
group('Border & Ring Utilities (45 classes)', () => {
|
|
722
|
-
bench('Crosswind', () => {
|
|
723
|
-
benchmarkCrosswind(borderUtilities)
|
|
724
|
-
})
|
|
725
|
-
|
|
726
|
-
bench('UnoCSS', async () => {
|
|
727
|
-
await benchmarkUnoCSS(borderUtilities)
|
|
728
|
-
})
|
|
729
|
-
|
|
730
|
-
bench('Tailwind CSS v3', async () => {
|
|
731
|
-
await benchmarkTailwindV3(borderUtilities)
|
|
732
|
-
})
|
|
733
|
-
|
|
734
|
-
bench('Tailwind CSS v4', async () => {
|
|
735
|
-
await benchmarkTailwindV4(borderUtilities)
|
|
736
|
-
})
|
|
737
|
-
})
|
|
738
|
-
|
|
739
|
-
// 18. Effects utilities benchmark (NEW)
|
|
740
|
-
group('Shadow & Effects (35 classes)', () => {
|
|
741
|
-
bench('Crosswind', () => {
|
|
742
|
-
benchmarkCrosswind(effectUtilities)
|
|
743
|
-
})
|
|
744
|
-
|
|
745
|
-
bench('UnoCSS', async () => {
|
|
746
|
-
await benchmarkUnoCSS(effectUtilities)
|
|
747
|
-
})
|
|
748
|
-
|
|
749
|
-
bench('Tailwind CSS v3', async () => {
|
|
750
|
-
await benchmarkTailwindV3(effectUtilities)
|
|
751
|
-
})
|
|
752
|
-
|
|
753
|
-
bench('Tailwind CSS v4', async () => {
|
|
754
|
-
await benchmarkTailwindV4(effectUtilities)
|
|
755
|
-
})
|
|
756
|
-
})
|
|
757
|
-
|
|
758
|
-
// 19. Incremental generation benchmark (NEW - tests caching efficiency)
|
|
759
|
-
group('Incremental Generation (add 100 classes to existing 100)', () => {
|
|
760
|
-
const initialClasses = simpleUtilities.concat(complexUtilities).concat(typographyUtilities.slice(0, 30))
|
|
761
|
-
const additionalClasses = flexboxUtilities.concat(gridUtilities.slice(0, 20)).concat(borderUtilities.slice(0, 30))
|
|
762
|
-
|
|
763
|
-
bench('Crosswind', () => {
|
|
764
|
-
const gen = new CSSGenerator(defaultConfig)
|
|
765
|
-
// Generate initial classes
|
|
766
|
-
for (const cls of initialClasses) {
|
|
767
|
-
gen.generate(cls)
|
|
768
|
-
}
|
|
769
|
-
// Add more classes (tests incremental efficiency)
|
|
770
|
-
for (const cls of additionalClasses) {
|
|
771
|
-
gen.generate(cls)
|
|
772
|
-
}
|
|
773
|
-
})
|
|
774
|
-
|
|
775
|
-
bench('UnoCSS', async () => {
|
|
776
|
-
// UnoCSS handles this in one call
|
|
777
|
-
await unoGen.generate(initialClasses.concat(additionalClasses).join(' '))
|
|
778
|
-
})
|
|
779
|
-
|
|
780
|
-
bench('Tailwind CSS v3', async () => {
|
|
781
|
-
await benchmarkTailwindV3(initialClasses.concat(additionalClasses))
|
|
782
|
-
})
|
|
783
|
-
|
|
784
|
-
bench('Tailwind CSS v4', async () => {
|
|
785
|
-
await benchmarkTailwindV4(initialClasses.concat(additionalClasses))
|
|
786
|
-
})
|
|
787
|
-
})
|
|
788
|
-
|
|
789
|
-
// 20. Full realistic project simulation (NEW)
|
|
790
|
-
group('Full Project Simulation (~800 unique classes)', () => {
|
|
791
|
-
// Simulate a real project with diverse utility usage
|
|
792
|
-
const projectClasses = [
|
|
793
|
-
...simpleUtilities,
|
|
794
|
-
...complexUtilities,
|
|
795
|
-
...arbitraryValues,
|
|
796
|
-
...realWorldComponents.flat(),
|
|
797
|
-
...typographyUtilities,
|
|
798
|
-
...flexboxUtilities,
|
|
799
|
-
...gridUtilities,
|
|
800
|
-
...stackedVariants,
|
|
801
|
-
...transformUtilities.slice(0, 30),
|
|
802
|
-
...transitionUtilities,
|
|
803
|
-
...borderUtilities,
|
|
804
|
-
...effectUtilities,
|
|
805
|
-
]
|
|
806
|
-
|
|
807
|
-
// Add color utilities
|
|
808
|
-
const colors = ['gray', 'blue', 'red', 'green']
|
|
809
|
-
for (const color of colors) {
|
|
810
|
-
for (const shade of validShades) {
|
|
811
|
-
projectClasses.push(`bg-${color}-${shade}`, `text-${color}-${shade}`)
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// Add responsive variants
|
|
816
|
-
const breakpoints = ['sm', 'md', 'lg']
|
|
817
|
-
for (const bp of breakpoints) {
|
|
818
|
-
projectClasses.push(
|
|
819
|
-
`${bp}:w-full`, `${bp}:flex`, `${bp}:hidden`, `${bp}:block`,
|
|
820
|
-
`${bp}:text-lg`, `${bp}:p-4`, `${bp}:grid-cols-2`
|
|
821
|
-
)
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
bench('Crosswind', () => {
|
|
825
|
-
benchmarkCrosswindWithOutput(projectClasses)
|
|
826
|
-
})
|
|
827
|
-
|
|
828
|
-
bench('UnoCSS', async () => {
|
|
829
|
-
const result = await unoGen.generate(projectClasses.join(' '))
|
|
830
|
-
result.css
|
|
831
|
-
})
|
|
832
|
-
|
|
833
|
-
bench('Tailwind CSS v3', async () => {
|
|
834
|
-
await benchmarkTailwindV3(projectClasses)
|
|
835
|
-
})
|
|
836
|
-
|
|
837
|
-
bench('Tailwind CSS v4', async () => {
|
|
838
|
-
await benchmarkTailwindV4(projectClasses)
|
|
839
|
-
})
|
|
840
|
-
})
|
|
841
|
-
|
|
842
|
-
console.log('\nš Running Comprehensive Framework Comparison Benchmarks...\n')
|
|
843
|
-
console.log('Comparing: Crosswind vs UnoCSS vs Tailwind CSS v3 vs Tailwind CSS v4')
|
|
844
|
-
console.log('All benchmarks use VALID Tailwind CSS utility classes\n')
|
|
845
|
-
|
|
846
|
-
await run({
|
|
847
|
-
colors: true,
|
|
848
|
-
})
|
|
849
|
-
|
|
850
|
-
console.log('\n⨠Benchmark completed!\n')
|