Skip to content

Commit

Permalink
feat: support order
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Jul 27, 2023
1 parent 3e29b34 commit e0ca539
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 41 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"@emotion/unitless": "^0.7.5",
"classnames": "^2.3.1",
"csstype": "^3.0.10",
"rc-util": "^5.34.1",
"rc-util": "^5.35.0",
"stylis": "^4.0.13"
},
"devDependencies": {
Expand Down
111 changes: 74 additions & 37 deletions src/hooks/useStyleRegister/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,16 @@ export default function useStyleRegister(
layer?: string;
nonce?: string | (() => string);
clientOnly?: boolean;
/**
* Tell cssinjs the insert order of style.
* It's useful when you need to insert style
* before other style to overwrite for the same selector priority.
*/
order?: number;
},
styleFn: () => CSSInterpolation,
) {
const { token, path, hashId, layer, nonce, clientOnly } = info;
const { token, path, hashId, layer, nonce, clientOnly, order = 0 } = info;
const {
autoClear,
mock,
Expand Down Expand Up @@ -399,6 +405,7 @@ export default function useStyleRegister(
styleId: string,
effectStyle: Record<string, string>,
clientOnly: boolean | undefined,
order: number,
]
>(
'style',
Expand All @@ -411,7 +418,14 @@ export default function useStyleRegister(
if (existPath(cachePath)) {
const [inlineCacheStyleStr, styleHash] = getStyleAndHash(cachePath);
if (inlineCacheStyleStr) {
return [inlineCacheStyleStr, tokenKey, styleHash, {}, clientOnly];
return [
inlineCacheStyleStr,
tokenKey,
styleHash,
{},
clientOnly,
order,
];
}
}

Expand All @@ -429,7 +443,7 @@ export default function useStyleRegister(
const styleStr = normalizeStyle(parsedStyle);
const styleId = uniqueHash(fullPath, styleStr);

return [styleStr, tokenKey, styleId, effectStyle, clientOnly];
return [styleStr, tokenKey, styleId, effectStyle, clientOnly, order];
},

// Remove cache if no need
Expand All @@ -446,6 +460,7 @@ export default function useStyleRegister(
mark: ATTR_MARK,
prepend: 'queue',
attachTo: container,
priority: order,
};

const nonceStr = typeof nonce === 'function' ? nonce() : nonce;
Expand Down Expand Up @@ -547,43 +562,65 @@ export function extractStyle(cache: Cache, plain = false) {
}

// ====================== Fill Style ======================
styleKeys.forEach((key) => {
const cachePath = key.slice(matchPrefix.length).replace(/%/g, '|');

const [styleStr, tokenKey, styleId, effectStyle, clientOnly]: [
string,
string,
string,
Record<string, string>,
boolean,
] = cache.cache.get(key)![1];

// Skip client only style
if (clientOnly) {
return;
}
type OrderStyle = [order: number, style: string];

const orderStyles: OrderStyle[] = styleKeys
.map((key) => {
const cachePath = key.slice(matchPrefix.length).replace(/%/g, '|');

const [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]: [
string,
string,
string,
Record<string, string>,
boolean,
number,
] = cache.cache.get(key)![1];

// Skip client only style
if (clientOnly) {
return null! as OrderStyle;
}

// ====================== Style ======================
styleText += toStyleStr(styleStr, tokenKey, styleId);
// ====================== Style ======================
// Used for rc-util
const sharedAttrs = {
'data-rc-order': 'prependQueue',
'data-rc-priority': `${order}`,
};

// Save cache path with hash mapping
cachePathMap[cachePath] = styleId;
let keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs);

// =============== Create effect style ===============
if (effectStyle) {
Object.keys(effectStyle).forEach((effectKey) => {
// Effect style can be reused
if (!effectStyles[effectKey]) {
effectStyles[effectKey] = true;
styleText += toStyleStr(
normalizeStyle(effectStyle[effectKey]),
tokenKey,
`_effect-${effectKey}`,
);
}
});
}
});
// Save cache path with hash mapping
cachePathMap[cachePath] = styleId;

// =============== Create effect style ===============
if (effectStyle) {
Object.keys(effectStyle).forEach((effectKey) => {
// Effect style can be reused
if (!effectStyles[effectKey]) {
effectStyles[effectKey] = true;
keyStyleText += toStyleStr(
normalizeStyle(effectStyle[effectKey]),
tokenKey,
`_effect-${effectKey}`,
sharedAttrs,
);
}
});
}

const ret: OrderStyle = [order, keyStyleText];

return ret;
})
.filter((o) => o);

orderStyles
.sort((o1, o2) => o1[0] - o2[0])
.forEach(([, style]) => {
styleText += style;
});

// ==================== Fill Cache Path ====================
styleText += toStyleStr(
Expand Down
61 changes: 58 additions & 3 deletions tests/server.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('SSR', () => {
'<div id=":R1:" class="id">:R1:</div><div class="box"><div id=":Ra:" class="id">:Ra:</div></div><div id=":R3:" class="id">:R3:</div>',
);
expect(style).toEqual(
'<style data-token-hash="u4cay0" data-css-hash="gn1jfq">.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"u4cay0|.box:gn1jfq";}</style>',
'<style data-rc-order="prependQueue" data-rc-priority="0" data-token-hash="u4cay0" data-css-hash="gn1jfq">.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"u4cay0|.box:gn1jfq";}</style>',
);
expect(plainStyle).toEqual(
'.box{background-color:#1890ff;}.data-ant-cssinjs-cache-path{content:"u4cay0|.box:gn1jfq";}',
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('SSR', () => {

const style = extractStyle(cache);
expect(style).toEqual(
'<style data-token-hash="1gt9vg4" data-css-hash="1fyoi4y">.css-dev-only-do-not-override-1cs5t9t.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"1gt9vg4|.hashPriority:1fyoi4y";}</style>',
'<style data-rc-order="prependQueue" data-rc-priority="0" data-token-hash="1gt9vg4" data-css-hash="1fyoi4y">.css-dev-only-do-not-override-1cs5t9t.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"1gt9vg4|.hashPriority:1fyoi4y";}</style>',
);
});

Expand Down Expand Up @@ -330,7 +330,7 @@ describe('SSR', () => {

expect(html).toEqual('<div class="box"></div>');
expect(style).toEqual(
'<style data-token-hash="u4cay0" data-css-hash="gn1jfq">.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"u4cay0|.box:gn1jfq";}</style>',
'<style data-rc-order="prependQueue" data-rc-priority="0" data-token-hash="u4cay0" data-css-hash="gn1jfq">.box{background-color:#1890ff;}</style><style data-ant-cssinjs-cache-path="data-ant-cssinjs-cache-path">.data-ant-cssinjs-cache-path{content:"u4cay0|.box:gn1jfq";}</style>',
);
});

Expand Down Expand Up @@ -386,4 +386,59 @@ describe('SSR', () => {

getStyleAndHash.mockRestore();
});

it('ssr keep order', () => {
const createComponent = (name: string, order?: number) => {
const OrderDefault = ({ children }: { children?: React.ReactNode }) => {
const [token] = useCacheToken<DerivativeToken>(theme, [baseToken]);

const wrapSSR = useStyleRegister(
{ theme, token, path: [name], order },
() => ({
[`.${name}`]: {
backgroundColor: token.primaryColor,
},
}),
);

return wrapSSR(<div className={name}>{children}</div>);
};

return OrderDefault;
};

const Order0 = createComponent('order0', 0);
const Order1 = createComponent('order1', 1);
const Order2 = createComponent('order2', 2);

const cache = createCache();

renderToString(
<StyleProvider cache={cache}>
<Order1 />
<Order0 />
<Order2 />
</StyleProvider>,
);

const style = extractStyle(cache);
const holder = document.createElement('div');
holder.innerHTML = style;
const styles = Array.from(holder.querySelectorAll('style'));

expect(styles[0].getAttribute('data-rc-priority')).toEqual('0');
expect(styles[1].getAttribute('data-rc-priority')).toEqual('1');
expect(styles[2].getAttribute('data-rc-priority')).toEqual('2');

// Pure style
const pureStyle = extractStyle(cache, true);
expect(pureStyle).toEqual(
[
`.order0{background-color:#1890ff;}`,
`.order1{background-color:#1890ff;}`,
`.order2{background-color:#1890ff;}`,
`.data-ant-cssinjs-cache-path{content:"u4cay0|order1:1qekw6y;u4cay0|order0:1r3sam0;u4cay0|order2:1at78yk";}`,
].join(''),
);
});
});

0 comments on commit e0ca539

Please sign in to comment.