Live data from Hacker News

The absurd complexity of server-side rendering

gist.github.com

171–180 of 395 posts

Re: The absurd complexity of server-side rendering

#171
post #120

https://htmx.org/ Having spent 36+ years in the computer industry, I consider the advent of htmx to be the first thing in web development to to attempt to pull the industy's head out of it's ass. Don't forget to include a solid remake of css in your project like tailwindcss. It also makes code much more readable.

When fetching from the backend, the docs recommend returning snippets of html instead of JSON. Is it technically valid to return a snippet of HTML with a content type of “text/html”?

There’s no standards saying you need !DOCTYPE or a head or body?

Re: The absurd complexity of server-side rendering

#172

Earlier quoted context omitted.

It's trivial to generate pages statically, irrespective of the update volume. Instead of updating database rows, just save S3 blobs of HTML. The reason this is not done is an accident of history that is no longer required but has become the norm. "Back in the day", browser compatibility issues meant that user agent strings had to be inspected and different HTML content served based on the browser. Mobile browsers esp…

Have you worked on one of these products before? I worked for Wikimedia Foundation, and it's not trivial to generate the pages statically. The content itself is wikitext, not html. It'd derived from content, templates, and meta-templates. Quite a bit of the data comes from other sources, like wikidata, or commons. You need to display things differently based on logged-in vs logged-out status. Through lots of layers o…

Yes, I have worked with these products at a moderately large scale. I have also developed a wiki-like CMS from scratch myself, with templating, macros, and everything. The issues I saw would occur at any scale above "tiny". Essentially as soon as scale-out is needed for a dynamic site, caching also becomes mandatory.

Caching is not well understood at all. People think they understand it, but probably don't actually know most of the pitfalls, especially in the face of failure in the general case.

With Wikimedia, many of the issues are not super important. E.g.: transaction integrity is not relevant. The occasional 404 or eventual (in)consistency problem is also not a big deal.

Similarly, the user-based rendering is also fairly easy to handle. The vast majority of the content (the rendered wiki text) is identical-ish between users. The headers, footers, CSS, etc... do change. This can be handled on the client-side in a variety of ways, typically via JavaScript. Even with mostly static content, headings can be altered on the way out "at the edge" by a CDN or CDN-like system.

This is my point: If you're going to cache things in something like a CDN, then you're 90% of the way there to static content anyway! Take the leap and go the whole way to get the benefits. Some things need to be done 100%, otherwise it's like being almost pregnant.

Some random examples of static vs dynamic problems/comparisons:

- You mentioned templating: In the static world, you can regenerate all static pages based on the new template asynchronously at whatever slow "batch process" rate you desire. In a dynamic system, a change to a template would typically invalidate the entire cache and blow your CPU budget instantly, dragging down the synchronous rendering path into molasses. This can be managed, but it's complex and difficult. Similarly, code changes can similarly result in either mixed/corrupt cache content or instant CPU spikes. At least with static content you can manage the rollout by content instead of by server. A trick you can pull with static content is pre-generate the updated pages side-by-side and swap instantly. This is impossible with dynamic content generation. You either get mixed content as the caches slowly expire, or instant load spike.

- Variations such as mobile/non-mobile pages: These add to cache pressure, and can result in sudden performance cliffs where going from 90% cache utilisation to 110% can cause dramatic spikes in load. If you use static content, your "utilisation" is known in advance and changes slowly. Everything is served at the same speed, always. In fact, with systems like S3, your speed goes up as your data volume increases because of the way the sharding works.

- Memcache and the like are hilarious to me. These days the "standard" is to have layers upon layers of caching to paper over the fundamental bottleneck of the database tier. SiteCore has so many layers of caching that I lost count. Is it ten? Eleven maybe? Whatever. The point is that keeping that straight in your head as a web developer is so difficult that SiteCore keeps all caching off by default, murdering performance for most sites most of the time. It's just too "difficult" to have it on by default because devs would lose their minds. Just the access control issues of providing devs with access to shared Redis clusters or CDNs for purge operations is a task all by itself. In large enterprise, this is almost never done and then it becomes a tradeoff between cache TTLs and freshness/consistency. I've lost count of the number of times I've heard some dev tell users to "clear their browser cache" as the "fix".

- Cache purging: you can hide a fundamental performance problem under a layer of caching for years, have it grow to monumental proportions, and then blow up your production site for days while everything slowly recovers from 1,000% load. This has caused several large-scale outages that have hit headlines.

