The Fastest Blog in the World
jacquesmattheij.com
jacquesmattheij.com
Take the first paragraph, about how Google's homepage of just a textbox should really be a few hundred bytes instead of a megabyte. Google's homepage does a lot more than just enabling you to enter a search - there's the autosuggest feature, there's analytics, the apps tray, G+ integration with live updates, etc. Google's homepage looks basic but under the hood there's a lot going on. Which is the real crux of the matter - Google have designed something that doesn't get in the way of searching but is really a powerful portal to Google's suite of services because that's what gets them the data that makes them money. The fact they might be able to shave a milliseconds off the domContentLoaded time (which is only 394ms on my work PC) wouldn't make anyone happier but it would damage their bottom line because they'd know less about us.
If Jacques blog gets a significant amount more traffic by loading super fast then that's a definite, measurable success. If the only change is that it loads faster, and he doesn't grow his audience, then he hasn't really achieved anything.
There's a good lesson in this that's analogous to startups that spend huge amounts of time and money doing things that get them no additional customers. Optimising things that don't affect the metrics you use to measure how successful you're being is a waste of effort. Put your time in to things that actually matter.
> If Jacques blog gets a significant amount more traffic by loading super fast then that's a definite, measurable success. If the only change is that it loads faster, and he doesn't grow his audience, then he hasn't really achieved anything.
If audience growth were the target, then yes that's true. But what matters too is that the audience that you already have does not spend more money (downloaded bytes on mobile for instance) or time (delay time waiting for stuff to load) than they really need to. On top of that I suspect (but can't prove) that a faster site will lead to people viewing more pages on that same site simply because of the convenience. For ad driven sites (which this is definitely not) that might turn into more turnover, and for e-commerce sites (which there is plenty of proof for) faster load times result in more turnover.
Keeping your users happy is important, even if you don't attract more of them directly. (Retention is a very important factor in a growth strategy...)
Premature optimization is definitely the root of all evil, but bloat is something you can do without. It's a matter of striking the right balance and I think that this blog probably is on the 'wrong' side of that balance but I just wanted to make an example of how much bloat there really is.
I'm reasonably sure that this theory is backed up by data. I don't have the time to look up the studies just now, but as someone with a professional interest in this, I'm pretty sure I've seen them in the past.
Certainly, page speed has a surprisingly large impact on overall user experience - backed up by studies like Amazon's and Google's, both of which showed a correlation between faster page load and increased user activity.
it assumes that anything under 400ms response can add to the addictiveness of a user interface.
For me, Google’s homepage circa 2005 was just as useful as the current one (or more useful even, since their results weren’t as crapped up by SEO spam sites, and the search syntax itself was more power-user friendly and predictable).
I used to occasionally click google ads, but they’ve gotten so obnoxious that I just zap the domain in /etc/hosts. I used to exclusively use google search, but it’s gotten slow and annoying enough that I now mostly use duckduckgo instead.
Clearly that’s not the main part of their user base, but spending a decade chasing money at the expense of user experience isn’t all upside, even for Google.
<html>
<head>
<style type="text/css">
html,body { margin: 0, width: 100%; }
body, input { font-family: Verdana, sans-serif; font-size: 1.2em; line-height: 1.4em; }
form { margin: 20% auto; width: 26em; }
</style>
</head>
<body>
<form action="https://www.google.com/search" method="get">
<input type="text" name="q" placeholder="search" size="30">
<input type="submit" value="google">
</form>
</body>
</html> data:text/html,%20%20%20%20%3Chtml%3E%0A%20%20%20%20%20%20%20%20%3Chead%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20html%2Cbody%20%7B%20margin%3A%200%2C%20width%3A%20100%25%3B%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20body%2C%20input%20%7B%20font-family%3A%20Verdana%2C%20sans-serif%3B%20font-size%3A%201.2em%3B%20line-height%3A%201.4em%3B%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20form%20%7B%20margin%3A%2020%25%20auto%3B%20width%3A%2026em%3B%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fstyle%3E%0A%20%20%20%20%20%20%20%20%3C%2Fhead%3E%0A%20%20%20%20%20%20%20%20%3Cbody%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cform%20action%3D%22https%3A%2F%2Fwww.google.com%2Fsearch%22%20method%3D%22get%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20type%3D%22text%22%20name%3D%22q%22%20placeholder%3D%22search%22%20size%3D%2230%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20type%3D%22submit%22%20value%3D%22google%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fform%3E%0A%20%20%20%20%20%20%20%20%3C%2Fbody%3E%0A%20%20%20%20%3C%2Fhtml%3E
:-) data:text/html,%3Chtml%3E%3Chead%3E%3Cstyle%20type%3D%22text%2Fcss%22%3Ehtml%2Cbody%20%7B%20margin%3A%200%2C%20width%3A%20100%25%3B%20%7Dbody%2C%20input%20%7B%20font-family%3A%20Verdana%2C%20sans-serif%3B%20font-size%3A%201.2em%3B%20line-height%3A%201.4em%3B%20%7Dform%20%7B%20margin%3A%2020%25%20auto%3B%20width%3A%2026em%3B%20%7D%3C%2Fstyle%3E%3C%2Fhead%3E%3Cbody%3E%3Cform%20action%3D%22https%3A%2F%2Fwww.google.com%2Fsearch%22%20method%3D%22get%22%3E%3Cinput%20type%3D%22text%22%20name%3D%22q%22%20placeholder%3D%22search%22%20size%3D%2230%22%3E%3Cinput%20type%3D%22submit%22%20value%3D%22google%22%3E%3C%2Fform%3E%3C%2Fbody%3E%3C%2Fhtml%3E> If the only change is that it loads faster, and he doesn't grow his audience, then he hasn't really achieved anything.
If this makes his readers happier, it is a success nonetheless.
Maybe this is a startup/HN thing that everything must grow and grow. But that isn't the only successful strategy, even from a purely economic point of view.
If you have a niche, and serve that niche very well, you can beat your competitors by quality rather than quantity. Not all niches are large. If you manage to cover 100% of your niche, it is a huge success! - even if 100% means just a few thousand people.
If there wasn't so much crud being transmitted I would be out an entire business, on the other hand, the entire internet would be a much nicer place
[1] https://www.branded3.com/blog/billion-dollar-javascript/
Before I had to scroll and the page shoots to the bottom. Talk about not knowing what you write about...
Sure he has achieved something. He has made his readers a little bit happier. Presumably, he has also made himself a little bit happier. It's called progress.
CSS doesn't minify particularly well since the class names, tag names, and attributes all have to stay in their full form. Basically it just ends up being removing extraneous whitespace.
However, ever since reading James Hague's post on "Extreme Formatting"[0], I've rather liked CSS without all the extra whitespace. For example, [1]. You can see all the rules at a glance, and while it's a bit weird at first, I think you can get used to it pretty quickly. But then again, I've always sort of thought APL/J/K are beautiful in their own way.
[0] http://prog21.dadgum.com/200.html [1] http://prog21.dadgum.com/p21.css
Looking at the page source for the "fastest blog", there's still far more formatting info than content. Much of that bloat isn't doing anything.
The 'payload to wrapper' ratio of that page is excellent.
It's idiotic that you are punished when you use HTML like it was supposed to be used but that's unfortunately how the mobile browsers work currently.
There's the extension "Stylish!" for Chrome and Firefox which has quite a good UI for giving the power of styling websites back to the user.
The Google homepage does a lot more than that. Since it is one of the most important pages for Google, I think that the engineers over there know what they are doing. I don't think it is a good example of bloat.
That's because you didn't consider the business reasons behind it being 1170Kb.
If it was your "few hundrend bytes" design it would have sank the company (or only have worked in the early days, when VC money took care of lack of income sources).
I've updated the article with another example (a BBC news page).
Thanks!
It only really starts getting js-heavy after about 2010. Evidently the relative cost of bandwidth and value of analytics have crossed over.
As we move to price per Gb of download from 'all you can eat' I think that page payload may become more important.
Browser caches solve a lot of things for us. Though you're still parsing a bunch of JS, google's front page is "only" fetching 56kb
Granted, this blog post is 13.5kb, but it doesn't have an entire search app embedded into it (with the whole search results automatically appearing thing, I imagine that inside that 56kb is pretty much all the code required for all of google's little widgets in the search results)
Anyways, always fun to see somebody go in and rip out as much cruft as possible
Apparently they don't. I remember reading 2-3 articles on the issue, and most things we'd expect to go there, don't even touch the browser cache.
Maybe for Google (a page we visit every day multiple times) that would be different, but for your average site the browser cache could as well be a forbidden zone with all the competition for the same limited resource.
Also, if your blog doesn't change often, it will also be seldom visited[2]. So the browser cache may not help here - either due to cache invalidation, or because you changed a tiny bit of your CSS in the meantime.
[1] And honestly, from that perspective all blogs are small.
[2] Ideally, all your readers use Atom/RSS.
Inlining the CSS was considerably faster in all my tests.
Though at that point gzip is probably the better solution.
I'd expect in-lining the css to be a slight net loss once the data is cached - my strategy would be a `style-<md5sum>.css` with a long max-age.
I wish browsers could cache page fragments!
I expected that too but it didn't work out that way. I'm not sure why, possibly a cache lookup is still slower than reading the style info out of the same page. I don't know enough about the guts of a modern browser to make the call but the numbers aren't there.
Can you expose your methodology, or are you using a common tool for testing these things?
I was not expecting to see such a difference between the two browsers, but I'm not familiar enough with firefox to guess what's causing it :-\
No idea how it’d handle 500 blog posts - but there’s only one way of finding out!
302 pages created
267 categories created
gin 1149 ms
real 0m1.613s
user 0m1.180s
sys 0m0.408sThe first time, the browser will receive it approximately as fast as the inlined version; subsequent times, there is no overhead, moreover browsers can load the stylesheet only once rather than needing to load it for every page.
I use wintersmith to generate it, and it is hosted by nginx in an EC2 t1.micro
X1C3:~$ httping http://natalian.org
PING natalian.org:80 (/):
connected to 54.192.159.125:80 (147 bytes), seq=0 time= 91.36 ms
connected to 54.192.159.123:80 (147 bytes), seq=1 time= 28.63 ms
^CGot signal 2
--- http://natalian.org/ ping statistics ---
2 connects, 2 ok, 0.00% failed, time 1394ms
round-trip min/avg/max = 28.6/60.0/91.4 ms
X1C3:~$ httping http://jacquesmattheij.com/the-fastest-blog-in-the-world
PING jacquesmattheij.com:80 (/the-fastest-blog-in-the-world):
connected to 62.129.133.242:80 (329 bytes), seq=0 time=550.05 ms
connected to 62.129.133.242:80 (329 bytes), seq=1 time=550.08 ms
^CGot signal 2
--- http://jacquesmattheij.com/the-fastest-blog-in-the-world ping statistics ---
2 connects, 2 ok, 0.00% failed, time 2760msBut then your css had to load... that was another 104ms. ;)
Pretty awesome.
Pretty good though, I think if you inline the CSS you'll win hands down :)
The first Java version of an internal app we had converted from Progress 4GL used Java Webstart to dynamically load & launch, and because of programmer laziness (and the 93 3rd party Java components they'd included) it literally took 3 minutes to launch. That was the point where the manager -- who was a better programmer than anyone in the team, but who had previously been hands-off -- stepped in and created some rules and instituted code reviews. Still, though, totally insane behavior by so many young web programmers.
robertsky$ ping localhost
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.051 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.049 ms
yep... looks right. PING hliyan.github.io:80 (http://hliyan.github.io):
connected to 103.245.222.133:80 (360 bytes), seq=0 time=525.96 ms
connected to 103.245.222.133:80 (360 bytes), seq=1 time=555.35 ms
Edit: Connecting from Sri Lanka though (not via Loon, just our regular old ISPs :)Your site is definitely better than most though.
Also, with respect to the numbers you quoted, those are much more related to how many hops the traffic has to traverse than how efficient your site is.
PING gotchacode.com:80 (/):
connected to 104.28.19.6:80 (651 bytes), seq=0 time=540.86 ms
^CGot signal 2
--- http://gotchacode.com/ ping statistics ---
1 connects, 1 ok, 0.00% failed, time 1259ms
round-trip min/avg/max = 540.9/540.9/540.9 msBut not as bad as most, so there's hope :)
Many of my posts use images and I use Google Analytics so I made a text only one and disabled GA to see how it compares. With your trick of the inline stylesheet I got a massive speed improvement[0], down from about 100ms to between 60-70ms.
I too use Hugo. I host the site on a $10 VPS from digital ocean located in London, but I also use Cloudflare to speed up image delivery.
I'm not sure where your site is physically hosted but testing from Amsterdam we're pretty much the same given the 1KB page size difference.
Very cool post and thanks for the tips!
[0] http://tools.pingdom.com/fpt/#!/bvkhPp/http://josharcher.uk/...
The "Recent Tweets" part of this site feels somehow at odds with the principles though. It's got nothing to do with the actual page, and has a really bad ratio of markup to content. Those 20 tweets are still 11kB uncompressed! It's also a very heavy visual element.
I'd be interested in seeing some waterfall charts comparing this setup with something that keeps the number of total requests small (say 3-5 requests) and evenly balanced. Particularly as we move toward HTTP2, having lots of small parallel requests will be a more effective way of getting raw page load performance.
The speed gains from eliminating all but the most necessary components is definitely the biggest win here, though - cool to see what you can do when you decide to get focused about what needs to be on the page.
When you're loading less than 20KB of content, I don't think there are any speed benefits of parallel requests. I suppose in theory an extremely slow mobile connection might benefit, but extremely slow mobile connections tend to have very high latency and packet loss that make the cost of additional requests hugely outweigh the benefits.
For instance, just taking the CSS out and loading that separately doubled the page rendering time (because another resource had to be loaded after the first one).
Now it is just like a 'declare before use' program in a regular programming language, by the time the browser reaches a tag that needs definitions from the CSS the CSS is already there, right there in the page, no need to wait until reading that separate resource is done. And that round-trip to the server is actually more expensive than the entire embedded CSS. Looking at it after going through the whole exercise it makes sense but that was definitely not what I expected. Even more counter-intuitive: this holds even when loading multiple pages on the same site that share the same (small) CSS file.
So in the end the inlining of the CSS was a good thing to test. Presumably, there is some cross over point where if the CSS file gets very large there is a benefit for follow-up pages on the same site to be able to re-use it.
Is there a way to instruct Hugo that once a crossover point is reached to unbundle the CSS? That'd be sweet.
Is there a way to concatenate multiple Markdown files into a single post?
The reason I ask is because I've recently started building a site that has weird hand-rolled static Markdown pages served up dynamically by a Rails/Bootstrap combo. The kicker, some of the pages are very long so I've split them up into multiple files to make them cognitively easier to edit. I'd be interested if I could drop the Rails part :)
Thx in advance
ps: I'm now too afraid to measure the page load times of my Wordpress blog now :(
Not that I'm aware of, Hugo is pretty much of the 'sausage grinder' variety of blog post generators, not much in terms of decision making during the processing from what I've seen so far. I also ran into a pretty serious bug while doing this and there are likely more. Still, as fresh as it is it performs amazingly well and the authors are super helpful and worked hard to track down and fix that bug.
> Is there a way to concatenate multiple Markdown files into a single post?
Again, not from within hugo but that one should be fixable with some pre-processing. I use a makefile that does some pre and post processing.
> I'm now too afraid to measure the page load times of my Wordpress blog now :(
Do it anyway, that will give you a nice before-and-after benchmark.
Did you verify that the cache headers where correct, and that the CSS file was only loaded once? It's certainly possible, but indeed surprising (to me) if the actual overhead of parsing the html (and then the css - 2x render time) is that big?
[ed: Did you see the same pattern using local static files?]
The configuration line reads:
ExpiresByType text/css "access plus 1 week"
And I verified that it worked using a commandline http tool as well as the firefox developer tools (network section), on the second view it only loaded the page and not the CSS.So while intuitively, the parallel request seem like the faster option, it's probably likely in this case, that the single page in-lined option is optimal. (Even at the expense of ever so slightly more bandwidth)
I guess you're optimizing for people who only visit one page and bounce away?
Well, come to think of it, the majority of visitors who followed this HN link is never going to navigate past the single page that was linked. So it probably makes sense for optimize for them, at the expense of repeat visitors who will have to download the stylesheet over and over again.
I've noted a few techniques I've used on my blog to get pages served in a single request to users, including using SSIs and avoid cloudflare's "rocket loader"
2. Using Hugo instead of Octopress won't make your site any faster to users ¯\_(ツ)_/¯
3. You're almost completely forgetting about server-side performance. I'd recommend looking into GitHub Pages for a free and fast (CDN-backed) way to host a static site.
---
Unrelated, but:
4. I'm not a fan at all of the self-upvoting link at the bottom of your post. Not cool.
You could try out Addy Osmani's tool, Critical, for extracting and inlining critical path css. That only leaves out the css in actual use. If you actually want all css in use (also below the fold), then just specify a bigger window size.
I believe Chrome's devtools can do that. (See the Page Audit functionality).
That will probably load really fast. You can server-side cache the post comments section fragment (or the render of the entire page really) to get nice results
The webfont kills me without that it'd be under I think.
(That being said, please don't do this. Minified JS is bad enough.)