Skip to content

Commit f37fd8d

Browse files
committed
fix: improve splitting
1 parent 0c0bcc0 commit f37fd8d

File tree

5 files changed

+135
-4
lines changed

5 files changed

+135
-4
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@pandacss/core': patch
3+
'@pandacss/generator': patch
4+
---
5+
6+
Fix `cssgen --splitting` not fully respecting `staticCss: { recipes: "*" }`.
7+
8+
- When `staticCss: { recipes: "*" }` is set globally, individual recipes with their own `staticCss` property would
9+
override the global wildcard, potentially omitting variants.
10+
11+
- Split CSS generation was missing recipes that only have base styles (no variants).

packages/core/__tests__/static-css.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,4 +2465,56 @@ describe('static-css caching', () => {
24652465
expect(count1).toBe(count2)
24662466
expect(count1).toBeGreaterThan(0)
24672467
})
2468+
2469+
test('recipes: "*" should override individual recipe staticCss config', () => {
2470+
// Create a context with a recipe that has its own staticCss config
2471+
const confWithRecipeStaticCss = {
2472+
hooks,
2473+
...defaults,
2474+
config: {
2475+
...defaults.config,
2476+
theme: {
2477+
...JSON.parse(JSON.stringify(defaults.config.theme)),
2478+
recipes: {
2479+
testRecipe: {
2480+
className: 'testRecipe',
2481+
base: { display: 'flex' },
2482+
variants: {
2483+
size: {
2484+
sm: { fontSize: '12px' },
2485+
md: { fontSize: '14px' },
2486+
lg: { fontSize: '16px' },
2487+
},
2488+
variant: {
2489+
primary: { color: 'blue' },
2490+
secondary: { color: 'gray' },
2491+
},
2492+
},
2493+
// This recipe has its own staticCss config that only includes 'sm' size
2494+
staticCss: [{ size: ['sm'] }],
2495+
},
2496+
},
2497+
},
2498+
},
2499+
} as typeof fixtureDefaults
2500+
2501+
const ctxWithStaticCss = new Context(confWithRecipeStaticCss)
2502+
const getStaticCssWithCtx = (options: StaticCssOptions) => {
2503+
const engine = ctxWithStaticCss.staticCss.clone().process(options)
2504+
return { results: engine.results, css: engine.sheet.toCss() }
2505+
}
2506+
2507+
// When using recipes: "*", ALL variants should be generated
2508+
// even though the recipe's staticCss only specifies ['sm']
2509+
const result = getStaticCssWithCtx({ recipes: '*' })
2510+
2511+
// Should include all size variants (sm, md, lg), not just sm
2512+
expect(result.css).toContain('testRecipe--size_sm')
2513+
expect(result.css).toContain('testRecipe--size_md')
2514+
expect(result.css).toContain('testRecipe--size_lg')
2515+
2516+
// Should include all variant variants (primary, secondary)
2517+
expect(result.css).toContain('testRecipe--variant_primary')
2518+
expect(result.css).toContain('testRecipe--variant_secondary')
2519+
})
24682520
})

packages/core/src/static-css.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,11 @@ export class StaticCss {
287287

288288
Object.entries(recipeConfigs).forEach(([name, recipe]) => {
289289
if (useAllRecipes) {
290+
// When recipes: "*" is set globally, always use ['*'] for all recipes
291+
// This should NOT be overridden by individual recipe.staticCss configs
290292
staticCss.recipes[name] = ['*']
291-
}
292-
293-
if (recipe.staticCss) {
293+
} else if (recipe.staticCss) {
294+
// Only use recipe-level staticCss when not using global wildcard
294295
staticCss.recipes[name] = recipe.staticCss
295296
}
296297
})
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { fixtureDefaults } from '@pandacss/fixture'
2+
import type { LoadConfigResult, StaticCssOptions } from '@pandacss/types'
3+
import { describe, expect, test } from 'vitest'
4+
import { Generator } from '../src'
5+
6+
const createSplitCssContext = (staticCss: StaticCssOptions) => {
7+
const config: LoadConfigResult = {
8+
...fixtureDefaults,
9+
config: {
10+
...fixtureDefaults.config,
11+
staticCss,
12+
},
13+
}
14+
15+
const generator = new Generator(config)
16+
const sheet = generator.createSheet()
17+
18+
generator.appendLayerParams(sheet)
19+
generator.appendBaselineCss(sheet)
20+
21+
const artifacts = generator.getSplitCssArtifacts(sheet)
22+
23+
return {
24+
generator,
25+
sheet,
26+
artifacts,
27+
recipeKeys: generator.recipes.keys,
28+
recipeNames: artifacts.recipes.map((r) => r.name),
29+
recipeFiles: artifacts.recipes.map((r) => r.file),
30+
}
31+
}
32+
33+
describe('split CSS generation', () => {
34+
test('staticCss recipes: "*" should include all recipes', () => {
35+
const { recipeKeys, recipeNames } = createSplitCssContext({ recipes: '*' })
36+
37+
for (const recipeName of recipeKeys) {
38+
expect(recipeNames).toContain(recipeName)
39+
}
40+
})
41+
42+
test('should generate separate CSS files for each recipe', () => {
43+
const { recipeKeys, recipeFiles, artifacts } = createSplitCssContext({ recipes: '*' })
44+
45+
// Number of recipe CSS files should match the number of recipe keys
46+
expect(artifacts.recipes.length).toBe(recipeKeys.length)
47+
48+
// Verify all recipe file names
49+
expect(recipeFiles.sort()).toMatchInlineSnapshot(`
50+
[
51+
"badge.css",
52+
"button-style.css",
53+
"card-style.css",
54+
"checkbox.css",
55+
"text-style.css",
56+
"tooltip-style.css",
57+
]
58+
`)
59+
60+
// Each recipe should have non-empty CSS
61+
artifacts.recipes.forEach((recipe) => {
62+
expect(recipe.code.trim().length).toBeGreaterThan(0)
63+
expect(recipe.file).toMatch(/\.css$/)
64+
expect(recipe.dir).toBe('recipes')
65+
})
66+
})
67+
})

packages/generator/src/generator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export class Generator extends Context {
141141

142142
// Recipe artifacts
143143
const recipes: SplitCssArtifact[] = []
144-
for (const recipeName of decoder.recipes.keys()) {
144+
for (const recipeName of this.recipes.keys) {
145145
const recipeSheet = this.createSheet()
146146
recipeSheet.processDecoderForRecipe(decoder, recipeName)
147147
const code = recipeSheet.getLayerCss('recipes')

0 commit comments

Comments
 (0)