Sign in to join this conversation, and others like it, in the communities you care about.
🚀 ✍🏻 Announcing Docz! A simple and powerful tool that'll help you a lot documenting things!
Open Source Slack Alternative
How do you compose your Apollo Mutations (or, Render Props versus Hocs)?
How to handle routing like Trello or Dribble?
React / General
I was surprised to not see styled-components mentioned.
My experience has been that streaming works well when styles have been extracted as part of the build process.
But for CSS-in-JS you need to get the full response to send the styles first, otherwise there's a FOUC.
That totally makes sense. Applying critical styles as you learn about them. Also, threepointone is a wizard.
What is the advantage of SSR, if as mentioned in the article the data for unauthenticated users doesn't change and for authenticated users it's all client-side anyway?
How are you using react-helmet-async?
styled-components does exactly that @tk, we have a sheet.interleaveWithNodeStream API which interleaves style tags with the HTML as it gets along
@jaredpalmer yep, backpack for all our backend servers
@tushkiz yep, using react-helmet-async!
@sedubois SEO, Spectrum needs to be 100% indexed on Google
And no, client-side-only rendering is not enough to get indexed on search engines haha
Yes, I am doing that :/
been trying to get renderToNodeStream to work and ran into issue with Helmet and styled-components... about to give up then i ran into this thread...
@mxstbr id you use SSR for SEO, why not just doing pre-rendering e.g using Gatsby?
Just playing devil‘s advocate here, because as shown in the article, SSR brings a lot of complexity compared to a static site. So I’m trying to understand exactly what unique value you get from it.
@egoist as I wrote in the article, as soon as you visit the page once we install a serviceworker which serves an app shell on any subsequent visit ☺️
@sdubois pre-rendering a real-time chat app? We have multiple tens of thousands of pages already, all of which need to be served with as close to real-time data as possible. How would we pre-render that?
@mxstbr thanks, I hadn't understood what was meant by "public pages". I thought that the dynamic chat data was loaded client-side anyway.
I haven't yet understood how the cache gets invalidated when a page's contents changes. It looks like the cache key is only `request.path`, however this doesn't change when the page contents change?
@sdubois we don't do any invalidation right now 🙈 pages are cached for 30 minutes
Working on that though, planning to have proper invalidation sometime soon
Any ideas on how to key things so they can easily be invalidated when anything changes? Imagine a thread page like this one
The issue is that a thread page like this one needs to be invalidated if:
1. A new message is sent
2. The contents are edited
3. Any participant changes their name or username or avatar
4. The community or channel name or image change
5. Somebody likes a message
That's a lot of stuff to key by
@mxstbr yeah. Note that instead of having a key that's unique for all those things, you could manually invalidate the cache whenever one of these things changes. But either way, that requires your data model to have relations between each of these points and the pages which are affected (but I guess it already has those relations in order to build the page contents).
One extra thought I had is that even with the caching, isn't the user is forced to load data from an origin server (on Now)? I.e. it can be a quite long trip introducing latency if someone is located far away from the origin server. Do you have some kind of server replication across different regions? Or would you consider doing CDN edge-level caching, e.g. with CloudFlare's new Workers beta feature? (https://www.cloudflare.com/products/cloudflare-workers/) (that would somehow require the edge caches to be informed about cache invalidation as well)
Additional question, why not using service workers for unauthenticated visitors as well? Might offer an extra perf improvement on top of what the article describes, and it could also solve this caching issue for returning visitors.
What sort of fallbacks do you have in place for browsers that don't support service workers ? I've found SSR to be a lot more of a mindf* when simultaneously dealing with auth and data fetching, so the service worker/app shell solution sounds appealing but I was under the impression it still wasn't supported in some browsers (IE) - is there a simple polyfill or do you fall back to a whole different method/exp for users who can't have the page served by SWs ?
Sorry, that was addressed to @mxstbr
I'm currently in the early stages of architecting something not too dissimilar from Spectrum (in the sense of also including chat/thread structures) and I wanted to try SSR with Next but handling auth flows has taken me a few days to wrap my head around (doesn't seem like there's a ton of info out there for how that works in Next, besides the barebones example implementations in the Next repo). While it doesn't cover auth, your article really couldn't have come at a more perfect time - so dense in useful information/techniques/ideas. So thanks a lot.
@sedubois we can't use a ServiceWorker on first visit, folks have to visit the page once for it to install. :( Definitely investigating CDN's though, looking into Fastly mostly right now
@mtphil well, browser that don't support ServiceWorkers just have the standard SPA experience, only their first open of the website will always be server rendered. No big deal!
Ah, I see - I wasn't thinking about it in a progressive enhancement sort of paradigm (trying to make that my default mindset though), but that makes total sense. I'll have to try that out - never messed with SWs bfore but they seem like fun.
Hey there, just read the article, I think I'm missing something. What is `cache` on the line `cache.set(key, Buffer.concat(bufferedChunks))` ?
Ok I see, I'm right now trying to implement it with node_redis :)
So I assume I will need to implement the cache.exists and cache.get part.
Thank you for this precision
i had to use res.write() instead of res.send() in the end callback. And it seems stream.pipe() takes a boolean for 'end' parameter, not a string.