I like Tesla. I think they are a great company, working towards a better future. That's why I was on their website recently, on a pretty average connection, and I noticed that it is loading very slowly. So of course, me being me, I opened Firefox dev tools and started digging around.
TLDR: At the end of the day I managed to speed up homepage time to interactive from over 17 seconds to around 4 seconds by removing unnecessary things and optimizing assets delivery.
This two-part article series is meant to show a real-world use case of how you can:
- Notice problems - Run webpagetest / Lighthouse on your website
- Identify rooms for improvement - Look for heavy resources, number of requests and pay special attention to CSS because it's blocking
- Fix
- Remove what's not needed
- Split into smaller chunks what is needed
- Lazy load what is not critical
- Load on demand what is not used by at least half of the users
Those are the easiest techniques, that don't involve rewriting the code or changing any functionality of the page, which is what this audit/article is supposed to demonstrate.
Problems
After running webpagetest and Lighthouse on the site, I identified the following problems:
- The main photo is in PNG format (7.7 MB)
- Non minified Boomerang.js library (http://www.boomerangjs.org/)
- Some fonts are inlined inside CSS but never used
- Some fonts are inlined, but really should not be
- Most inlined assets are duplicated (huge savings can be achieved there)
- Some assets for all 44 languages are included in the main CSS file, even though a user can use only one at a time
- A lot of media queries, which at this size should be separated into multiple CSS files
- Main JS file is heavy and it looks like it could be divided into smaller parts and lazy loaded
We won't tackle some of those problems, because the nature of JavaScript is too complicated and I don't know this website well enough to decide which script can or cannot be loaded on demand. This is a task for Tesla developers, I can only help their decisions with my advice.
Solutions
I did the following to speed up the site:
- Compress image and use JPEG format - saved 6.7 MB + improved perceived performance by using progressive JPEG
- Remove unused font - made the page lighter by 150 KB, and because it was inside CSS, it is no longer blocking rendering
- Minify the boomerang.js library - 120 KB → 40 KB
Performance before
I made some baseline measurements using webpagetest.org (see report) and Lighthouse:
In webpagetest, the most significant thing is Largest Contentful Paint. This means that this 7 MB hero image was loaded after 16 seconds.
In the Lighthouse test, I like to pay special attention to Time to interactive, and First CPU Idle - this indicates when the user can start using your page (meaning, JavaScript is not blocking the main thread anymore).
Head image solution
Let's address the first issue first because it is the lowest hanging fruit of the bunch and does not require any technical knowledge. As I wrote in my article Optimizing Images for the Web you can basically tell which format should be used for an image by the contents of it. In this case, it should be JPEG and I'm going to use MacOS Preview to save it as a JPEG and then compress it using ImageOptim.
To make sure that I'm not going to degrade the quality of the image (it is a product page, so it has to look good) I used quality >90, which produces minimal artifacts. Results are pretty good, saving over 7 MB on that one image. Additionally, JPEG is progressive, so it will load in a much more pleasant way than PNG.
Unminified boomerang.js library
This is also a simple task to do, just take the contents of the file and paste it into a JavaScript minifier. If you use the DuckDuckGo search engine, just type: "js minifier online" and it will pop right up. Minification made the file smaller by 80 KB, 120 KB → 40 KB. Not bad for 20 seconds of work.
Unused font
I noticed that the book-override.font.css
file had inlined some Gotham fonts, but never used them. I removed the reference to them from the HTML file altogether.
Result
As a result of those operations, the site got lighter by around 7 MB without any advanced techniques.
Let's see what Lighthouse says about it (after it has been uploaded to platformOS as hosting):
A little bit better. Let's hope the next steps will improve it further.
In part two of this series, we will take a look at the huge (2.5 MB!) CSS file and cut it down to 365 KB.
Update
Since I started writing this article, Tesla.com did exactly what I described here in regards to images, and even used more aggressive compression, so their image is 370 KB, which means there was no need to have it in such a good quality after all. :)
Source code
You can see the results and source code here:
Part 1: https://github.com/pavelloz/tesla.com - https://tesla.prod01.oregon.platform-os.com/part-1
Part 2: https://github.com/pavelloz/tesla.com/tree/part-2 - https://tesla.prod01.oregon.platform-os.com/part-2/ and https://tesla.prod01.oregon.platform-os.com/part-2-de/
Read more
If you are interested in more performance oriented content, follow me and I promise to deliver original, or at least effective methods of improving your website.
Top comments (6)
Also never use <img src='' /> for bulk image rendering.
It will block the engine and make page little bit unresponsive.
Pull image via fetch() in web-worker and generate blob as well and just assign the blob in src.
Images are not blocking, so pushing them wherever, especially to web worker seems like a bad idea, because web worker needs to be downloaded, executed as well. Thats adding links to the chain. Not only it would load slower (and its a header image, which you want to load fast) but it would also add complexity in a place where browsers are very good at optimizing.
And all the below-the-fold images are pushed to low priority so they are not blocking anything (especially if loading="lazy" is used)
You can verify that in chrome dev tools:
Explained here : dev.to/trezy/loading-images-with-w...
Except the article is based on an incorrect assumption.
"Turns out, we can construct the render tree and even paint the page without waiting for each asset on the page: not all resources are critical to deliver the fast first paint. In fact, when we talk about the critical rendering path we are typically talking about the HTML markup, CSS, and JavaScript. Images do not block the initial render of the page—although we should also try to get the images painted as soon as possible."
developers.google.com/web/fundamen...
okay, but loading image via blob have beneficial too.
check out a small project of mine : jswalker.in/its/gladit
generate via blob and web worker.
Why would i generate blobs and add complexity of web workers to load an image? Browser is very good at loading an image without it.
Your demo is really a different case - you are loading lots and lots of images and none of them is "the most important" - tesla website has one image and its covers 100% of the page above the fold, so it needs to be loaded ASAP.
PS. What you used on this page is service worker not web worker and if im honest, im pretty sure that if you removed it and replaced it with plain old img tags it would load much much faster. Maybe thats material for a quick dev.to article ;-)