From 4736057de74ef1c3038ca8a5db82ef76125212da Mon Sep 17 00:00:00 2001 From: Alexandre Stahmer <47224540+astahmer@users.noreply.github.com> Date: Sat, 24 Feb 2024 19:23:03 +0100 Subject: [PATCH] fix: cache recipe_base result to prevent in-memory duplicated CSS (#2249) 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 https://github.com/chakra-ui/panda/discussions/2236#discussioncomment-8574813 --- .changeset/dull-donkeys-obey.md | 6 + .../core/__tests__/rule-processor.test.ts | 1 - .../core/__tests__/sort-style-rules.test.ts | 1 - packages/core/__tests__/style-decoder.test.ts | 120 ------------------ packages/core/src/style-decoder.ts | 10 +- 5 files changed, 15 insertions(+), 123 deletions(-) create mode 100644 .changeset/dull-donkeys-obey.md diff --git a/.changeset/dull-donkeys-obey.md b/.changeset/dull-donkeys-obey.md new file mode 100644 index 000000000..ec384362e --- /dev/null +++ b/.changeset/dull-donkeys-obey.md @@ -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). diff --git a/packages/core/__tests__/rule-processor.test.ts b/packages/core/__tests__/rule-processor.test.ts index a75486db6..5d9ba3d7f 100644 --- a/packages/core/__tests__/rule-processor.test.ts +++ b/packages/core/__tests__/rule-processor.test.ts @@ -907,7 +907,6 @@ describe('rule processor', () => { expect(processor.toCss()).toMatchInlineSnapshot(` "@layer recipes { @layer _base { - .btn { display: inline-flex; outline: var(--borders-none); diff --git a/packages/core/__tests__/sort-style-rules.test.ts b/packages/core/__tests__/sort-style-rules.test.ts index 2230b0c85..de2bf02f5 100644 --- a/packages/core/__tests__/sort-style-rules.test.ts +++ b/packages/core/__tests__/sort-style-rules.test.ts @@ -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); diff --git a/packages/core/__tests__/style-decoder.test.ts b/packages/core/__tests__/style-decoder.test.ts index 59f2cb9bc..8b741eb27 100644 --- a/packages/core/__tests__/style-decoder.test.ts +++ b/packages/core/__tests__/style-decoder.test.ts @@ -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, - }, }, } `) diff --git a/packages/core/src/style-decoder.ts b/packages/core/src/style-decoder.ts index df607f9dc..44c74611d 100644 --- a/packages/core/src/style-decoder.ts +++ b/packages/core/src/style-decoder.ts @@ -30,6 +30,7 @@ export class StyleDecoder { // atomic_cache = new Map() group_cache = new Map() + recipe_base_cache = new Map() // atomic = new Set() // @@ -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) => {