Back to Blog
Nov 14th, 2023

Stop Combining CSS & JS! + Performance Revisited

weaverryan avatar

Written by weaverryan

Stop Combining CSS & JS! + Performance Revisited

Read the entire series about LAST Stack:

And look out for an upcoming 30 Days with Last Stack tutorial. Or join me for my UX + AssetMapper SymfonyCon Workshop!

You know the all-important rule of frontend performance. Heck, it's probably the first thing you think about when profiling your site via Lighthouse. Repeat after me: combine your CSS and JS files to minimize the number of HTTP requests.

But wait, plot twist! That's not true anymore. Heck, it's been a myth for a while. Even Lighthouse doesn't seem to care. The one metric that mentions it doesn't affect your score... and the "solutions" relate to avoiding "blocking" resources, not eliminating requests.

Don't Care about Requests

What changed? Simple: HTTP/2 (and HTTP/3). With HTTP/2, browsers can make multiple requests (via a single connection) to the server at the same time. It's that simple. Game over. Oh, and HTTP/2 is supported by all browsers and all web servers. And if you're lazy (like us!), you can also put a service like Cloudflare in front of your site to automatically enable HTTP/2+.

Is there still some theoretical number of requests that's too many? Probably! But it's also probably a lot higher than you think. And that's the point: HTTP/2+ allows us to stop worrying about the number of requests. If you did hit some limit, let a tool like Lighthouse tell you... instead of guessing & worrying about it. For reference, today serves 7 uncombined CSS files and 50+ uncombined JS files on page load! The Lighthouse performance score? 100 ⚡️.

Long-Term Caching ✅

Forgetting about HTTP/2 & requests, there's one thing that hasn't changed: the importance of long-term caching. When a user comes to my site, I want them to download my /assets/alien-attack.js file once and then never again. Heck, I don't even want their browser to take the time to ask if it's changed: just use the cached version.

Doing this is simple and not new. On your web server, set an Expires response header to a super-distant time in the future for every asset (CSS, JS, images, etc.). Then, after your browser requests GET /assets/alien-attack.js, it will cache that file (nearly) forever.

But... what happens when we change the file? To bust the cache, we need to change the URL. That's where asset versioning comes in. Instead of naming the file /assets/alien-attack.js, we call it /assets/alien-attack-10030cb02068eb.js. The 10030cb02068eb is known as a "digest": it's a hash of the file's contents. When we change the file, the digest changes, the URL changes, and the browser downloads the new file.

Since manually renaming the file ourselves would be... insane... this is the main task that we still need some tool to help us with. Webpack did this for us. And so does AssetMapper. In fact, AssetMapper is built for this.

For example, if we have an assets/uploads/blog/alien-attack.png file, we can reference it in a template like this:

<img src="{{ asset('assets/uploads/blog/alien-attack.png') }}" />

<img src="/assets/uploads/blog/alien-attack-10030cb02068eb.png" />

Free versioning! And this works for any file you put in a mapped assets directory.

Oh, and fun-fact: now that we're no longer combining files, if update change just one file, only that file's name will change... and our users will only re-download that one file... instead of a combined file that contains the code from a bunch of files that did not change.

Compression? Minification?

Status check!

  • Number of requests: ✅ don't care
  • Long-term caching: ✅ AssetMapper

But what about compression... or minification? These are still important, right? If we can squeeze a 25KB JavaScript file down to 5KB, shouldn't we do that?

Yup! This is something else that Webpack did for us. But, it's also something that web servers can do! Like long-term caching, you can configure your web server to compress your assets on-the-fly. Or, even easier, put a service like Cloudflare in front of your site, and it will do this for you... even choosing from the best compression algorithm for each browser.


Compression (e.g. via gzip or brotli) is not the same as minification. Minification can reduce your file sizes a bit more. But do you care enough? famously does not minify their assets, relying only on compression... and they're pretty big. Let tools like Lighthouse tell if you really need to minify. And if you do, you can always add a step to your deploy process.

So yes! Compression still matters!, But it doesn't need to be part of your frontend tooling. Solve it once (via web server or CloudFlare), then celebrate that you never need to think about it again. Maybe work on something more important instead.

In the next post, we'll talk about preloading: a fancy way to hint to the browser what files it should download before it even knows it needs them.


Sort By
Login or Register to join the conversation

Hey, CloudFlare deprecated auto minify.

>We recommend that you minify at the origin during the build phase. Minification is included in most modern web development frameworks.

Note that this kinda implies AssetMapper != a modern web development framework.

So now what?

| Reply |

Hey Mathieu,

As it's said in this article, first of all, try to figure out if you really need to minify those assets, e.g. using Lighthouse check. Some famous big websites do not minify their assets relying only on compression, e.g., so are you sure you should care about it to much? Some performance tests and tools probably would help to answer it.

Also, as it's said, along with web servers assets compression on-the-fly and like long-term caching iI bet it will be the almost same size if you would minify.

If you have some strong arguments about minifying assets that could be considered as important - feel free to open an issue. The AssetMapper is a new modern tool (not a modern web development framework thought), so this feature could be added if needed IMO. Moreover, contributions are warmly welcome :)


| Reply |

Hey Victor,

Those are decent points I will throw into consideration with my team - although I have my doubts about how they'll receive it. Partially because many big net entities like CloudFlare still recommend minifying.

We are in the process of switching a big legacy monolith over to Symfony, and there is a lot of legacy JS which is currently minified and I suspect the stakeholders want to keep it that way.

So therefore I am left with two questions:

  • Is the reason AssetMapper doesn't support this a point of principle or as some would state "being opinionated" or just a scope of functionality in this case? It already supports TypeScript compiling, so why not minifying and uglifying? It doesn't seem like an awful lot of work to implement since the relevant scripts already exist in many forms.
  • How could I best go about implementing minifying/uglifying into AssetMapper - if only to keep the stakeholders happy or to save 0.1% on loading times? Writing a custom ExtensionBundle?
| Reply |

Hey Mathieu,

Unfortunately, I don't know the exact reasons behind about why AssetMapper does not have minify feature out of the box. My guess is that it's new tool, and that was not in priority for that bundle to implement it considering the facts I mentioned in my previous message. If there're no blockers for minify feature (which I'm not sure about) - I think it can be easily implemented by request, especially if there will be a volunteer who would love to help to implement it. But to get more feedback, I would recommend you to open a detailed issue on the GitHub repo first to discuss it more.

If you need that minify feature now - there's another tool called Webpack Encore - that's more flexibly and more powerful tool that already comes with minify feature, you can consider using that probably.

That's all I can say about it for now.


| Reply |

Delete comment?

Share this comment

astronaut with balloons in space

"Houston: no signs of life"
Start the conversation!