Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
[WIP] styled-sheet #2357
This is a complete rewrite and modernisation of the core StyleSheet to speed up SSR performance and be much smaller bundle size-wise.
In styled-components v3 and below we had to clone styles (
With the new
Click for a more detailed technical explanation of the proposed changes
Current StyleSheet — deferred injection
Our current model keeps order of first injection per component. When new rules are then injected they're appended to the first rule the component injected. However, we care about order of creation for components instead, so we want to inject a placeholder as soon as the component is created. Now, because we don't want to immediately inject rules we have deferred injection to "fake insert" as first rules. That's when
When we clone a
Proposed system — injection by indices
We can capture the creation order of components with a simple counter. If we then get to
We can then take the creation index and walk the complete list of creation indices until either the next index is greater or the current one is equal. All of the number of rules in the list up until the matching index can then be added up. What we get is the injection index, which can be passed to
Another problem we tried to solve is Babel-less SSR. How can we ensure consistent classes, ordering, and unique names without the Babel plugin?
The problem we need to solve is that there has to be a “single consistent moment” between the result of SSR and the rehydration where the client renders the same result. What we're trying to achieve is consistency between the two. We can't use our “best guess displayName” since it's ordered by creation, which might be different on the server and the client.
Essentially we can keep another counter for the render order. Since in SSR the rendered tree is enforced to be the same on the client we can count upwards for rendered
This is the moment when the user creates a
This is when a
When an optimisation on the above operation is made we thus need to take into account:
To restore the correct ordering the output CSS needs to be rehydrated. This is basically a process
The order index of all components must be restored. This can be done by having a mapping
Apart from this process everything remains the same.
As an optimisation the CSS rules' hash (which is also their
If you want to get involved and help out with this please comment below! We can use all the hands we can get, especially to write tests and to figure out the API.
Ref issue #2120
I just added my first (working) test for the Sheet, yay!
Why do I have to call
const group = new Group('name'); sheet.inject(group, 'key', );
I just did
It would also be nice if
Also another random idea, what about making
const sheet = new Sheet(); const group = new Group(sheet, name); group.inject('key', rules);
That seems nicer than the implicit
const sheet = new Sheet(); const group = new sheet.Group(name); group.inject('key', rules); // or sheet.inject(group, 'key', rules);
Why would these work/not work?
For posterity so we do not forget: @kitten pointed that out that we could move to classes-as-order-markers instead of comments-as-order-markers, which would make it possible to rehydrate from a
@probablyup we'll revert the decision around Group and go back to the GroupRegistry singleton. That being said there's less allocations now, even including this change which only happens while the StyledComponent and ComponentStyle are being created :) during updates there's shouldn't ever be an allocation in styled-sheet