Hi there,
At my place of work we have a large RN codebase and have been working hard on the web platform side of things. We have a very high level of code reuse made possible by RNWeb (thanks). We're doing SSR (using Next) for SEO reasons mostly
Here's the rub - almost everyone approaches this web platform work as if it's a standard responsive website ("let's use media queries", "let's lazy load all components") and i'm not doing a good job communicating the differences particularly with regard to the RNWeb "atomic CSS-in-JS" styling of RNWeb vs standard CSS, especially with SSR thrown into the mix
Using the Twitter site as an example helped loads but as it's CSR it doesn't cover all bases and we're now stuck in the depths of lazy loading vs "full SSR" (with vary headers ) discussion.
Are there any good examples of an SSR RNWeb site out there? Bonus points if they go full SSR and perhaps communicate the client dimensions etc via cookies or other method.
Thanks
As for SSR media queries: https://github.com/artsy/fresnel I believe this is the only reliable approach.
Rendering all permutations of our responsive breakpoints/orientations serverside isn't an option i'm afraid
@elmpp Then you have no other option.
There are plenty of options and it's kinda why i'm asking the question
I'm not looking for another discussion of the merits of each, just examples please (it's the reason for the question)
Any React DOM app using those SSR techniques is an example. It's not usually a good idea for apps to do "full SSR". The new Facebook app doesn't even do that, even though it has chosen to rely on SSR. You still want to lazy load expensive assets that aren't needed for the initial render
Yeah the majority of components probably will be lazy loaded (user-specific data) but we're finding there is another class of components that need to be adaptive and would be best rendered ServerSide.
Examples would be a our navigation which hits an api for its items but looks and operates quite differently mobile/desktop
Any React DOM app using those SSR techniques is an example
I guess so but RNWeb's atomic CSS-in-JS means the media queries can't be generated and sent down initially - it has to "pick" which can lead to jank for those prerendered components
Anyway, thanks for the reminder about facebook.com - it does actually render entirely differently based on UserAgent so it's just the example i needed (and stores it in cookies for subsequent visits) 馃憤
SSR techniques don't generate media queries either. The only good thing about CSS media queries is that a SSR response doesn't need to know anything about the viewport dimensions. The problem with CSS media queries is how little you can do with them in the first place since they have no relation to the DOM (unlike JS media queries). They're completely deficient when it comes to creating dynamic apps that adapt to their environment, supporting everything from a portrait phone to a widescreen desktop screen. Even using client hints it's pretty complicated to get a SSR web app to render as if it were in the browser. At the moment there is probably no benefit for SSR of a React app, because you pay the cost of rendering on both the server and the client. The initial response isn't even interactive. Plus, using a PWA architecture would let you cut out the server roundtrip for assets anyway.
At my place of work we have a large RN codebase and have been working hard on the web platform side of things. We have a very high level of code reuse made possible by RNWeb (thanks). We're doing SSR (using Next) for SEO reasons mostly
I have a similar experience at my workplace. We had a large RN codebase first and needed to do the web at a later stage.
I first chose RNW + Next.js and artsy/fresnel to do full SSR for SEO (we have hundreds of thousands of dynamic pages).
Using artsy/fresnel with RNW in next.js had a few problems:
div as a wrapping element in the DOM, which is not a RNW component so you need to apply hacky styles to the wrapper div at various places if you combine them<View style={[isMobile && { color: 'red' }] />)2 was not easy to solve, so in some places where SEO didn't matter, we simply code-splitted some part and did CSR there because having SP and PC components separately led to so much duplicate code.
I however later decided to ditch Next.js and SSR altogether because the added complexity of SSR hurt our team productivity and decided it wasn't worth it (responsive design, developing for both client/server, using lib limited to SSR compatible, not exposing credentials to shared pages, etc all added extra cognitive overhead).
I migrated the app to create-react-app + hand-written small useResponsive() utility, GoogleChrome/Rendertron to pre-render for google bots (I pre-render only mobile version).
In my observation our transition to CSR didn't affect SEO negatively after all. In contrast our team productivity increased a lot as a result. it's not going to be as fast as proper SSR, but IMO it's a decent trade off for some use cases.
A bit off-topic: I faced one issue when I set up Rendertron though: CSS wasn't picked up properly. I believe it's due to RNW's optimized CSSOM? @necolas. I added a script to copy RNW style into a dummy style tag for HeadlessChrome UserAgent to solve this.
Even using client hints it's pretty complicated to get a SSR web app to render as if it were in the browser. At the moment there is probably no benefit for SSR of a React _app_, because you pay the cost of rendering on both the server and the client. The initial response isn't even interactive. Plus, using a PWA architecture would let you cut out the server roundtrip for assets anyway.
Yeah - the I agree distinction is correct there for an _app_ where the true value is after the client initialisation but for a more presentational site the more a site can be SSR'd the better (for example a movie details page with "related movies" sidebar). The difference in UX can be quite stark for this kind of audience
Another big factor that isn't thought of so much is the ability to cache - if you're rendering large portions of the site during SSR and then caching in Cloudflare or wherever you're reducing load on both Server and API
- the lib appends
divas a wrapping element in the DOM, which is not a RNW component so you need to apply hacky styles to the wrapperdivat various places if you combine them
- the lib provides no easy way to apply responsive inline styles to a component (e.g.
<View style={[isMobile && { color: 'red' }] />)- It increased the output size (it wasn't too much of a problem at that time)
We have a similar situation whereby another styling solution choice (Radium) is incompatible with RNWeb leading to all the components needing to be wrapped. This definitely feels like you're fighting things at that point so i understand you choosing a different path
I however later decided to ditch Next.js and SSR altogether because the added complexity of SSR hurt our team productivity and decided it wasn't worth it (responsive design, developing for both client/server, using lib limited to SSR compatible, not exposing credentials to shared pages, etc all added extra cognitive overhead).
Yeah, the extra complexity really is a massive factor. Only thing i'd say in its defence is that it is getting easier (@EvanBacon @brunolemos have helped loads with the 100% reuse dream) and when it works well it can allow a very small number of devs create a product for all platforms with proven SEO + great UX (can you imagine facebook.com lazy loading the main feed now it's done SSR?!)
Radium's styling implementation is incredibly slow and should be avoided.
I think this question has been answered. There currently isn't a way to define static CSS media queries with this API, and that prevents certain responsive layouts from being possible via SSR before the client initializes
@necolas Is it possible to expose the styleResolver as unstable_styleResolver this would help me a great deal to make some kind of library which would work on the server too.
E.g.
<CrossResponsive
style={styles.categoryHeader}
styleIfLargerThan={{
width: {
700: styles.categoryHeaderDesktop,
},
}} />
To make this work on the server I would like to use the styleResolver to generate all combinations of styles as hardcoded classNames and add them later outside of react based on screen width/height with screen listener in javascript outside of React.
I don't understand why you'd need that API to do what you're saying. Sounds like you can already do that now. But if you're using JS media queries that's not going to really work for SSR anyway
It can if you load the script tag directly in the html instead of via React
But that would require generating the classNames for all possible configurations so I know outside of React which classnames to add based on width/height.
E.g. I would have a JSON in my script tag like this
<script>
const styleIfLargerThan = { width: { 700: "rn929 rn 292 rn292" }}
let element = getElementbyUniqueID('CrossResponsive9293002')
const screenWidth = window.screenWidth
const applyClasses = Object.keys(styleIfLargerThan.width).filter(width => screenWidth > Number(width)).map(width => styleIfLargerThan[width])
element.classes.add(applyClasses)
</script>
This would run before React hydrates the view so the user does not see any flickering
Ofcourse this approach would only be done in SSR and client-side still in a normal way without any internal api's needed
That's currently a very fragile approach. I'm not going to expose any internals to support that, so you can reach into the modules at your own risk. I happen to be working on another framework that could support this, but the problem space overlaps with SSR streaming and is something that should really be automatically handled by a framework that explicitly supports these features.
You can also use dataSet to connect styles from outside the framework to data-* props. Obviously won't be compatible with RN though. And you lose the deterministic rendering guarantees too
I don't think that's what I'm looking for, but I dont use SSR that much and our app had much of the same styling across mobile and desktop. Only one place where I needed this today.
Maybe if I feel like I'll hack a together a small demo with demo of this approach so we can discuss it further