Skip to content

Commit

Permalink
fix: cache recipe_base result to prevent in-memory duplicated CSS (#2249
Browse files Browse the repository at this point in the history
)

each HMR change triggered would add duplicate styles (recipe bases), slowly increasing the time taken to output the CSS, even tho the final CSS would never contain any duplicate due to postcss/lightningcss plugins
#2236 (reply in thread)
  • Loading branch information
astahmer authored Feb 24, 2024
1 parent 47e9b05 commit 4736057
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 123 deletions.
6 changes: 6 additions & 0 deletions .changeset/dull-donkeys-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@pandacss/core': patch
---

Fix an issue with recipes that lead to in-memory duplication the resulting CSS, which would increase the time taken to
output the CSS after each extraction in the same HMR session (by a few ms).
1 change: 0 additions & 1 deletion packages/core/__tests__/rule-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,6 @@ describe('rule processor', () => {
expect(processor.toCss()).toMatchInlineSnapshot(`
"@layer recipes {
@layer _base {
.btn {
display: inline-flex;
outline: var(--borders-none);
Expand Down
1 change: 0 additions & 1 deletion packages/core/__tests__/sort-style-rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ describe('sort style rules', () => {
expect(sheet2.toCss({ optimize: true })).toMatchInlineSnapshot(`
"@layer recipes {
@layer _base {
.btn {
display: inline-flex;
outline: var(--borders-none);
Expand Down
120 changes: 0 additions & 120 deletions packages/core/__tests__/style-decoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2180,126 +2180,6 @@ describe('style decoder', () => {
},
"slot": undefined,
},
{
"className": "buttonStyle",
"details": [
{
"conditions": undefined,
"entry": {
"prop": "display",
"recipe": "buttonStyle",
"value": "inline-flex",
},
"hash": "display]___[value:inline-flex]___[recipe:buttonStyle",
"result": {
"display": "inline-flex",
},
},
{
"conditions": undefined,
"entry": {
"prop": "alignItems",
"recipe": "buttonStyle",
"value": "center",
},
"hash": "alignItems]___[value:center]___[recipe:buttonStyle",
"result": {
"alignItems": "center",
},
},
{
"conditions": undefined,
"entry": {
"prop": "justifyContent",
"recipe": "buttonStyle",
"value": "center",
},
"hash": "justifyContent]___[value:center]___[recipe:buttonStyle",
"result": {
"justifyContent": "center",
},
},
{
"conditions": [
{
"raw": "&:is(:hover, [data-hover])",
"type": "self-nesting",
"value": "&:is(:hover, [data-hover])",
},
],
"entry": {
"cond": "_hover",
"prop": "backgroundColor",
"recipe": "buttonStyle",
"value": "red.200",
},
"hash": "backgroundColor]___[value:red.200]___[cond:_hover]___[recipe:buttonStyle",
"result": {
"backgroundColor": "var(--colors-red-200)",
},
},
{
"conditions": [
{
"raw": "&:is(:hover, [data-hover])",
"type": "self-nesting",
"value": "&:is(:hover, [data-hover])",
},
],
"entry": {
"cond": "_hover",
"prop": "fontSize",
"recipe": "buttonStyle",
"value": "3xl",
},
"hash": "fontSize]___[value:3xl]___[cond:_hover]___[recipe:buttonStyle",
"result": {
"fontSize": "var(--font-sizes-3xl)",
},
},
{
"conditions": [
{
"raw": "&:is(:hover, [data-hover])",
"type": "self-nesting",
"value": "&:is(:hover, [data-hover])",
},
],
"entry": {
"cond": "_hover",
"prop": "color",
"recipe": "buttonStyle",
"value": "white",
},
"hash": "color]___[value:white]___[cond:_hover]___[recipe:buttonStyle",
"result": {
"color": "var(--colors-white)",
},
},
],
"hashSet": Set {
"display]___[value:inline-flex]___[recipe:buttonStyle",
"alignItems]___[value:center]___[recipe:buttonStyle",
"justifyContent]___[value:center]___[recipe:buttonStyle",
"backgroundColor]___[value:red.200]___[cond:_hover]___[recipe:buttonStyle",
"fontSize]___[value:3xl]___[cond:_hover]___[recipe:buttonStyle",
"color]___[value:white]___[cond:_hover]___[recipe:buttonStyle",
},
"recipe": "buttonStyle",
"result": {
".buttonStyle": {
"&:is(:hover, [data-hover])": {
"backgroundColor": "var(--colors-red-200)",
"color": "var(--colors-white)",
"fontSize": "var(--font-sizes-3xl)",
},
"alignItems": "center",
"display": "inline-flex",
"justifyContent": "center",
},
},
"slot": undefined,
},
},
}
`)
Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/style-decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class StyleDecoder {
//
atomic_cache = new Map<string, AtomicStyleResult>()
group_cache = new Map<string, GroupedResult>()
recipe_base_cache = new Map<string, RecipeBaseResult>()
//
atomic = new Set<AtomicStyleResult>()
//
Expand Down Expand Up @@ -212,15 +213,22 @@ export class StyleDecoder {
? this.context.recipes.getSlotKey(recipeConfig.className, slot)
: recipeConfig.className

const cached = this.recipe_base_cache.get(className)
if (cached) return cached

const selector = this.formatSelector([], className)
const style = this.getGroup(hashSet, className)

return Object.assign({}, style, {
const result = Object.assign({}, style, {
result: { ['.' + selector]: style.result },
recipe: recipeName,
className,
slot,
})

this.recipe_base_cache.set(className, result)

return result
}

collectAtomic = (encoder: StyleEncoder) => {
Expand Down

0 comments on commit 4736057

Please sign in to comment.