Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: stringify keys on cache #383

Merged

Conversation

mleralec
Copy link
Contributor

@mleralec mleralec commented Aug 23, 2022

Summary

Following this issue #371, I investigated the source code of xstyled to understand what was happening by adding logs:

// node_modules/@xstyled/system/dist/index.cjs (v3.6.0)

const getStyleFactory = (prop, mixin, themeGet) => {
  return (props) => {
    const fromValue = (value2) => {
      if (!util.is(value2))
        return null;
      if (util.obj(value2))
        return reduceVariants(props, value2, fromValue);
      return util.cascade(mixin(themeGet ? themeGet(value2)(props) : value2), props);
    };
    const value = props[prop];
    if (!util.is(value))
      return null;
    const cache = getCache(props.theme, prop);
    if (cache.has(value)) {
+     console.log('--- cache.has --- (getStyleFactory)', value)
      return cache.get(value);
    }
    const style2 = fromValue(props[prop]);
+   console.log('--- cache.set --- (getStyleFactory)', value)
    cache.set(value, style2);
    return style2;
  };
};

On the server, with each new request, we can see these logs appear:

--- cache.set --- (getStyleFactory) { md: '60%' }
--- cache.set --- (getStyleFactory) { md: 2 }
--- cache.set --- (getStyleFactory) { xs: 'center', md: 'flex-end' }
--- cache.set --- (getStyleFactory) { md: 'column' }
--- cache.set --- (getStyleFactory) { md: '80%' }
--- cache.set --- (getStyleFactory) { xs: 'center', md: 'flex-end' }
--- cache.set --- (getStyleFactory) { md: '20%' }
// ...

Basically, an object cannot be used as a key on a map:

const obj = { xs: 'center', md: 'flex-end' }
const map = new Map()
map.set(obj, 'whatever')

const obj2 = { ...obj }
map.has(obj2) // false
map.get(obj2) // undefined

So the solution here is to stringify the value when it's an object:

const key = obj(value) ? JSON.stringify(value) : value

Benchmarks:

(main)  @xstyled/system x 317,090 ops/sec ±0.61% (90 runs sampled)`
(fix-map-with-object-keys) @xstyled/system x 261,981 ops/sec ±0.40% (91 runs sampled)`

This fix slows down the benchmark a bit, probably because of the JSON.stringify but prevent memory leaks...

(maybe we can look at a library to speed up the conversion object -> string, like https://github.com/fastify/fast-json-stringify)

Copy link
Contributor

@theo-mesnil theo-mesnil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

@theo-mesnil
Copy link
Contributor

Hi @gregberge

Can you check this PR please to unlock our projects ? 😊

@gregberge gregberge merged commit 879708c into styled-components:main Oct 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants