Optimising CSS, JS and fonts in PrestaShop without breaking your store
Every module loads its CSS and JS on every page, even when they are not used. We go over what to do with them, how to serve Google Fonts locally and how to measure so you do not break the checkout to gain a few milliseconds.
Open a product page on a PrestaShop store with forty modules and count the CSS and JS files it loads. It can easily go over fifty. Among them are the contact form CSS, the JS of a reviews module that only appears on another page and a typeface with six weights, of which the theme uses two.
None of those files breaks anything on its own. Together, they make the browser download, parse and execute far more than it needs before rendering the page. This weighs on LCP and INP, the Core Web Vitals metrics that stores struggle with most.
Where all these files come from
In PrestaShop, each module registers its assets in the front-office hook. Most do so on every page, for convenience: the developer does not know where you will place their block, so they always load it. Add the theme, its parent theme if it is a child theme, the libraries each one brings and third-party scripts (analytics, chat, pixels, external reviews).
That is why optimising is not just «compressing». There are four different levers, and it is best not to mix them up.
1. Combine and minify
PrestaShop comes with smart cache for CSS and JavaScript as standard, in Advanced Parameters > Performance: it merges the files into one or a few and minifies them. It is the first thing to enable, and it almost always works.
- Advantage: fewer requests and fewer bytes.
- Limit: it still loads everything on every page, just bundled together. If 40% of the CSS is not used on the product page, it is still unused, now inside a bigger file.
- Risk: badly written JS that relied on load order or on a global variable can fail once combined. You notice because a button stops responding; the error shows up in the browser console.
After enabling it, clear the cache and test the whole journey: listing, product page, cart, checkout and payment.
2. Remove what each page does not need
This is what makes the biggest difference and what is done least. If the forms module CSS is only used on the contact page, there is no point loading it on the product page. To decide, you need an inventory: which asset each page type loads, how much it weighs and which module it comes from.
With that inventory in front of you, the rules are simple: «this CSS, off the product page», «this JS, only in checkout». The risk is removing something that was in fact used somewhere you had not checked. That is why each rule is tested on the affected pages before you leave it in place.
3. Defer, async and delay until interaction
A normal script in the <head> stops the page from being parsed until it has been downloaded and executed. There are three ways to avoid this:
| Technique | What it does | Used for |
|---|---|---|
defer | Downloads in parallel and runs once the HTML is finished, in order | Most of your own scripts |
async | Downloads in parallel and runs as soon as it arrives, in no particular order | Standalone scripts that depend on nothing |
| Delay until interaction | Does not run until the visitor moves the mouse, taps or scrolls | Third parties: chats, widgets, heatmaps |
Delaying until interaction is very effective with third-party scripts, which are usually the heaviest. But it has two pitfalls:
- Analytics and consent. If you delay the analytics tag, visits that bounce without touching anything are not measured. That may or may not be acceptable, depending on what you need. And the consent script is never delayed: it has to come before everything else.
- Dependencies. If a delayed script defines something that another script uses on load, the second one fails. Delayed scripts must run in document order and with a maximum wait time, so they do not hang forever.
4. Google Fonts from your own server
Many themes load fonts from Google's servers. This has two costs:
- Performance: connections to another domain, and often more weights and character sets than you use.
- Data protection: the visitor's browser sends their IP address to Google when requesting the font, before they have accepted anything. A German court has already ruled against a website over this, and it is a frequent complaint.
The solution is to download the woff2 files and serve them from your domain, keeping only the weights and subsets you use (for Spanish, usually latin and latin-ext). Also:
- Preload only the font of the text that appears first, not all of them.
- Use
font-display: swapso text shows in the system font while yours loads. - Check that no reference to Google remains in the parent theme, in modules or in the CSS they generate.
How to measure without fooling yourself
- Measure first. PageSpeed Insights gives you field data (real users, if your store has enough traffic) and lab data.
- Change one thing at a time.
- Compare the same page with and without the change, on mobile.
- Go through checkout and place a test order.
- Look at the browser console: a new error is a broken feature you have not found yet.
The version matters
Stores on PrestaShop 1.6 or early 1.7 versions carry themes with old jQuery and libraries that cannot be deferred without breaking something. In PrestaShop 8 and 9, with current PHP and themes such as Hummingbird, the starting point is cleaner and every optimisation pays off more. If your store is far behind, updating is part of the optimisation, not a separate step.
How to solve it in PrestaShop
RKR OptiMatters builds an inventory of the CSS and JS that each page type loads, with their weight and source module, and lets you create rules to remove them, apply defer or async, delay them until the first interaction, load them after page load or force them to load, restricted by page, controller, category, device or URL. It downloads the Google Fonts your store uses and serves them from your server, with only the weights and subsets needed, and includes a test mode to compare any page with and without the optimiser. On the server side, All In One Cache adds full-page caching, query caching in Redis (PrestaShop 8 or later) and OPcache management, with optional minification of HTML and inline CSS and JS.