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

Concurrent mode and streaming server rendering support #754

Closed
TxHawks opened this issue Dec 2, 2019 · 2 comments
Closed

Concurrent mode and streaming server rendering support #754

TxHawks opened this issue Dec 2, 2019 · 2 comments
Labels
Type: Proposal Proposals describe new feature ideas and additions with full examples and description

Comments

@TxHawks
Copy link
Collaborator

TxHawks commented Dec 2, 2019

Type: Feature


Description

With React's concurrent mode expected to soon be released in production releases, combined with streaming SSR, our current approach of populating style tags in the <head>, becomes no longer tenable, since by the time a server-rendered component is rendered the <style> tag it is trying to populate may (and likely has) already have been streamed to the user.

This leaves us needing to find a progressive rendering alternative. Work on this has already been started in #337 and #435, but was later abandoned as the approach of of prepending additive style tags before components proved to be too complex and carry too many edge cases and cascade pitfalls, e.g.,

// ComponentA.js
import { useFela, } from 'react-fela';

export default () => {
  const { css, } = useFela();
  return (
    <div
      className={css({ 
        backgroundColor: "#00f",
        "@media (min-width: 600px)": {
          backgroundColor: "#f00",
        },
      })}
    >
      I'm blue and turn red in screens wider than 600px
    </div>
  );
};
// ComponentB.js
import { useFela, } from 'react-fela';

export default () => {
  const { css, } = useFela();
  return (
    <div
      className={css({ 
        backgroundColor: "#0f0",
        "@media (min-width: 600px)": {
          backgroundColor: "#f00",
        },
      })}
    >
      I'm green and turn red in screens wider than 600px
    </div>
  );
};

If because of streaming, server rendered html turns out to be:

<style>.a{background-color: "#0f0"}</style>
<style media="(min-width: 600px)">.b{background-color: "#f00"}</style>
<div class="a b">I'm blue and turn red in screens wider than 600px</div>
<!-- ... -->
<style>.c{background-color: "#00f"}</style>
<div class="b c">I'm green and turn red in screens wider than 600px</div>

The second div will always remain green, because .c comes after .b in the cascade, at least until rehydration, when media query ordering takes place.

Alternatives

Other atomic css-in-js libraries are also faced by the same issue.

Styletron

Styletron has been tracking the issue for quite some time in in styletron/#137, which was recently superseded by the newer styletron/#334. Their current direction is to additively prepend <style> elements before component elements on the server, and then, during rehydration, remove them and append their content to the "canonical" <style> element(s) in the <head>. As I already indicated there, this is likely to cause incompatibilities between pre-hydrated and hydrated UI in a way similar to the case posted above.

React Native Web

React Native Web has also tackled this issue in react-native-web/#1136, although eventually from a different angle. A comment to this thread suggested
prepending inline <script> elements before component element instead of <style> ones. The scripts, when run, are meant to add relevant styles to the "canonical" <style> element(s) in the <head>.

Proposal

I feel the approach discussed in the React Native Web comment is currently the best solution available for a number of reasons:

  1. Inline <script> elements are blocking in the same way <style> elements are, so there should be no FOUT involved.
  2. Fela <style> elements in the <head> are sorted, so styles added to them will conform with the user's cascade expectations.
  3. As result of the above, there should be not difference between pre and post hydration UI

It is critical, however, to check the performance implications of this approach.

@TxHawks TxHawks added the Type: Proposal Proposals describe new feature ideas and additions with full examples and description label Dec 2, 2019
@robinweser
Copy link
Owner

Let's discuss this over at Spectrum or WhatsApp in detail, but I'd love to see a working PR with that.
I lost track of the feature since I'm not actively using stream rendering at all.

@KittyGiraudel
Copy link
Contributor

@robinweser Hey Robin! I hope you’re doing well. 😊 Do you know whether streaming will eventually be supported by Fela? Let‘s chat on Telegram if it‘s easier. ✨

@robinweser robinweser closed this as not planned Won't fix, can't repro, duplicate, stale Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Proposal Proposals describe new feature ideas and additions with full examples and description
Projects
None yet
Development

No branches or pull requests

3 participants