 So last time we worked on our visuals. We added images and CSS, and now we have something that actually looks like a real block. But also, it's at this point in development where you have to start to worry about the weight of your site, because all of these images and the CSS files add weight. Add file size has to be downloaded for the site to actually appear as you like. So if you are developing on your big desktop machine with a big screen and a good network connection, everything might feel great and look great. But if you serve the exact same experience to a Moto G4 phone on a 3G network, it might feel very, very differently. So we've already talked about a bit how you can streamline your loading to make it feel faster for the user. But another thing that you can look into is caching headers. Caching headers help the browser only download the things that have actually changed. And I thought that was very important and I wanted to implement it correctly in my blog. I've already given some tips in the past on caching headers and a micro-tip, so I'm gonna link to that one in the description down below. But let's do a quick recap. So the advice that I usually give is to segment your files into two groups. The one group is the files that are entry points to your app, which is usually your HTML files. And the other group is all the rest, JavaScript, CSS, images, what have you. For the HTML files, you always want to revalidate with a server if the version that you locally have is still the most recent one. And the caching header for that is called must revalidate. So that means the browser has to check with a server if the version is still the most recent one. And if it is, it doesn't have to re-download. So it doesn't really save you time, but it does save the user's bandwidth and that's already a win. For JavaScript and CSS, you wanna put the hash of the content into its file name and then set the caching duration to a really long time. So in this example, I'm gonna choose max age and then something like 31 million. 31 million sounds big and it is big and it's roughly a year. So I'm saying these files are allowed to be served straight from cache without checking with the server for a year. And that's okay because if the file changed, the file name would change. We put the hash in there after all and that's why this caching procedure works. All these assets will be referenced by the HTML. So the browser will revalidate the HTML with a server, but if that didn't change, it can just use all the other assets from cache, doesn't have to hit the network and that will save us a lot of time. So I said the browser has to revalidate with a server, but I didn't really explain how that works. So in HTTP, there's two request headers that allow this mechanism. One is called if modified since and the other header is called if non-match. If modified since basically means I have a version cache that is from this state. If it has been changed after the state, please send it to me. If non-match basically says I have a version cache that has this specific e-tag. If the current version has a different e-tag, please send it to me. Both of these headers achieve the same effect in only downloading something when actually necessary. Just one is state-based and one is e-tag-based. I personally feel like the date-based version is a little bit less robust. So I prefer e-tags most of the time, but the problem here is that we are running a blog that is written in PHP and that means that most of our content is dynamically generated. So how would you generate a hash of the content of something that is dynamically generated? So it turns out there's actually a pretty neat trick in PHP that you can use to achieve that and I'm gonna show you how. So PHP has two functions. One of them is called OB start and the other one is called OB get clean. OB here stands for output buffer and it basically means that any output I generate will be put into a variable as long as it is between those two function calls. So that means instead of sending the output straight to the user, to the browser, I instead get it in a variable first. And then I can use this variable to calculate the SHA-256 hash of the content and this is the way how I can generate an e-tag for the content that I have generated. The only thing left to do is to do the matching myself if I actually need to send the variable or not. So I grab the if-non-match header from the request and see if my content hash and the one from the header match up and if that's the case, I just send a 304 saying no change, just reuse what you already have. And if they don't match, that's only when I actually echo the variable saying now actually do send the content to a client. We can see this in action in Chrome DevTools in the network tab. So if we clear out all the caches, basically start fresh and load our page, we can see in the network tab that we download about 300 kilobytes and that all of our requests have the status code 200. Because the cache is empty, nothing can be reused. But if we now reload the page after our caches have been warmed up, as I say, you can see that pretty much every request turns into a 304, meaning not modified. And the total download size went down to just one kilobyte because we could reuse everything that was already in cache and didn't have to download anything new. And that's pretty good, right? I think being mindful of your user's bandwidth is really important. You know when you're on this really bad hotel Wi-Fi on vacation, this is where all these techniques really help and you wish every website would use them. Next time, however, we are going back to some more front-end code and we are going to build a router. You know the thing, it takes care of transitions and making it all really shiny. So if you want to see that, subscribe and I'll see you next time.