callstack / linaria

Zero-runtime CSS in JS library
https://linaria.dev
MIT License
11.63k stars 416 forks source link

(atomic): string serialization for atomic styles produced #912

Open jpnelson opened 2 years ago

jpnelson commented 2 years ago

Describe the enhancement

Currently, atomic styles produces an object in the resulting code like this:

const atoms = css`
  background: red;
  width: 100%;
`;

// gets compiled to
const atoms = {
  background: 'atm_foo',
  width: 'atm_bar',
}

I would propose to change it to this:

const atoms = css`
  background: red;
  width: 100%;
`;

// gets compiled to
const atoms = 'atm_hash1-foo atm_hash2-bar';

Where hash1 is a hash of background and hash2 is a hash of width.

cx can then be modified to do something like this:

const KEY_VALUE_SEPARATOR = '-';

const cx = function cx() {
  const presentClassNames = Array.prototype.slice
    .call(arguments)
    .filter(Boolean);

  // `cx` is passed all strings with encoded key:value, we need to dedupe
  const map = {};

  for (let str of presentClassNames) {
    // className could be the output of a previous cx call, so split by ' ' first
    const individualClassNames = str.split(' ')

    for (let className of individualClassNames) {
        const [key, value] = className.split(KEY_VALUE_SEPARATOR);
        map[key] = `${key + KEY_VALUE_SEPARATOR + value}`;
    }
  }

  return Object.values(map);
};

Motivation

The issue we have today is people using cx multiple times, and not getting correct merging behavior. Generally this happens because people merge styles before passing them around. The issue is that effectively,

cx(a, cx(b, c)) !== cx(a, b, c)

Possible implementations

From benchmark testing, doing string manipulation isn't much worse than merging objects. However, if anyone felt strongly about it, we could:

  1. Provide an option to choose between the two representations
  2. Provide a different cx util

I don't think that extra complexity is needed though, so I'd recommend not adding that complexity

Related Issues

yume-chan commented 1 year ago

Is this issue already fixed and can be closed?