-
-
Notifications
You must be signed in to change notification settings - Fork 399
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
New old id generation algorithm - back to the future #432
Comments
Implementation details:
|
That sounds good to me. Does it mean we would no longer have to removed the SSR generated CSS on the client? |
We still need to remove, because we have dynamic values, its not not immutable. This should be out of concern though, because its blazingly fast. |
This is an awesome find/idea. When is it being implemented? Funny how solutions can stare you right in the face sometimes. |
Its wip, I have been struggling with dynamic rules id generation and @iamstarkov came up with the idea to provide the map from the server and use non-deterministic ids. |
Right now I have still the problem to identify the sheets, I am not sure we can rely on the order we have on the backend and client. |
@kof what do you mean by "order we have on the backend and client"? |
The order in which we render sheets during ssr and then on the client. |
we discussed that, and you may have control on that |
give me a sec |
my proposed change to jss's ssr https://github.com/cssinjs/examples/blob/gh-pages/react-ssr/src/server.js import React from 'react'
import {renderToString} from 'react-dom/server'
import {SheetsRegistryProvider, SheetsRegistry} from 'react-jss'
import Button from './Button'
export default function render() {
const sheets = new SheetsRegistry()
const app = renderToString(
<SheetsRegistryProvider registry={sheets}>
<Button />
</SheetsRegistryProvider>
)
return '' +
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Server-side rendering with rehydration</title>
<link rel="stylesheet" href="../../example.css" />
- <style type="text/css" id="server-side-styles">
- ${sheets.toString()}
- </style>
+ ${sheets.getStyleTags()}
+ <!-- or -->
+ ${sheets.getStyleTags().forEach(elem => elem.setAttribute('arbitrary', 'attr')) }
</head>
<body>
<a href="https://github.com/cssinjs/examples/tree/gh-pages/react-ssr" title="View on Github" class="github-fork-ribbon" target="_blank">View on Github</a>
<div id="app">${app}</div>
<script src="./app.js"></script>
</body>
</html>`
} |
this isn't much of a problem, the prob is that in pure jss without react-jss we have no idea if sheets are going to be rendered in the browser in the same order as on the server, rehydration data has to rely on that. Even with react I am not sure this is guaranteed. |
Does react guarantees that when rendering on the client first time, it renders exactly the same thing like the SSR did? |
why wouldnt it? |
dunno, its a question) |
but actually any framework would need to guarantee that, otherwise it would need a full rerender on startup. |
I mean the whole point of rehydration is to start the js powered application on top of server rendered one without rerender the whole thing, if it rerenders, we have no problems anyways. |
and why do you care about the order? if styletags would be generated 1 to 1 with components, you need only |
if components are the same sheets will be too, but if its possible that the client for e.g. skips rendering one component in the middle, without full rerender, then it is fucked up. |
i dont understand you |
If server renders this:
But the client renders this:
Without a full rerender of the App. Rehydration will use Data from the server and will use the ids map for SheetC from SheetB, but I guess this shouldn't be possible anyways. |
there are several cases of this behavior, e.g. when you want |
In this case, react would rerender the whole thing, right? Rerender in the sense of all components render methods and updating dom if needed. |
let me check with colleagues |
but i still cant get why does jss need to care about the order, when you can link stylesheets to components with dom node attributes. am i right that |
You can see how the map looks like, its an array, where each object is a map of rule name to a class name and represents a sheet. The order needs to be the same. |
We can advise users to use a function to generate the styles object or to deepClone the styles object when passing it to JSS, because it will mutate that object. Basically users should care about it only if they create multiple sheets using the same styles object. |
Also we could accept a function instead of styles object which returns the styles object in order to make it even a bit simpler |
we should find a way to identify sheets by some kind of identifier, order is fragile |
the only way is to create hashes … are u sure order is fragile? |
look sheets.add(jss.createStyleSheet({
a: { color: 'red' },
b: { color: () => 'green' }
}).attach())
sheets.add(jss.createStyleSheet({
a: { color: () => 'blue' }
}).attach())
expect(sheets.toMap()).to.eql([
{ a: 'a-id',
b: 'b-id' },
{ a: 'a-id' }
]) order is fragile in case if you cant guarantee original rule names |
sorry |
rule names are the same, its about the sheets order, I am not sure its a prob. |
React Stack definitely has a deterministic order. I assume that the initial render on React Fiber will be deterministic (need verification). Another note is that Fiber apparently doesn't come with SSR initially and will probably rely on community solutions. I can't say how those community solutions will be. My guess is that it will match the render order on the client (need verification).
|
Can we go with this logic: if SSR renders only critical markup/css - don't call |
React gives a warning when markup from server differs from the client, can't we assume they are always the same? Who uses server rendering to render a critical markup that differs from the clients render? |
And another thought I have is: Do we need to transmit a map of class names to the client? Can't the server and client calculate it independently using counters and still have the same result? |
I am wondering right now as well, counters are invoked in exact same way, there is no randomness. If ssr logic is the same, there should be no difference, if it is not, client would render a different view and in this case update the entire document where needed, which essentially mens there is no need in rehydration in such a case. |
Released without rehydration. Lets see if it broke anything. |
Increased only minor version because I expect no breaking change. |
@kof This changes broke my SSR. (client) ader-wrapper fade-0-256 fade-0-191 in-0- |
@rasentry do you know how? |
@kof I just upgraded to v7 and stil do not see obvious reason why this happen. Trying to understand... |
Let me know if I can help to debug this. Ideally I need some simple working example that reproduces the issue. |
I'm seeing this in next.js as well:
When the next.js server first boots, the jss counter is at 0. If I hit my page everything works, and there is no React warning. If I refresh the browser, for some reason next.js reruns my component file, and re-injects the sheet, which increments the server-side jss counter (This only happens one time). But the browser got refreshed, so its counter is back to zero. Additionally, every time the dev server detects a file change it reruns all the components, and the counter gets incremented yet again. I think you guys are right in thinking the the load order of React components is deterministic. What might not be though is the counter's starting point on the server. SSR is a weird beast. If you have five sheets, the counter will always increment five times in the same sheet order. But, where it always runs 0, 1, 2, 3, 4 on the client, it might run 13,14,15,16,17 on the server. And, just to make sure I'm not missing something, is there a special format for the server-generated |
So SSR rerenders, but counter continues to increase. |
I think we don't reset the counter between the requests. |
no, just what it is in the docs. Please open a separate issue for this story. |
@kof Just to be clear, you want a new bug report on the next.js counter issue? |
I think we can handle it in #457 as it seems to be specific to next.js |
lets create an example over there and see what we need to fix |
Me and @iamstarkov just had a discussion about #356 and decided to reimplement the id generation algorithm.
Right know we JSON.stringify the rules and generate hashes with murmurhash in order to have predictable unique class names in order to support SSR.
We found a way to avoid that overhead and still support SSR.
This will not only allow us to implement unique class names for dynamic rules in #356 but will also increase an overall performance by factor 3.
cc @nathanmarks @cvle @iamstarkov @typical000 @sapegin @oliviertassinari
The text was updated successfully, but these errors were encountered: