Skip to content

Commit c983d7b

Browse files
committed
feat(tasty): chunk styling * 2
1 parent a283b93 commit c983d7b

File tree

3 files changed

+34
-44
lines changed

3 files changed

+34
-44
lines changed

src/tasty/chunks/cacheKey.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -69,33 +69,3 @@ export function generateChunkCacheKey(
6969
// Use null character as separator (safe, not in JSON output)
7070
return parts.join('\0');
7171
}
72-
73-
/**
74-
* Generate a cache key for the subcomponents chunk.
75-
*
76-
* For subcomponents, we serialize the entire nested style objects
77-
* since they contain their own style hierarchies.
78-
*
79-
* @param styles - The full styles object
80-
* @param selectorKeys - Keys of selectors (subcomponents) in this chunk
81-
* @returns A stable cache key string
82-
*/
83-
export function generateSubcomponentsCacheKey(
84-
styles: Styles,
85-
selectorKeys: string[],
86-
): string {
87-
const parts: string[] = ['subcomponents'];
88-
89-
// Sort keys for stable ordering
90-
const sortedKeys = selectorKeys.slice().sort();
91-
92-
for (const key of sortedKeys) {
93-
const value = styles[key];
94-
if (value !== undefined) {
95-
// Use stable stringify for consistent serialization regardless of key order
96-
parts.push(`${key}:${stableStringify(value)}`);
97-
}
98-
}
99-
100-
return parts.join('\0');
101-
}

src/tasty/chunks/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ export {
1111
} from './definitions';
1212
export type { ChunkName, ChunkInfo } from './definitions';
1313

14-
export {
15-
generateChunkCacheKey,
16-
generateSubcomponentsCacheKey,
17-
} from './cacheKey';
14+
export { generateChunkCacheKey } from './cacheKey';
1815

1916
export { renderStylesForChunk } from './renderChunk';

src/tasty/hooks/useStyles.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useInsertionEffect, useMemo, useRef } from 'react';
22

33
import {
44
categorizeStyleKeys,
5-
CHUNK_NAMES,
65
generateChunkCacheKey,
76
renderStylesForChunk,
87
} from '../chunks';
@@ -64,35 +63,58 @@ export function useStyles({ styles }: UseStylesOptions): UseStylesResult {
6463
// Array of dispose functions for each chunk
6564
const disposeRef = useRef<(() => void)[]>([]);
6665

67-
// Memoize the style key for change detection
66+
// Store styles by their stringified key to avoid recomputing when only reference changes
67+
const stylesRef = useRef<{ key: string; styles: Styles | undefined }>({
68+
key: '',
69+
styles: undefined,
70+
});
71+
72+
// Compute style key - this is a primitive string that captures style content
6873
const styleKey = useMemo(() => {
6974
if (!styles || Object.keys(styles).length === 0) {
7075
return '';
7176
}
7277
return stringifyStyles(styles);
7378
}, [styles]);
7479

80+
// Update ref when styleKey changes (content actually changed)
81+
if (stylesRef.current.key !== styleKey) {
82+
stylesRef.current = { key: styleKey, styles };
83+
}
84+
7585
// Process chunks: categorize, generate cache keys, render, and allocate classNames
86+
// Only depends on styleKey (primitive), not styles object reference
7687
const processedChunks: ProcessedChunk[] = useMemo(() => {
77-
if (!styleKey || !styles) {
88+
const currentStyles = stylesRef.current.styles;
89+
if (!styleKey || !currentStyles) {
7890
return [];
7991
}
8092

8193
// Categorize style keys into chunks
82-
const chunkMap = categorizeStyleKeys(styles as Record<string, unknown>);
94+
const chunkMap = categorizeStyleKeys(
95+
currentStyles as Record<string, unknown>,
96+
);
8397
const chunks: ProcessedChunk[] = [];
8498

85-
for (const [chunkName, styleKeys] of chunkMap) {
99+
for (const [chunkName, chunkStyleKeys] of chunkMap) {
86100
// Skip empty chunks
87-
if (styleKeys.length === 0) {
101+
if (chunkStyleKeys.length === 0) {
88102
continue;
89103
}
90104

91105
// Generate cache key for this chunk
92-
const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);
106+
const cacheKey = generateChunkCacheKey(
107+
currentStyles,
108+
chunkName,
109+
chunkStyleKeys,
110+
);
93111

94112
// Render styles for this chunk
95-
const renderResult = renderStylesForChunk(styles, chunkName, styleKeys);
113+
const renderResult = renderStylesForChunk(
114+
currentStyles,
115+
chunkName,
116+
chunkStyleKeys,
117+
);
96118

97119
// Skip chunks with no rules
98120
if (renderResult.rules.length === 0) {
@@ -104,15 +126,16 @@ export function useStyles({ styles }: UseStylesOptions): UseStylesResult {
104126

105127
chunks.push({
106128
name: chunkName,
107-
styleKeys,
129+
styleKeys: chunkStyleKeys,
108130
cacheKey,
109131
renderResult,
110132
className,
111133
});
112134
}
113135

114136
return chunks;
115-
}, [styleKey, styles]);
137+
138+
}, [styleKey]);
116139

117140
// Inject styles in insertion effect (avoids render phase side effects)
118141
useInsertionEffect(() => {

0 commit comments

Comments
 (0)