Look at it this way: Wikipedia is something like 99% read-only access and 1% write access. With a static hosting model the VMs would only need to be scaled to handle the write-throughput, not the read-throughput. The content could be put on cloud storage like S3 and that's it. The whole site could be hosted of a handful of small VMs just for HA/DR!

Re: The absurd complexity of server-side rendering

#173
post #79

Earlier quoted context omitted.

> Sure, but the first hit would've been a cache hit anyways. Similarly, a serverless function that is "warm" already has all the logic needed to inject the static template into memory. It simply needs to call out to the database, which is physically closer to the server, and always quicker, without the need for an additional HTTP handshake...and then inject the data into the template, before sending it down the wire.…

> Similarly, a serverless function that is "warm" already has all the logic needed to inject the static template into memory Sure, I accept this. > It simply needs to call out to the database, which is physically closer to the server, and always quicker, without the need for an additional HTTP handshake I contest all three parts of this. * physically closer How can this be guaranteed? You have no control over the clo…

> * physically closer

> How can this be guaranteed? You have no control over the closest Edge function vs Cloud Server to the user.

Because the user doesn't get to talk directly to the database. The database could be on the second floor of the user's building, but it's still going to have to get routed via an API. If you're using serverless functions for your API (presumably so, given this conversation), you still have the multi-hop issue to fetch data from the db. And in the case of a complex BI dashboard with multiple data sources, the extra hops can add up significantly.

> Again, your Edge function seems likely to either be cold or busy, so this is only something you can speak about probabilistically

A true Edge function has nearly 0ms latency to spin up from cold. They are distinguished from Lambda functions, which would alternatively be running in a data-center colocated with your database in most cases. Lambda functions do have a small cold start issue. But whether you're using Lambdas or Edge functions or Node.js containers, this doesn't affect the core issue.

> HTML still needs to render a DOM, not sure you're hitting on the right points of the parsing... Plus if this page is meant to be interactive still, you've not gained anything with the initial SSR phase

The HTML has to load into memory and only when it hits the JS script that actually triggers the XHR request does the call out for data occur. Depending on how your JS is bundled with your static HTML, those XHR requests may fire off at sub-optimal times. That is not something just automatically handled. It's something you have to consciously optimize for.

> It's just not a big deal, and it's laughable you'd make the example a BI dashboard because you rendered something nice for them initially in maybe 0.5s faster on a median request, in exchange for literally enormous complexity. But a BI user is probably going to be in there for a long time, interacting heavily with client-side JS you shipped and they had to parse and render and then also reconcile/hydrate

It's not laughable. A BI dashboard is an excellent use case for SSR, because it has multiple independent components that draw data from multiple API endpoints. This is precisely where SSR shines. Not sure why you're laughing. It almost sounds like you're being cognitively dissonant in the face of a practical example that conflicts with your thesis.

SSR is not complex with a framework like Next.js. It's incredibly simple. It also trivially toggles between static or server rendering depending on that particular page's data access pattern.

> How is this easier to satisfy on SSR? You have minimal advantage on your Edge worker being closer to your database than the user, unless your Edge function is actually just sitting beside your database server. It has to make the same requests and transfer the same data the client would be transferring in order to perform this SSR, there are only savings here if your Cloud provider is offering you big vendor lock-in promotions.

