Static Asset Caching Strategy
The video explains how to cache CSS, JavaScript, and images to prevent unnecessary re-downloads and improve load performance. It highlights using browser disk caching and CDNs to reduce latency, especially for geographically distant users.
CDN and Cache-Control Configuration
Assets are configured with Cache-Control headers specifying public, a max age (e.g., three months), and immutable to optimize long-term caching. This allows both browsers and CDNs to cache static assets effectively.
ETag-Based Validation
An ETag is generated using an MD5 hash of the file content combined with its length to create a unique fingerprint. If the browser sends a matching If-None-Match header, the server responds with 304 Not Modified, avoiding redundant downloads.
Production-Only Caching Logic
Caching headers are applied only in the production environment to prevent interference with development workflows. This ensures developers can see changes immediately without stale cached assets.
Cache Verification in Browser DevTools
The implementation is validated using the browser network tab to confirm memory and disk caching behavior. Initial loads fetch from the server, while subsequent loads retrieve assets from cache with near-zero latency.
Timestamp-Based Cache Busting
A UNIX timestamp is appended to CSS and JavaScript file URLs to signal changes when the server restarts. When the timestamp changes, the browser treats the asset as new and refreshes its cache.
Single JavaScript Entry Point
A unified scripts.js file is introduced to import all JavaScript dependencies. This simplifies asset management and provides a centralized, cacheable endpoint for script delivery.
Final Optimization Overview
The system now includes page caching, static asset caching, ETag validation, timestamp-based cache invalidation, and a consolidated JavaScript entry point. The setup prepares the application for efficient production deployment.
So that is page caching or a more generalized memory cache out of the way. We can now utilize that to whatever we need. But we also have these static assets that we don't necessarily want the user to have to redownload all the time because it could create this little flicker whenever they load the page. So we want to utilize the browser to do some un-disk caching, but also provide the proper tags or information so we could
run our DNS through something like CloudFare, and then CloudFare will take our assets, cast them for us, and then serve them to the user for a server that is closer than our server. I hope that makes sense, because we might have our server running in, say, Copenhagen, and then a user from NullBurn visits our site, and that is obviously going to be a long trip around to get the data.
Here, something like what is called a CDN in front. But it's also nice if it's just the initial load that is maybe a little bit slower. And then going forward, it's going to be a lot faster because the browser has all of the CSS and JavaScript and the images on disk. And you don't need to refit them all the time. So we're going to cache assets. So we cache CSS and JavaScript. And we're going to make some changes to how we set up our
JavaScript and CSS endpoints. So we can put a little timestamp in them to indicate to the browser if something has changed. We need two things to work together. We need to provide a cache control header that will specify an age on the asset. We also specify if it's public so that the CDNs we just talked about can cache it. And we will also
specify something like, specify that this is immutable. This file will never change. And this is also why we're going to be adding this timestamp so that if that timestamp is different from what the browser expected, it knows to change it. And having this immutable on will make the caching much more effective. We'll be adding eTags or identity tags. That is a unique fingerprint of the file's content.
so that we can always respond to the browser that this is not the right version. We have a new version, so don't download it. We will send you a new version. I hope this makes sense. If not, we are gonna be implementing a little helper method that we can use on our assets, and you can see it in the browser. I will show you how we can verify with the network tab that our cache is working.
In controller.go, I'm going to go down to the bottom here. I'm going to create a helper function called enable caching. Maybe we should call enable assets caching to be more clear. We're going to take in the echo context and some content. There's a byte slice and we turn on echo context. Let me make some room.
Then we want to say if config.env equals config.production environment, then we're going to implement these headers. We need to say EC. And this is because we don't want our developer environment to cast stuff, so we can't actually see the things change. Right. We're going to generate a hash here.
with md5 and then a sum of the content. Then we'll say e tag is equal to, it's gonna be equal to the hash plus dash and then plus the length of the content. Give that a save. And we need this to be a string and a string.
Okay, we cannot do, we cannot convert. Okay, interesting. Do we have, we do not. All right. Let me try and do it with FMT sprint F instead. So we're gonna say, percentage sign X, percentage sign pro, percentage sign X. Close, and then we say,
hash and provide it with length of content comma. All right, that did the trick. Now you want to say if match and then say C, we crest, no, EC, we crest a header and then get and say if
none match and match if match equals our e-tech then we say easy respawns header set cache control
And we will set it to these brands, F, Public, Max, H, which we will set to a string. And then we want to say emutable, right? Is that in what we want? So then we want to say, let's cast this for like three months. So let's say three months.
in seconds. We're going to create that soon. Yes, let's do that. Right. Then we also say easy response, header, and set the tag, the tag. Finally, see no, easy, no content, HTTP status, not
modified. Right, let me just calculate, let's say three months in seconds. Okay, I have to value somewhere else. Let me just grab it real quick. Let's grab it, grabbing it off screen here, create a const and make this into
this and close and we need to actually create the variable write. So here we simply say if the header we get which matches our e-tag, then we just say use this. This is the same and nothing is modified. If not, then we say easy response header.
And then set, and here we're gonna say all of this that we just provided with a three month cache. And easy response header set. And here we'll say very and accept encoding. Finally, easy response.
header, set, and then we provide the v tag, v tag. Right, this is our enable as it's caching a helper function that we're only running in production right now, but if we let's change this to development, yes, and then let's actually try and
and add this to some of our assets. Where do we have Java script? Let me simply say, EC equals to enable caching pass EC. And we also want to pass the script. This one returns.
our returns on you, echo context, we can technically just do this. All right, and then simply do this one more time, pass EC and style sheet. And let's now go back into our block, open the development tools,
And if I go into network and give it a refresh, let's see what it says. We actually have on disk here. Let me try and clear the cache. So if you see here now that we have no indicator that any caching is happening, it's loading it directly. But if I refresh, you can see now here, make this a little bit bigger. This is now in memory cache and there's zero seconds time to fetch these.
these files right versus exactly what we wanted the first time. It's technically a little bit slower to respond, but then the second time is in the browser's cache and it goes super fast. All of this is cached in memory. So it's working. We just need to only run this in production. Next, I want to add the timestamp to our CSS and also to our JavaScript.
And I want to have a single entry point from all of our JavaScript files. And finally move all of this to the header tag of the base layout so we get them down immediately. So let's begin by defining a start time that is going to be whenever the server puts up. It's going to say start time is equal to time dot now dot unix.
Alright, so we got a UNIX timestamp, it's just a 64 representation. Then let's say FMT Sprint F here, and let's also do it down here, where we in our CSS want to add the timestamp here. So start time, then we want to have
JavaScript and JavaScript files, where this will be a specific JavaScript file called scripts. So this will just be scripts.js. Give that a save. And then we also need to add the timestamp here. Start time, start time.
Why? What am I doing wrong here? What am I doing? Ah, sorry, it's not a string. I need to provide it as a value. And I need to call the function to get the Unix times the version. Right, now if we go in
here, open our network and say clear assets. Let's check the request here. You see now we have this UNIX timestamp here. And if I refresh one more time, it stays the same. So easy and easy. So this is an indication to the browser that whenever this changes, maybe we can actually test it now. Let's go back to our controller and then say again,
that this should be in development environment. Give this a save. Go back to the browser and then let's do a hard refresh. We have, now we have a memory cache, yes. And if you were to go back into, let's say into our views here and update. Let's be, actually just need to trigger the application to do a re
Reload. Let's just say web site. I'm just doing something to trigger the Timbal Reload. And now, let's see what happens. So you can see here that the memory is gone. And that's because now this has changed. And until the browser, like, hey, this is changed. We cannot use this anymore. But the second time, we get the memory cache again. So I hope this is starting to make a little bit more sense. The final thing.
I want to add this in assets. I'm going to create this file here called scripts.js that will quite simply just import the JavaScript assets. So we say import and then we have need to import easy mde.js and we also
No, ECJ is yes. And then we need to import data star dash v1, RC6minmin.js. That should do the trick. Then if we go into our controller, and we find JavaScript.
and what did I call the routes JavaScript files. So we load JavaScript files. We don't need the file name, because this is gonna be scripts.js, a bit of this, and also a bit of this, this,
Back into our router. We register JavaScript files and JavaScript files. Finally, in our base layout, we no longer need this. We no longer need this one. We can just say that we want to use JavaScript.
files, yes, get rid of all of this. And now, can I, let me just clear here, clear here. Do we get the call to scripts? Yes, yes, and then controller, we have
this one right here, which is also what we want. Okay, let me just, oh, we have an error. That's why we're not seeing it. We need to remove strings, and now the binary will probably reload. So let me try one more time here. And now we see we have this script here that simply returns all of these imports, and then we have the imports here being loaded
And again, this gets casted very fast on the second attempt. And this is just easier. So now we load all of the script. And we also load the ones we don't need. We don't need EasyMD here on the home page. You could refactor this and have our admin and our normal one if you wanted to. But this is perfectly fine. And it's super fast for our use case. Right. So we have enabled.
page caching, we have enabled static assets caching and we have made a single endpoint from which we can import our JavaScript files. If you wanted to do something other than tailwind, you can do a similar setup there as well where you would have a main CSS file that didn't just import everything else. So this is our assets caching and we're almost ready, we just need to deal with
I have our login strategy and we are ready to go to production.