@tenphi/tasty 3.4.0 → 3.6.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/README.md +147 -129
- package/dist/astro-CzY4LCpr.js +437 -0
- package/dist/astro-CzY4LCpr.js.map +1 -0
- package/dist/{babel-BUQGeOXA.d.ts → babel-DWCsafYw.d.ts} +2 -2
- package/dist/{collector-DUaHCcTS.d.ts → collector-BTVXj2hS.d.ts} +21 -3
- package/dist/{collector-DTahQUiV.js → collector-C6TtL8HJ.js} +36 -13
- package/dist/collector-C6TtL8HJ.js.map +1 -0
- package/dist/{config-B5kHzuNz.js → config-B3gPdCqd.js} +305 -153
- package/dist/config-B3gPdCqd.js.map +1 -0
- package/dist/{config-YsxGv4tq.d.ts → config-LfIDmVHx.d.ts} +132 -32
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +6 -6
- package/dist/{core-Dr4u1NVD.js → core-Bq7w2kti.js} +215 -95
- package/dist/core-Bq7w2kti.js.map +1 -0
- package/dist/{css-writer-B-J87ncv.js → css-writer-Bgowobbx.js} +3 -3
- package/dist/{css-writer-B-J87ncv.js.map → css-writer-Bgowobbx.js.map} +1 -1
- package/dist/{format-rules-DKOA-6qu.js → format-rules-rCZ37rqY.js} +2 -2
- package/dist/format-rules-rCZ37rqY.js.map +1 -0
- package/dist/{hydrate-OeMX99We.js → hydrate-CNOmZprz.js} +3 -3
- package/dist/{hydrate-OeMX99We.js.map → hydrate-CNOmZprz.js.map} +1 -1
- package/dist/{index-PqN-DIpn.d.ts → index-Bm9ltvdH.d.ts} +38 -16
- package/dist/{index-Cd45t5NM.d.ts → index-BmogEzTo.d.ts} +69 -15
- package/dist/index.d.ts +5 -5
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/{keyframes-CV8azJf3.js → keyframes-DE-OE76F.js} +45 -3
- package/dist/keyframes-DE-OE76F.js.map +1 -0
- package/dist/{merge-styles-CU7JbEwg.d.ts → merge-styles-BcLl1u_d.d.ts} +2 -2
- package/dist/{merge-styles-oklji0KB.js → merge-styles-DuoZEsm9.js} +2 -2
- package/dist/{merge-styles-oklji0KB.js.map → merge-styles-DuoZEsm9.js.map} +1 -1
- package/dist/{resolve-recipes-DTG81rzl.js → resolve-recipes-H9NqOQuP.js} +3 -3
- package/dist/{resolve-recipes-DTG81rzl.js.map → resolve-recipes-H9NqOQuP.js.map} +1 -1
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro-middleware-extract-static.d.ts +11 -0
- package/dist/ssr/astro-middleware-extract-static.js +9 -0
- package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
- package/dist/ssr/astro-middleware-extract.d.ts +11 -0
- package/dist/ssr/astro-middleware-extract.js +9 -0
- package/dist/ssr/astro-middleware-extract.js.map +1 -0
- package/dist/ssr/astro-middleware-static.d.ts +3 -1
- package/dist/ssr/astro-middleware-static.js +1 -1
- package/dist/ssr/astro-middleware.d.ts +3 -1
- package/dist/ssr/astro-middleware.js +1 -1
- package/dist/ssr/astro.d.ts +45 -3
- package/dist/ssr/astro.js +1 -156
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.js +3 -3
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +1 -1
- package/dist/ssr/next.js +4 -4
- package/dist/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +4 -4
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +1 -1
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +1 -1
- package/docs/README.md +13 -8
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +78 -77
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +97 -87
- package/docs/debug.md +4 -2
- package/docs/design-system.md +41 -22
- package/docs/dsl.md +225 -195
- package/docs/getting-started.md +60 -39
- package/docs/injector.md +63 -26
- package/docs/methodology.md +42 -36
- package/docs/migration-v3.md +49 -49
- package/docs/plugins.md +37 -33
- package/docs/react-api.md +65 -44
- package/docs/runtime-benchmarks.md +178 -0
- package/docs/ssr.md +124 -61
- package/docs/styles.md +1 -1
- package/docs/tasty-static.md +137 -104
- package/package.json +26 -8
- package/dist/collector-DTahQUiV.js.map +0 -1
- package/dist/config-B5kHzuNz.js.map +0 -1
- package/dist/core-Dr4u1NVD.js.map +0 -1
- package/dist/format-rules-DKOA-6qu.js.map +0 -1
- package/dist/keyframes-CV8azJf3.js.map +0 -1
- package/dist/ssr/astro.js.map +0 -1
package/docs/tasty-static.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Build-Time Extraction (`tastyStatic`)
|
|
2
2
|
|
|
3
|
-
`tastyStatic` is
|
|
3
|
+
`tastyStatic` is Tasty's framework-agnostic build-time utility for extracting CSS before rendering. It produces no client styling runtime in file mode, but it is not the only way to achieve zero-runtime delivery: server-only `tasty()` also ships no Tasty runtime to the browser while retaining the full React component API. Astro's `tastyIntegration({ islands: false })` is the clearest example; the same architecture applies to server-only Next.js RSC.
|
|
4
|
+
|
|
5
|
+
Choose `tastyStatic` specifically when styles must be generated during the build, when the consumer is not React, or when you want static class-name objects instead of components. For the broader docs map, see the [Docs Hub](README.md).
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
@@ -8,19 +10,19 @@
|
|
|
8
10
|
|
|
9
11
|
- **Static site generation (SSG)** — Pre-render all styles at build time
|
|
10
12
|
- **No-JavaScript websites** — CSS works without any JS runtime
|
|
11
|
-
- **Performance-critical pages** —
|
|
13
|
+
- **Performance-critical pages** — CSS extracted before the application renders
|
|
12
14
|
- **Landing pages** — Minimal bundle size with pre-generated CSS
|
|
13
15
|
|
|
14
16
|
## Requirements
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Build-time extraction is part of the main `@tenphi/tasty` package but requires additional peer dependencies depending on your setup:
|
|
17
19
|
|
|
18
|
-
| Dependency
|
|
19
|
-
|
|
20
|
-
| `@babel/core`
|
|
21
|
-
| `@babel/helper-plugin-utils` | >= 7.24 | Babel plugin
|
|
22
|
-
| `@babel/types`
|
|
23
|
-
| `jiti`
|
|
20
|
+
| Dependency | Version | Required for |
|
|
21
|
+
| ---------------------------- | ------- | -------------------------------------------------------------------------- |
|
|
22
|
+
| `@babel/core` | >= 7.24 | Babel plugin (`@tenphi/tasty/babel-plugin`) |
|
|
23
|
+
| `@babel/helper-plugin-utils` | >= 7.24 | Babel plugin |
|
|
24
|
+
| `@babel/types` | >= 7.24 | Babel plugin |
|
|
25
|
+
| `jiti` | >= 2.6 | Next.js wrapper (`@tenphi/tasty/zero/next`) when using `configFile` option |
|
|
24
26
|
|
|
25
27
|
All of these are declared as optional peer dependencies of `@tenphi/tasty`. Install only what your setup requires:
|
|
26
28
|
|
|
@@ -107,11 +109,11 @@ tastyStatic('body', {
|
|
|
107
109
|
|
|
108
110
|
## StaticStyle Object
|
|
109
111
|
|
|
110
|
-
| Property
|
|
111
|
-
|
|
112
|
-
| `className`
|
|
113
|
-
| `styles`
|
|
114
|
-
| `toString()` | `() => string` | Returns `className` for string coercion
|
|
112
|
+
| Property | Type | Description |
|
|
113
|
+
| ------------ | -------------- | ------------------------------------------ |
|
|
114
|
+
| `className` | `string` | Space-separated class names for use in JSX |
|
|
115
|
+
| `styles` | `Styles` | The original (or merged) styles object |
|
|
116
|
+
| `toString()` | `() => string` | Returns `className` for string coercion |
|
|
115
117
|
|
|
116
118
|
---
|
|
117
119
|
|
|
@@ -123,67 +125,73 @@ tastyStatic('body', {
|
|
|
123
125
|
// babel.config.js
|
|
124
126
|
module.exports = {
|
|
125
127
|
plugins: [
|
|
126
|
-
[
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
[
|
|
129
|
+
'@tenphi/tasty/babel-plugin',
|
|
130
|
+
{
|
|
131
|
+
output: 'public/tasty.css',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
],
|
|
130
135
|
};
|
|
131
136
|
```
|
|
132
137
|
|
|
133
|
-
These examples use `data-schema="dark"` as the root-state convention. If your app already uses a different root attribute such as `data-theme`, keep the same alias pattern and swap the attribute name consistently in your
|
|
138
|
+
These examples use `data-schema="dark"` as the root-state convention. If your app already uses a different root attribute such as `data-theme`, keep the same alias pattern and swap the attribute name consistently in your build-time config.
|
|
134
139
|
|
|
135
140
|
### With Configuration
|
|
136
141
|
|
|
137
142
|
```javascript
|
|
138
143
|
module.exports = {
|
|
139
144
|
plugins: [
|
|
140
|
-
[
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
[
|
|
146
|
+
'@tenphi/tasty/babel-plugin',
|
|
147
|
+
{
|
|
148
|
+
output: 'public/tasty.css',
|
|
149
|
+
config: {
|
|
150
|
+
states: {
|
|
151
|
+
'@mobile': '@media(w < 768px)',
|
|
152
|
+
'@tablet': '@media(w < 1024px)',
|
|
153
|
+
'@dark': '@root(schema=dark)',
|
|
154
|
+
},
|
|
155
|
+
devMode: true,
|
|
147
156
|
},
|
|
148
|
-
devMode: true,
|
|
149
157
|
},
|
|
150
|
-
|
|
151
|
-
]
|
|
158
|
+
],
|
|
159
|
+
],
|
|
152
160
|
};
|
|
153
161
|
```
|
|
154
162
|
|
|
155
163
|
### Plugin Options
|
|
156
164
|
|
|
157
|
-
| Option
|
|
158
|
-
|
|
159
|
-
| `output`
|
|
160
|
-
| `mode`
|
|
161
|
-
| `configFile`
|
|
162
|
-
| `config`
|
|
163
|
-
| `configDeps`
|
|
164
|
-
| `injectImport`
|
|
165
|
-
| `config.states`
|
|
166
|
-
| `config.devMode`
|
|
167
|
-
| `config.tokens`
|
|
168
|
-
| `config.replaceTokens`
|
|
169
|
-
| `config.recipes`
|
|
170
|
-
| `config.keyframes`
|
|
171
|
-
| `config.fontFaces`
|
|
172
|
-
| `config.counterStyles`
|
|
173
|
-
| `config.units`
|
|
174
|
-
| `config.functions`
|
|
175
|
-
| `config.polyfills`
|
|
176
|
-
| `config.plugins`
|
|
177
|
-
| `config.handlers`
|
|
178
|
-
| `config.presets`
|
|
179
|
-
| `config.globalStyles`
|
|
180
|
-
| `config.autoPropertyTypes` | `boolean`
|
|
181
|
-
| `config.parserCacheSize`
|
|
182
|
-
| `config.namePrefix`
|
|
183
|
-
|
|
184
|
-
### Coexisting with
|
|
185
|
-
|
|
186
|
-
When a page mixes `tastyStatic` with
|
|
165
|
+
| Option | Type | Default | Description |
|
|
166
|
+
| -------------------------- | ------------------------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
167
|
+
| `output` | `string` | `'tasty.css'` | Path for generated CSS file |
|
|
168
|
+
| `mode` | `'file' \| 'inject'` | `'file'` | `'file'` writes CSS to disk; `'inject'` embeds CSS inline in JS (see [Inject Mode](#inject-mode)) |
|
|
169
|
+
| `configFile` | `string` | — | Absolute path to a TS/JS module that default-exports a `TastyZeroConfig` object. JSON-serializable alternative to `config` — required for Turbopack. |
|
|
170
|
+
| `config` | `TastyZeroConfig \| () => TastyZeroConfig` | `{}` | Inline config object or factory function. Takes precedence over `configFile`. |
|
|
171
|
+
| `configDeps` | `string[]` | `[]` | Absolute file paths that affect config (for cache invalidation) |
|
|
172
|
+
| `injectImport` | `boolean` | `true` | Replace `@tenphi/tasty/static` imports with an import of the generated CSS file. Set to `false` to manage CSS imports manually. |
|
|
173
|
+
| `config.states` | `Record<string, string>` | `{}` | Predefined state aliases (e.g. `{ '@mobile': '@media(w < 768px)' }`) |
|
|
174
|
+
| `config.devMode` | `boolean` | `false` | Add source comments to CSS |
|
|
175
|
+
| `config.tokens` | `ConfigTokens` | — | Design tokens injected as CSS custom properties on `:root`. Values are parsed through the Tasty DSL. Supports state maps for responsive/themed tokens. |
|
|
176
|
+
| `config.replaceTokens` | `Record<string, string \| number>` | — | Parse-time token substitution. Keys use `$name` for custom properties and `#name` for color tokens. |
|
|
177
|
+
| `config.recipes` | `Record<string, RecipeStyles>` | `{}` | Predefined style recipes |
|
|
178
|
+
| `config.keyframes` | `Record<string, KeyframesSteps>` | — | Global `@keyframes` definitions available to all `tastyStatic` calls |
|
|
179
|
+
| `config.fontFaces` | `Record<string, FontFaceInput>` | — | Global `@font-face` definitions |
|
|
180
|
+
| `config.counterStyles` | `Record<string, CounterStyleDescriptors>` | — | Global `@counter-style` definitions |
|
|
181
|
+
| `config.units` | `Record<string, string \| UnitHandler>` | — | Custom units for the style parser (merged with built-ins). E.g. `{ em: 'em', vw: 'vw' }` |
|
|
182
|
+
| `config.functions` | `Record<string, FunctionDefinition \| Function>` | — | Custom functions (merged). Bare keys → parse functions; `$$name` keys → declarative CSS `@function` definitions |
|
|
183
|
+
| `config.polyfills` | `{ functions?: boolean }` | `{}` | Opt-in polyfills. `functions: true` inlines `@function` calls into plain CSS at build time |
|
|
184
|
+
| `config.plugins` | `TastyPlugin[]` | — | Plugins that extend tasty with custom functions, units, states, and handlers |
|
|
185
|
+
| `config.handlers` | `Record<string, StyleHandlerDefinition>` | — | Custom style handlers that transform style properties into CSS declarations |
|
|
186
|
+
| `config.presets` | `Record<string, TypographyPreset>` | — | Typography presets — shorthand for `generateTypographyTokens()`. Generated tokens merge under explicit `tokens`. |
|
|
187
|
+
| `config.globalStyles` | `Record<string, Styles>` | — | Global Tasty styles keyed by CSS selector. Supports the full style syntax. |
|
|
188
|
+
| `config.autoPropertyTypes` | `boolean` | `true` | Automatically infer and register CSS `@property` declarations from values |
|
|
189
|
+
| `config.parserCacheSize` | `number` | `1000` | Parser LRU cache size. Larger values improve performance for builds with many unique style values |
|
|
190
|
+
| `config.namePrefix` | `string` | `'ts'` | Prefix prepended to every generated identifier. Defaults to `'ts'` so static classes never collide with runtime (`'t'`) classes. See [Configuration: Name prefix](configuration.md#name-prefix). |
|
|
191
|
+
|
|
192
|
+
### Coexisting with `tasty()`
|
|
193
|
+
|
|
194
|
+
When a page mixes `tastyStatic` with `tasty`, both must use **different** `namePrefix` values. The defaults handle this automatically (`'t'` for React rendering, `'ts'` for build-time extraction). If you customize one, customize the other:
|
|
187
195
|
|
|
188
196
|
```ts
|
|
189
197
|
// tasty-zero.config.ts (Babel plugin)
|
|
@@ -191,7 +199,7 @@ export default { namePrefix: 'mbs' };
|
|
|
191
199
|
```
|
|
192
200
|
|
|
193
201
|
```ts
|
|
194
|
-
// app entry (
|
|
202
|
+
// app entry (`tasty()` configure)
|
|
195
203
|
configure({ namePrefix: 'mb' });
|
|
196
204
|
```
|
|
197
205
|
|
|
@@ -205,16 +213,24 @@ Recipes work with `tastyStatic` the same way as with runtime `tasty`:
|
|
|
205
213
|
// babel.config.js
|
|
206
214
|
module.exports = {
|
|
207
215
|
plugins: [
|
|
208
|
-
[
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
[
|
|
217
|
+
'@tenphi/tasty/babel-plugin',
|
|
218
|
+
{
|
|
219
|
+
output: 'public/tasty.css',
|
|
220
|
+
config: {
|
|
221
|
+
recipes: {
|
|
222
|
+
card: {
|
|
223
|
+
padding: '4x',
|
|
224
|
+
fill: '#surface',
|
|
225
|
+
radius: '1r',
|
|
226
|
+
border: true,
|
|
227
|
+
},
|
|
228
|
+
elevated: { shadow: '2x 2x 4x #shadow' },
|
|
229
|
+
},
|
|
214
230
|
},
|
|
215
231
|
},
|
|
216
|
-
|
|
217
|
-
]
|
|
232
|
+
],
|
|
233
|
+
],
|
|
218
234
|
};
|
|
219
235
|
```
|
|
220
236
|
|
|
@@ -226,7 +242,7 @@ const card = tastyStatic({
|
|
|
226
242
|
color: '#text',
|
|
227
243
|
});
|
|
228
244
|
|
|
229
|
-
<div className={card}>Styled card</div
|
|
245
|
+
<div className={card}>Styled card</div>;
|
|
230
246
|
```
|
|
231
247
|
|
|
232
248
|
---
|
|
@@ -250,14 +266,14 @@ export default withTastyZero({
|
|
|
250
266
|
|
|
251
267
|
### `withTastyZero` Options
|
|
252
268
|
|
|
253
|
-
| Option
|
|
254
|
-
|
|
255
|
-
| `output`
|
|
256
|
-
| `mode`
|
|
257
|
-
| `enabled`
|
|
258
|
-
| `configFile` | `string`
|
|
259
|
-
| `config`
|
|
260
|
-
| `configDeps` | `string[]`
|
|
269
|
+
| Option | Type | Default | Description |
|
|
270
|
+
| ------------ | -------------------- | -------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
271
|
+
| `output` | `string` | `'public/tasty.css'` | Output path for CSS relative to project root |
|
|
272
|
+
| `mode` | `'file' \| 'inject'` | `'file'` | `'file'` writes CSS to disk; `'inject'` embeds CSS inline in JS |
|
|
273
|
+
| `enabled` | `boolean` | `true` | Enable/disable the plugin |
|
|
274
|
+
| `configFile` | `string` | — | Path to a TS/JS module that default-exports `TastyZeroConfig`. Recommended for Turbopack compatibility. |
|
|
275
|
+
| `config` | `TastyZeroConfig` | — | Inline config object. For static configs that don't change during dev. |
|
|
276
|
+
| `configDeps` | `string[]` | `[]` | Extra files the config depends on (for cache invalidation) |
|
|
261
277
|
|
|
262
278
|
### Turbopack Support
|
|
263
279
|
|
|
@@ -295,12 +311,15 @@ export default defineConfig({
|
|
|
295
311
|
react({
|
|
296
312
|
babel: {
|
|
297
313
|
plugins: [
|
|
298
|
-
[
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
[
|
|
315
|
+
'@tenphi/tasty/babel-plugin',
|
|
316
|
+
{
|
|
317
|
+
output: 'public/tasty.css',
|
|
318
|
+
config: {
|
|
319
|
+
states: { '@mobile': '@media(w < 768px)' },
|
|
320
|
+
},
|
|
302
321
|
},
|
|
303
|
-
|
|
322
|
+
],
|
|
304
323
|
],
|
|
305
324
|
},
|
|
306
325
|
}),
|
|
@@ -334,7 +353,9 @@ export const Button = () => <button className={button}>Click</button>;
|
|
|
334
353
|
const button = {
|
|
335
354
|
className: 'ts3f2a1b ts8c4d2e',
|
|
336
355
|
styles: { padding: '2x 4x', fill: '#purple', color: '#white' },
|
|
337
|
-
toString() {
|
|
356
|
+
toString() {
|
|
357
|
+
return this.className;
|
|
358
|
+
},
|
|
338
359
|
};
|
|
339
360
|
|
|
340
361
|
export const Button = () => <button className={button}>Click</button>;
|
|
@@ -382,13 +403,16 @@ This is ideal for **reusable components**, **extensions**, and **libraries** whe
|
|
|
382
403
|
// babel.config.js
|
|
383
404
|
module.exports = {
|
|
384
405
|
plugins: [
|
|
385
|
-
[
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
406
|
+
[
|
|
407
|
+
'@tenphi/tasty/babel-plugin',
|
|
408
|
+
{
|
|
409
|
+
mode: 'inject',
|
|
410
|
+
config: {
|
|
411
|
+
states: { '@mobile': '@media(w < 768px)' },
|
|
412
|
+
},
|
|
389
413
|
},
|
|
390
|
-
|
|
391
|
-
]
|
|
414
|
+
],
|
|
415
|
+
],
|
|
392
416
|
};
|
|
393
417
|
```
|
|
394
418
|
|
|
@@ -428,13 +452,20 @@ tastyStatic('.heading', { preset: 'h1' });
|
|
|
428
452
|
```tsx
|
|
429
453
|
import { injectCSS as _$i } from '@tenphi/tasty/static/inject';
|
|
430
454
|
|
|
431
|
-
const button =
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
455
|
+
const button =
|
|
456
|
+
(_$i(
|
|
457
|
+
'ts3f2a1b ts8c4d2e',
|
|
458
|
+
'.ts3f2a1b.ts3f2a1b{padding:16px 32px}\n.ts8c4d2e.ts8c4d2e{background:#9370db}',
|
|
459
|
+
),
|
|
460
|
+
{
|
|
461
|
+
className: 'ts3f2a1b ts8c4d2e',
|
|
462
|
+
styles: { padding: '2x 4x', fill: '#purple' },
|
|
463
|
+
toString() {
|
|
464
|
+
return this.className;
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
_$i('.heading', '.heading{font-size:2.5rem;font-weight:700;line-height:1.2}');
|
|
438
469
|
```
|
|
439
470
|
|
|
440
471
|
### Dev Mode / HMR
|
|
@@ -443,7 +474,7 @@ Class names are content-hashed (`ts` + MD5). When styles change, a new hash prod
|
|
|
443
474
|
|
|
444
475
|
### Limitations (inject mode)
|
|
445
476
|
|
|
446
|
-
- **Client-side only** — Styles are injected via the DOM, so they are not available during SSR. For server-rendered apps, use `mode: 'file'` or
|
|
477
|
+
- **Client-side only** — Styles are injected via the DOM, so they are not available during SSR. For server-rendered apps, use `mode: 'file'` or React `tasty()`.
|
|
447
478
|
- **Larger JS bundle** — CSS is embedded in JavaScript, increasing bundle size. Best suited for components and extensions, not full-app styling.
|
|
448
479
|
|
|
449
480
|
---
|
|
@@ -512,13 +543,15 @@ For dynamic styling needs, combine with regular CSS or CSS variables:
|
|
|
512
543
|
```tsx
|
|
513
544
|
const card = tastyStatic({
|
|
514
545
|
padding: '4x',
|
|
515
|
-
fill: '
|
|
546
|
+
fill: '($card-bg, #white)',
|
|
516
547
|
});
|
|
517
548
|
|
|
518
549
|
<div
|
|
519
550
|
className={card}
|
|
520
|
-
style={{
|
|
521
|
-
|
|
551
|
+
style={{
|
|
552
|
+
'--card-bg': isActive ? 'var(--purple-color)' : 'var(--white-color)',
|
|
553
|
+
}}
|
|
554
|
+
/>;
|
|
522
555
|
```
|
|
523
556
|
|
|
524
557
|
---
|
|
@@ -535,15 +568,15 @@ const card = tastyStatic({
|
|
|
535
568
|
## Common Issues
|
|
536
569
|
|
|
537
570
|
- No CSS file is generated: make sure the Babel plugin actually runs for files importing `@tenphi/tasty/static`, and verify the `output` path is writable.
|
|
538
|
-
- Styles stay dynamic by mistake: `tastyStatic()` only supports build-time-known values. Move
|
|
571
|
+
- Styles stay dynamic by mistake: `tastyStatic()` only supports build-time-known values. Move dynamic values to CSS variables or switch that component to React `tasty()`.
|
|
539
572
|
- Turbopack config behaves inconsistently: prefer `configFile` over inline functions so the setup stays JSON-serializable.
|
|
540
573
|
|
|
541
574
|
---
|
|
542
575
|
|
|
543
576
|
## Related
|
|
544
577
|
|
|
545
|
-
- [Docs Hub](README.md) — Choose the right guide by task or
|
|
578
|
+
- [Docs Hub](README.md) — Choose the right guide by task or CSS delivery model
|
|
546
579
|
- [Style DSL](dsl.md) — State maps, tokens, units, extending semantics (shared by runtime and static)
|
|
547
|
-
- [React API](react-api.md) —
|
|
580
|
+
- [React API](react-api.md) — Client or server rendering with `tasty()`: component props, variants, sub-elements, and style functions
|
|
548
581
|
- [Configuration](configuration.md) — Global configuration: tokens, recipes, custom units, and style handlers
|
|
549
582
|
- [Plugins & Extension Points](plugins.md) — Which extension points work at build time (`functions`, `units`, `states`, `handlers`, `recipes`) and which do not (`propHandlers` — `tastyStatic()` takes styles objects, not props)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenphi/tasty",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -72,6 +72,16 @@
|
|
|
72
72
|
"import": "./dist/ssr/astro-middleware-static.js",
|
|
73
73
|
"default": "./dist/ssr/astro-middleware-static.js"
|
|
74
74
|
},
|
|
75
|
+
"./ssr/astro-middleware-extract": {
|
|
76
|
+
"types": "./dist/ssr/astro-middleware-extract.d.ts",
|
|
77
|
+
"import": "./dist/ssr/astro-middleware-extract.js",
|
|
78
|
+
"default": "./dist/ssr/astro-middleware-extract.js"
|
|
79
|
+
},
|
|
80
|
+
"./ssr/astro-middleware-extract-static": {
|
|
81
|
+
"types": "./dist/ssr/astro-middleware-extract-static.d.ts",
|
|
82
|
+
"import": "./dist/ssr/astro-middleware-extract-static.js",
|
|
83
|
+
"default": "./dist/ssr/astro-middleware-extract-static.js"
|
|
84
|
+
},
|
|
75
85
|
"./tasty.config": "./tasty.config.ts"
|
|
76
86
|
},
|
|
77
87
|
"files": [
|
|
@@ -85,7 +95,9 @@
|
|
|
85
95
|
"./dist/ssr/astro.js",
|
|
86
96
|
"./dist/ssr/astro-client.js",
|
|
87
97
|
"./dist/ssr/astro-middleware.js",
|
|
88
|
-
"./dist/ssr/astro-middleware-static.js"
|
|
98
|
+
"./dist/ssr/astro-middleware-static.js",
|
|
99
|
+
"./dist/ssr/astro-middleware-extract.js",
|
|
100
|
+
"./dist/ssr/astro-middleware-extract-static.js"
|
|
89
101
|
],
|
|
90
102
|
"engines": {
|
|
91
103
|
"node": ">=20"
|
|
@@ -143,6 +155,7 @@
|
|
|
143
155
|
"csstype": "^3.1.0"
|
|
144
156
|
},
|
|
145
157
|
"devDependencies": {
|
|
158
|
+
"@astrojs/react": "^4.4.2",
|
|
146
159
|
"@babel/core": "^7.24.0",
|
|
147
160
|
"@babel/helper-plugin-utils": "^7.24.0",
|
|
148
161
|
"@babel/types": "^7.24.0",
|
|
@@ -151,22 +164,25 @@
|
|
|
151
164
|
"@eslint/js": "^10.0.1",
|
|
152
165
|
"@size-limit/esbuild": "^12.0.0",
|
|
153
166
|
"@size-limit/file": "^12.0.0",
|
|
154
|
-
"@tenphi/eslint-plugin-tasty": "^0.
|
|
167
|
+
"@tenphi/eslint-plugin-tasty": "^1.0.5",
|
|
155
168
|
"@testing-library/jest-dom": "^6.9.1",
|
|
156
169
|
"@testing-library/react": "^16.3.2",
|
|
157
170
|
"@types/babel__core": "^7.20.5",
|
|
158
171
|
"@types/babel__helper-plugin-utils": "^7.10.3",
|
|
159
|
-
"@types/node": "^
|
|
172
|
+
"@types/node": "^24.13.3",
|
|
160
173
|
"@types/react": "^19.0.0",
|
|
174
|
+
"@types/react-dom": "^19.0.0",
|
|
161
175
|
"@vitest/browser-playwright": "^4.1.10",
|
|
176
|
+
"astro": "^5.18.2",
|
|
162
177
|
"eslint": "^10.0.0",
|
|
163
178
|
"eslint-config-prettier": "^10.1.8",
|
|
164
179
|
"jiti": "^2.6.1",
|
|
165
180
|
"knip": "^5.61.3",
|
|
166
181
|
"next": "^16.0.0",
|
|
167
182
|
"playwright": "^1.62.1",
|
|
168
|
-
"prettier": "^3.
|
|
183
|
+
"prettier": "^3.9.6",
|
|
169
184
|
"react": "^19.0.0",
|
|
185
|
+
"react-dom": "^19.0.0",
|
|
170
186
|
"size-limit": "^12.0.0",
|
|
171
187
|
"tsdown": "^0.22.0",
|
|
172
188
|
"typescript": "^6.0.2",
|
|
@@ -178,13 +194,13 @@
|
|
|
178
194
|
"name": "main (import *)",
|
|
179
195
|
"path": "dist/index.js",
|
|
180
196
|
"import": "*",
|
|
181
|
-
"limit": "
|
|
197
|
+
"limit": "57.5 kB"
|
|
182
198
|
},
|
|
183
199
|
{
|
|
184
200
|
"name": "core (import *)",
|
|
185
201
|
"path": "dist/core/index.js",
|
|
186
202
|
"import": "*",
|
|
187
|
-
"limit": "
|
|
203
|
+
"limit": "54.5 kB"
|
|
188
204
|
},
|
|
189
205
|
{
|
|
190
206
|
"name": "static",
|
|
@@ -212,7 +228,7 @@
|
|
|
212
228
|
"path",
|
|
213
229
|
"crypto"
|
|
214
230
|
],
|
|
215
|
-
"limit": "49.
|
|
231
|
+
"limit": "49.6 kB"
|
|
216
232
|
}
|
|
217
233
|
],
|
|
218
234
|
"scripts": {
|
|
@@ -231,6 +247,8 @@
|
|
|
231
247
|
"size": "size-limit",
|
|
232
248
|
"bench": "vitest bench --project node",
|
|
233
249
|
"bench:browser": "vitest bench --project browser",
|
|
250
|
+
"bench:overhead": "vitest bench --config vitest.production-browser-bench.config.ts src/tasty-overhead.bench.tsx",
|
|
251
|
+
"bench:injection": "vitest bench --config vitest.production-browser-bench.config.ts src/tasty-injection.bench.ts",
|
|
234
252
|
"changeset": "changeset",
|
|
235
253
|
"version": "changeset version",
|
|
236
254
|
"release": "changeset publish",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collector-DTahQUiV.js","names":[],"sources":["../src/ssr/collector.ts"],"sourcesContent":["/**\n * ServerStyleCollector — server-safe style collector for SSR.\n *\n * Accumulates CSS rules and cache metadata during server rendering.\n * This is the server-side counterpart to StyleInjector: it allocates\n * hash-based class names using the configured `namePrefix` (defaults\n * to `'t'`), formats CSS rules into text, and tracks rendered class\n * names for lightweight client transfer.\n *\n * One instance is created per HTTP request. Concurrent requests\n * each get their own collector (via AsyncLocalStorage or React context).\n */\n\nimport {\n getEffectiveProperties,\n getGlobalStyles,\n getGlobalCounterStyles,\n getGlobalFontFaces,\n getGlobalFunctions,\n getGlobalConfigTokens,\n getNamePrefix,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { formatFunctionRule, parseFunctionName } from '../functions';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport {\n makeClassName,\n makeCounterStyleName,\n makeKeyframeName,\n validateNamePrefix,\n} from '../utils/name-prefix';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nexport class ServerStyleCollector {\n private chunks = new Map<string, string>();\n private cacheKeyToClassName = new Map<string, string>();\n private flushedKeys = new Set<string>();\n private propertyRules = new Map<string, string>();\n private flushedPropertyKeys = new Set<string>();\n private keyframeRules = new Map<string, string>();\n private flushedKeyframeKeys = new Set<string>();\n private globalStyles = new Map<string, string>();\n private flushedGlobalKeys = new Set<string>();\n private rawCSS = new Map<string, string>();\n private flushedRawKeys = new Set<string>();\n private fontFaceRules = new Map<string, string>();\n private flushedFontFaceKeys = new Set<string>();\n private counterStyleRules = new Map<string, string>();\n private flushedCounterStyleKeys = new Set<string>();\n private functionRules = new Map<string, string>();\n private flushedFunctionKeys = new Set<string>();\n private keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\n private namePrefix: string;\n\n /**\n * @param namePrefix - Optional override for the configured prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n * Pass an explicit prefix when constructing a collector outside the\n * normal configure() lifecycle (e.g. in tests). Validated eagerly\n * so misconfiguration fails before any CSS is collected.\n */\n constructor(namePrefix?: string) {\n if (namePrefix !== undefined) {\n validateNamePrefix(namePrefix);\n }\n this.namePrefix = namePrefix ?? getNamePrefix();\n }\n\n private generateClassName(cacheKey: string): string {\n return makeClassName(this.namePrefix, hashString(cacheKey));\n }\n\n /**\n * Collect internal @property rules and :root token defaults.\n * Mirrors markStylesGenerated() from the client-side injector.\n * Called automatically on first chunk collection; idempotent.\n *\n * Internals are always emitted here — the RSC path deliberately\n * defers to SSR so that tokens appear exactly once per page in\n * <style data-tasty-ssr> (avoiding duplication of large token sets).\n */\n collectInternals(): void {\n if (this.internalsCollected) return;\n this.internalsCollected = true;\n\n for (const [token, definition] of Object.entries(\n getEffectiveProperties(),\n )) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n this.collectProperty(`__prop:${token}`, css);\n }\n }\n\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const tokenRules = renderStyles(tokenStyles, ':root') as StyleResult[];\n if (tokenRules.length > 0) {\n const css = formatGlobalRules(tokenRules);\n if (css) {\n this.collectGlobalStyles('__global:tokens', css);\n }\n }\n }\n\n const globalFF = getGlobalFontFaces();\n if (globalFF) {\n for (const [family, input] of Object.entries(globalFF)) {\n const descriptors = Array.isArray(input) ? input : [input];\n for (const desc of descriptors) {\n const hash = fontFaceContentHash(family, desc);\n const css = formatFontFaceRule(family, desc);\n this.collectFontFace(hash, css);\n }\n }\n }\n\n const globalCS = getGlobalCounterStyles();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css, { weak: true });\n }\n }\n\n const globalFn = getGlobalFunctions();\n if (globalFn) {\n for (const [name, definition] of Object.entries(globalFn)) {\n const css = formatFunctionRule(name, definition);\n this.collectFunction(parseFunctionName(name), css, { weak: true });\n }\n }\n\n const globalStyles = getGlobalStyles();\n if (globalStyles) {\n for (const [selector, styles] of Object.entries(globalStyles)) {\n if (Object.keys(styles).length > 0) {\n const rules = renderStyles(styles, selector) as StyleResult[];\n if (rules.length > 0) {\n const css = formatGlobalRules(rules);\n if (css) {\n this.collectGlobalStyles(`__global:styles:${selector}`, css);\n }\n }\n }\n }\n }\n }\n\n /**\n * Allocate a className for a cache key, server-side.\n * Mirrors StyleInjector.allocateClassName but without DOM access.\n */\n allocateClassName(cacheKey: string): {\n className: string;\n isNewAllocation: boolean;\n } {\n const existing = this.cacheKeyToClassName.get(cacheKey);\n if (existing) {\n return { className: existing, isNewAllocation: false };\n }\n\n const className = this.generateClassName(cacheKey);\n this.cacheKeyToClassName.set(cacheKey, className);\n\n return { className, isNewAllocation: true };\n }\n\n /**\n * Record CSS rules for a chunk.\n * Called by useStyles during server render.\n */\n collectChunk(\n cacheKey: string,\n className: string,\n rules: StyleResult[],\n ): void {\n if (this.chunks.has(cacheKey)) return;\n const css = formatRules(rules, className);\n if (css) {\n this.chunks.set(cacheKey, css);\n }\n }\n\n /**\n * Record a @property rule. Deduplicated by name.\n */\n collectProperty(name: string, css: string): void {\n if (!this.propertyRules.has(name)) {\n this.propertyRules.set(name, css);\n }\n }\n\n /**\n * Record a @keyframes rule. Deduplicated by name.\n */\n collectKeyframes(name: string, css: string): void {\n if (!this.keyframeRules.has(name)) {\n this.keyframeRules.set(name, css);\n }\n }\n\n /**\n * Allocate a keyframe name for SSR. Uses provided name or generates one.\n */\n allocateKeyframeName(providedName?: string): string {\n return (\n providedName ??\n makeKeyframeName(this.namePrefix, String(this.keyframesCounter++))\n );\n }\n\n /**\n * Record a @font-face rule. Deduplicated by key (content hash).\n */\n collectFontFace(key: string, css: string): void {\n if (!this.fontFaceRules.has(key)) {\n this.fontFaceRules.set(key, css);\n }\n }\n\n /**\n * Record a @counter-style rule. Deduplicated by name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectCounterStyle(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.counterStyleRules.get(name);\n if (existing === undefined) {\n this.counterStyleRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.counterStyleRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedCounterStyleKeys.delete(name);\n }\n\n /**\n * Record a @function rule. Deduplicated by CSS function name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectFunction(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.functionRules.get(name);\n if (existing === undefined) {\n this.functionRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.functionRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedFunctionKeys.delete(name);\n }\n\n /**\n * Allocate a counter-style name for SSR. Uses provided name or generates one.\n */\n allocateCounterStyleName(providedName?: string): string {\n return (\n providedName ??\n makeCounterStyleName(this.namePrefix, String(this.counterStyleCounter++))\n );\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectGlobalStyles(key: string, css: string, replace?: boolean): void {\n if (replace || !this.globalStyles.has(key)) {\n this.globalStyles.set(key, css);\n }\n }\n\n /**\n * Record raw CSS text (from useRawCSS). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectRawCSS(key: string, css: string, replace?: boolean): void {\n if (replace || !this.rawCSS.has(key)) {\n this.rawCSS.set(key, css);\n }\n }\n\n /**\n * Extract all CSS collected so far as a single string.\n * Includes @property and @keyframes rules.\n * Used for non-streaming SSR (renderToString).\n */\n getCSS(): string {\n const parts: string[] = [];\n\n for (const css of this.propertyRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.fontFaceRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.counterStyleRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.functionRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.rawCSS.values()) {\n parts.push(css);\n }\n\n for (const css of this.globalStyles.values()) {\n parts.push(css);\n }\n\n for (const css of this.chunks.values()) {\n parts.push(css);\n }\n\n for (const css of this.keyframeRules.values()) {\n parts.push(css);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Flush only newly collected CSS since the last flush.\n * Used for streaming SSR (renderToPipeableStream + useServerInsertedHTML).\n */\n flushCSS(): string {\n const parts: string[] = [];\n\n for (const [name, css] of this.propertyRules) {\n if (!this.flushedPropertyKeys.has(name)) {\n parts.push(css);\n this.flushedPropertyKeys.add(name);\n }\n }\n\n for (const [key, css] of this.fontFaceRules) {\n if (!this.flushedFontFaceKeys.has(key)) {\n parts.push(css);\n this.flushedFontFaceKeys.add(key);\n }\n }\n\n for (const [key, css] of this.counterStyleRules) {\n if (!this.flushedCounterStyleKeys.has(key)) {\n parts.push(css);\n this.flushedCounterStyleKeys.add(key);\n }\n }\n\n for (const [key, css] of this.functionRules) {\n if (!this.flushedFunctionKeys.has(key)) {\n parts.push(css);\n this.flushedFunctionKeys.add(key);\n }\n }\n\n for (const [key, css] of this.rawCSS) {\n if (!this.flushedRawKeys.has(key)) {\n parts.push(css);\n this.flushedRawKeys.add(key);\n }\n }\n\n for (const [key, css] of this.globalStyles) {\n if (!this.flushedGlobalKeys.has(key)) {\n parts.push(css);\n this.flushedGlobalKeys.add(key);\n }\n }\n\n for (const [key, css] of this.chunks) {\n if (!this.flushedKeys.has(key)) {\n parts.push(css);\n this.flushedKeys.add(key);\n }\n }\n\n for (const [name, css] of this.keyframeRules) {\n if (!this.flushedKeyframeKeys.has(name)) {\n parts.push(css);\n this.flushedKeyframeKeys.add(name);\n }\n }\n\n return parts.join('\\n');\n }\n\n private flushedClassNames = new Set<string>();\n\n /**\n * Return class names rendered since the last call (for streaming).\n * Used to emit lightweight class-list scripts for client hydration.\n */\n getRenderedClassNames(): string[] {\n const names: string[] = [];\n for (const className of this.cacheKeyToClassName.values()) {\n if (!this.flushedClassNames.has(className)) {\n this.flushedClassNames.add(className);\n names.push(className);\n }\n }\n return names;\n }\n}\n\n/**\n * Factory for creating a {@link ServerStyleCollector} instance.\n *\n * Canonical functional entry point; the `ServerStyleCollector` class remains\n * exported for advanced/internal use.\n *\n * @param namePrefix - Optional override for the configured class-name prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n *\n * @example\n * ```ts\n * import { createServerStyleCollector } from '@tenphi/tasty/ssr';\n *\n * const collector = createServerStyleCollector();\n * ```\n */\nexport function createServerStyleCollector(\n namePrefix?: string,\n): ServerStyleCollector {\n return new ServerStyleCollector(namePrefix);\n}\n"],"mappings":"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"}
|