Multiple database hits? Simple, if you have a page with 10 components that draw from different API routes / endpoints, instead of waiting for each of those components to load into memory on the client-side with janky placeholder data while it runs 10 HTTP requests (unless you've taken on the complexity of rolling up component requests to the top level, which can be difficult if for example, the dashboard is customizable in some way from user to user).

Firstly, Edge functions aren't a prereq for SSR. You can totally deploy a Node.js container in a particular data center right alongside the DB instance if you need. Secondly, you also have access to numerous caching solutions if you really need to keep data hot. Thirdly, if you're using Edge for SSR, you're presumably already using Edge for your API. Fourth, if you really want to have data located near your edge functions, you can achieve this too! See: https://blog.cloudflare.com/workers-kv-is-ga/

> Cloudflare loss-leader pricing > Unconvincing.

I don't know what to tell you. AWS Lambdas are $0.20 per 1M requests: https://aws.amazon.com/lambda/pricing/ and they've been around for 6 years.

At any rate, I also suggest looking at the direction that Next.js + React is going in: https://calibreapp.com/blog/nextjs-performance

"With Server Components, you’re able to opt-in which parts of your application are rendered on the server and when client-side code is required. In Next.js, a server component will be denoted by filename, e.g., page-name.server.js, whereas a client-side component will use page-name.client.js.

In the following example, we can fetch content from a CMS, import a date-time utility (date-fn) and render markdown. The resulting client-side JavaScript from this page will only include the ShareMenu, which is dynamically loaded. React will resolve boundaries client-side."

So the direction it's heading, you'll get the best of both worlds.

Re: The absurd complexity of server-side rendering

#174
post #120

https://htmx.org/ Having spent 36+ years in the computer industry, I consider the advent of htmx to be the first thing in web development to to attempt to pull the industy's head out of it's ass. Don't forget to include a solid remake of css in your project like tailwindcss. It also makes code much more readable.

When fetching from the backend, the docs recommend returning snippets of html instead of JSON. Is it technically valid to return a snippet of HTML with a content type of “text/html”? There’s no standards saying you need !DOCTYPE or a head or body?

I guess it's not valid, although the impact might be that big if it's only you calling your own endpoints. If you want to be really correct you could use your own content type under the vendor tree: https://www.rfc-editor.org/rfc/rfc6838#section-3.2.

E.g.

Content-type: application/vnd+yourorg.htmlx+html-snippet

Re: The absurd complexity of server-side rendering

#175
post #17

Earlier quoted context omitted.

Adtech needs a lot of JS to work. JS to determine how long they are hovering over this and that element, how long this or that ad is in their view, and so on and so forth. The logical conclusion is that every single HTML element needs to be wrapped in a bit of JS somewhere. Nothing should happen in the users browser that can't be monitored by JS.

This is a gross mischaracterization of what's happening. People want to build interactive pages and products with neat little shiny user-friendly doodads. JavaScript provides that ability. SSR allows you to write JavaScript that will be rendered before the user ever sees it so all that effort that went into making browsers really good at rendering HTML can work for your interactive applialcation too. I have to assume…

Angular.js came out of Google. React.js came out of Facebook.

I promise you this is not a coincidence. You can use these frameworks to build cute toys, but they were built to advance certain business interests.

Re: The absurd complexity of server-side rendering

#176
post #73

Earlier quoted context omitted.

> documentation sites, blog-like sites Sites like those can often be fully static sites. Process the docs or the blog posts into HTML. Nothing is generated at runtime. Of course you can cheat a tiny bit, like putting the date in the footer, or cheat a lot. Life's a lot simpler if you don't cheat at all.

I've tried this twice and it didn't work out for me. If you want even just some features like categories and tags you end up with a tool that has some weird metadata language you put over the actual text, the markup obviously is yet another slightly different kind of markdown, and then learn the umpteenth way of linking to internal sites. Then you run the generator, triple check everything is not messed up because of…

I don't think I understand your point. Weird markup vs WYSIWYG authoring is orthogonal to static vs dynamic serving.

Re: The absurd complexity of server-side rendering

#178
Nexus DocUI is server-side defined, but client-side rendered. It doesn't have real-time updates yet, you have to reload the page, but I'm working on a plan to implement that. Currently renders the front-end with Flutter, the back-end could theoretically be any language since it sends JSON to the front-end.

https://nexusdev.tools

Re: The absurd complexity of server-side rendering

#179

Earlier quoted context omitted.

When fetching from the backend, the docs recommend returning snippets of html instead of JSON. Is it technically valid to return a snippet of HTML with a content type of “text/html”? There’s no standards saying you need !DOCTYPE or a head or body?

I guess it's not valid, although the impact might be that big if it's only you calling your own endpoints. If you want to be really correct you could use your own content type under the vendor tree: https://www.rfc-editor.org/rfc/rfc6838#section-3.2 . E.g. Content-type: application/vnd+yourorg.htmlx+html-snippet

Some discussion here https://stackoverflow.com/questions/19303361/content-type-fo...

Basically that nowadays it’s fine to use text/html for html fragments, because the content is still html, even if it’s not a full document.

Re: The absurd complexity of server-side rendering

#180
post #120

https://htmx.org/ Having spent 36+ years in the computer industry, I consider the advent of htmx to be the first thing in web development to to attempt to pull the industy's head out of it's ass. Don't forget to include a solid remake of css in your project like tailwindcss. It also makes code much more readable.

What's the difference between this and AlpineJS?

I think it's just an alternative https://www.libhunt.com/bigskysoftware/htmx
Post reply on HN