I'm down the rabbit-hole of website speed optimization. I have a site that's getting terrible marks from all of the usual suspects (PageSpeed and GT Metrics, specifically; it looks OK on Pingdom tools).
My setup is a single T3-Medium server running Apache and Wordpress, behind an AWS ELB, with deployment to CloudFront as the CDN.
My first attempts to improve performance included
- upgraded to Medium (the server runs about 1/2-dozen websites, but they're tiny — collective traffic across all of them is only a few-thousand visits a day — nevertheless, a "Small" instance was too sluggish on even a single hit, because of memory constraints),
- installed the WP Super Cache plugin (I was already running behind CloudFront, but installed the plugin to actually cache the pages themselves)
- Added cache-control headers to the CloudFront behaviour
- Removed query strings from the cache key (this isn't a traditional e-commerce site, and twitter ads was adding a unique string per user, which was basically making every page view a cache miss)
However, even with that, the default performance is unacceptable. The culprit seems to be javascript delivery (and execution). Here are some results from GT Metrics, based on how much manual intervention I perform:
Cache-Miss Cache-Hit Cache-Miss Cache-Hit Cache-Miss Cache-Hit
Default Default Hammer YouTube Hammer Youtube Sledge Hammer Sledge Hammer
TTFB 1,100 91 75 66 75 72 | 74 74 122 74 54 75 | 76 86 104 86 63 45
FCP 2,200 1,100 4,200 494 519 383 | 1,100 2,700 1,400 710 415 622 | 1,200 1,200 1,200 388 338 256
LCP 3,300 2,000 6,300 1,900 1,700 1,800 | 1,800 3,500 2,000 2,700 881 1,600 | 1,900 2,000 2,500 684 617 490
Onload 4,600 3,200 7,600 2,300 3,000 2,700 | 2,900 4,900 2,700 3,100 1,500 2,500 | 2,000 2,000 2,400 766 824 489
TTI 4,700 3,300 7,600 2,500 2,900 3,200 | 3,000 8,000 2,800 3,400 1,700 3,000 | 8,000 6,800 1,200 6,700 6,700 6,400
As you can see, if I don't do anything (the first two, "default" subtables), the site is taking nearly 3 seconds to load with a cache hit, and often north of 4 on a cache miss.
This is really the root of the question. What should I do from here? I'll describe what I'm now doing, below, but I don't believe what I'm about to describe is standard practice on the Internet, and clearly the Internet isn't, in general, suffering from this kind of performance.
Applying A Sledge Hammer
I'm not sure which of those metrics matter most from a user-experience perspective, but I suspect in my case it's LCP and onload (I can imagine for some websites it's TTI, but in my case there's nothing to do above the fold, so the old First CPU Idle metric would have been great, if Lighthouse were still reporting it).
What I'm doing now is what I have in the "Sledge Hammer" section of the table. I wrote a script that strips out all non-essential javascript src tags, and only puts them back after either 5 seconds or first user interaction. You can see the results. Even on a cache miss, the site is loading in around 2 seconds, and on a cache hit, it's well under 1 second (we can ignore the TTI number, because that's my 5 second delay, and isn't affecting above-the-fold appearance or interactivity).
OK, the site is "working", but really, not only does it seem like one shouldn't need to do this in the abstract, but also there's some javascript I'd really love to have working from the beginning.
Digging in, the problems all seem to be third-party JavaScript (i.e., stuff that isn't / can't be on my CDN). Some of this is just egregious, and I can deal with it internally (e.g., I can tell the marketing people, "Only use HotJar when you really need to, then turn it off — it adds a full second to page-load time"). But some of it is just "Internet standard" — Stripe and Google analytics are each adding ~500ms between load time and run time.
I can continue to fine-tune my sledgehammer, as Tim suggested in the comments, but this still doesn't feel right. There has to be something I'm missing in terms of this set-up and (particularly third-party) JavaScript.