Hacker News new | ask | show | jobs
by seanwilson 2052 days ago
So instead of pursuing the idea of server pushing your CSS so the top of your page renders fast, the best option is to inline CSS directly into the page but lose caching benefits between pages?

Crafting a fast website is going to be messy and difficult for a good while still.

5 comments

A "fast website" is super-easy to create if you don't add dozens of megabytes of useless crap to each page.

Two decades ago: hardware was slower, bandwidth was far more constrained, and browsers didn't have so many features nor take up so much resources --- and yet the speed of page loading was often much better than it is today!

Indeed, most of the "problems" web developers complain about are self-inflicted.

Things weren't just slower, they were orders of magnitude slower. It's ridiculous how we've managed to make computers ludicrously fast and the developer response has been to keep adding garbage until they are slow again.
Same with disk sizes and game file sizes, it's common to see 60gb+ installs for AAA titles.
Games specifically primarily take up space due to art assets. A high fidelity modern AAA game full of thousands of 4k+ textures, super-high-poly models, detailed animations, and hours of high quality audio is going to take up a lot of space. There are certainly optimizations to be had, but there's no way a 60GB+ game today would ever fit on, say, a DVD, at the same level of fidelity while maintaining the same player experience.

Higher compression means longer load times, so there's incentive to not compress more than absolutely necessary, and the biggest games tend to have huge worlds, which means you can't hold the whole world in memory at once. So you have to stream it in.

It's a constant balancing act between your nominal hardware target, the space the game will take up, up-front load times, and the amount of stuff that can be in a scene before the hardware can't keep up and you get model/texture streaming pop-in, stuttering, or an otherwise degraded player experience.

Perhaps in the next few years we'll see games leveraging super-resolution AI to quickly produce usably high-res textures from lower-res installed ones in storage faster than a directly compressed equivalent could be.... or games will leverage the same to take what they already ship and make it even higher detail...

> but there's no way a 60GB+ game today would ever fit on, say, a DVD, at the same level of fidelity while maintaining the same player experience.

I mean, you could make a modern open-world game where all the textures are procedurally generated from set formulae, ala https://en.wikipedia.org/wiki/.kkrieger .

It might even load quickly, if the texture generation algorithms were themselves parallelized as compute shaders.

But it'd be a 100% different approach to an art pipeline, one where you can't just throw industry artists/designers at the problem of "adding content" to your world, but instead have to essentially hire mathematicians (sort of like Pixar does when they're building something new.) Costly!

I don't know if you're being ironic or not. We would obviously not have as many great games if only math nerds were allowed to design them.

In fact, games are one of the few areas where all those compute/storage resources in private PCs are mostly justified.

I’ve shipped almost pure HTML landing pages (Single kBs of total JS, none of it render blocking) in the last few years, and inline CSS and preload headers help a lot, especially for older devices. Expectations for image/video resolutions in particular have gone up since “the good old days”. You can really see the effect with much older devices, which become the majority once you look outside the US and EU.

IME most people trying to optimize their way out of tag manager, monolithic SPA hell don’t generally bother with these kind of features outside of turning on all the cloudflare rewriting and praying. If performance was important to them and they knew what they were doing, they’d fix those first.

This is like when people complain about legacy code they first see it without understanding the context the code was written in. Or saying C coding is safe if everyone was just more careful and more skilled.

It's just not true that it's super easy to write fast pages. There's a huge amount of background you need to understand to optimize fonts, images, CSS, your server, your CMS, caching, scripts etc. There's multiple approaches for everything with different tradeoffs.

Even if you have the skills to do this solo, you might not have the budget or the time or the approval of management. Big websites also require you to collaborate with different developers with different skillsets with different goals, and you need to keep people in sales, graphic design, SEO, analytics, security etc. roles happy too.

Typical page loads were much slower two decades ago than they are today by my recollection, unless you were lucky enough to have something better than 56k dialup.
Server push arguably doesn’t bring caching benefits if you have to push the same CSS file as part of every request for any page. With browsers already able to eagerly parse <link preload> out of the head and HTTP/2 multiplexing concurrent connections you’re looking at saving a single round-trip time, once and adding bandwidth overhead to every other request for a page.
There's no solution to fix this problem with push though by changing how push works? A single round trip is significant on slow mobile connections.
No, it's not possible. It will take a round trip for the client to tell the server if an object is cached.

So you have two options:

1. Pessimistically start pushing the response, and stop if the client tells you it is already cached

2. Optimistically don't push the response until the client tells you that it doesn't have it cached.

The first option is what push does.

The second option is basically equivalent to sending a `Link: <..> rel=preload` header.

So I guess one way to look at is that we had both choices available. But it turns out that Push wasn't used much and probably isn't the best option.

> It will take a round trip for the client to tell the server if an object is cached.

Why wouldn't the client be able to give the server some information about what it has cached already when it makes the initial GET request for the HTML page?

"It is not possible" is an overly strong claim. But the options I can think of are not great.

Uploading an entire list of cached resources probably isn't feasible (and probably not possible or a privacy concern).

You could maybe do a bloom filter but probably still have privacy concerns.

There is a solution that mostly works. You can use cookies! A simple solution might be setting a cookie for the app version when you respond. On the next request you can avoid pushing resources that haven't changed between the client's last version and the current one. Or you can even try to set cookies for each asset, however I'm not sure that is a good strategy.

But this is still not perfect. The presence of the cookie doesn't mean the resource was ever downloaded (maybe it was aborted partway though?) and things can get purged from the cache and the cookie has no way of knowing.

You can also try to do out-of-band info. For example storing in a database which resources the client has downloaded before and a bunch of heuristics to determine if they are likely still in the cache. But at the end of the day only the client knows that.

So the TL;DR is I'm not sure this is possible. You are looking for `required resources - cached resources` and since `cached resources` is sensitive and probably much larger it is way easier to do this computation on the client.

So TL;DR it might be possible but is very tricky. The current state-of-the art isn't anywhere near a perfect solution.

I would think the best option would still be to have the css in a separate file unless your css is very small. It is of course a tradeoff between if the extra RTT hurts you more than the extra bytes in your page (how much that matters depends on how big your page is and tcp window sizes), and how often your users are viewing your website totally uncached.

Keep in mind, that even without server push http/2 still fixes head of line blocking which was a major reason that the folk wisdom of inlining things and using sprites popped up in the first place.

Well the best thing is to in-line only the CSS needed for content actually in the server render if it’s much smaller than total site CSS. If you’re code splitting your CSS in the first place this is usually handled pretty well by the same mechanism. Then CSS is still cacheable across page loads for later navigation (particularly if you use a ServiceWorker in lieu of server rendering once enough core assets are cached).
Yes but inlining the critical CSS only for every page isn't trivial, and usually involves complicating your build chain.

I'm not saying there's a perfect solution, it's just interesting they're giving up on push.

Or use <link rel="preload"> I guess (bonus: local caching still works).
You then have to wait for the preload content to arrive before your page starts to display though.