Skip to content

Commit f1aebf0

Browse files
committed
feat: extractStyle support once
1 parent eb0170f commit f1aebf0

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

src/Cache.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Entity {
2323
/** @private Record update times for each key */
2424
updateTimes = new Map<string, number>();
2525

26+
extracted: Set<string> = new Set();
27+
2628
get(keys: KeyType[]): ValueType | null {
2729
return this.opGet(pathKey(keys));
2830
}

src/extractStyle.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ export default function extractStyle(
3636
| {
3737
plain?: boolean;
3838
types?: ExtractStyleType | ExtractStyleType[];
39+
once?: boolean;
3940
},
4041
) {
41-
const { plain = false, types = ['style', 'token', 'cssVar'] } =
42+
const { plain = false, types = ['style', 'token', 'cssVar'], once = false } =
4243
typeof options === 'boolean' ? { plain: options } : options || {};
4344

4445
const matchPrefixRegexp = new RegExp(
@@ -60,6 +61,10 @@ export default function extractStyle(
6061

6162
styleKeys
6263
.map<[order: number, style: string, updateTime: number] | null>((key) => {
64+
if (once && cache.extracted.has(key)) {
65+
return null; // Skip if already extracted
66+
}
67+
6368
const cachePath = key.replace(matchPrefixRegexp, '').replace(/%/g, '|');
6469
const [prefix] = key.split('%');
6570
const extractFn = ExtractStyleFns[prefix as keyof typeof ExtractStyleFns];
@@ -74,6 +79,10 @@ export default function extractStyle(
7479
if (key.startsWith('style')) {
7580
cachePathMap[cachePath] = styleId;
7681
}
82+
83+
// record that this style has been extracted
84+
cache.extracted.add(key);
85+
7786
return [order, styleStr, updateTime];
7887
})
7988
.filter(isNotNull)

tests/server.spec.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ describe('SSR', () => {
6969
},
7070
});
7171

72+
const genCardStyle = (token: DerivativeToken): CSSInterpolation => ({
73+
'.card': {
74+
backgroundColor: token.primaryColor,
75+
},
76+
});
77+
7278
const Box = ({ children }: { children?: React.ReactNode }) => {
7379
const [token] = useCacheToken<DerivativeToken>(theme, [baseToken], {
7480
cssVar: { key: 'css-var-test' },
@@ -79,6 +85,16 @@ describe('SSR', () => {
7985
return <div className="box">{children}</div>;
8086
};
8187

88+
const Card = ({ children }: { children?: React.ReactNode }) => {
89+
const [token] = useCacheToken<DerivativeToken>(theme, [baseToken], {
90+
cssVar: { key: 'css-var-test' },
91+
});
92+
93+
useStyleRegister({ theme, token, path: ['.card'] }, () => [genCardStyle(token)]);
94+
95+
return <div className="card">{children}</div>;
96+
};
97+
8298
const IdHolder = () => {
8399
const id = React.useId();
84100
return (
@@ -415,4 +431,33 @@ describe('SSR', () => {
415431
// C B A
416432
testOrder(<C />, <B />, <A />, ['c', 'b', 'a']);
417433
});
434+
435+
it('should extract once when once option is true', () => {
436+
const cache = createCache();
437+
438+
renderToString(
439+
<StyleProvider cache={cache}>
440+
<IdHolder />
441+
<Box>
442+
<IdHolder />
443+
</Box>
444+
<IdHolder />
445+
</StyleProvider>,
446+
);
447+
448+
const style = extractStyle(cache, {plain: true, once: true});
449+
450+
renderToString(
451+
<StyleProvider cache={cache}>
452+
<Card />
453+
</StyleProvider>,
454+
);
455+
const style2 = extractStyle(cache, {plain: true, once: true});
456+
457+
expect(style).toContain('.box');
458+
expect(style).not.toContain('.card');
459+
460+
expect(style2).toContain('.card');
461+
expect(style2).not.toContain('.box');
462+
})
418463
});

0 commit comments

Comments
 (0)