Composable-Frontends Performance
Shopware Backend caching
The current versions of Shopware rely heavily on POST
requests for /store-api/
.POST
requests are by design not cacheable, so Fastly simply passes them to the backend cluster without even trying to cache them.
A temporary plugin has been developed. With this workaround, Fastly can cache some of the /store-api/
POST
requests.
This plugin includes new Fastly snippets that must be used instead of the usual ones.
The plugin includes a few routes which will become automatically cacheable.
If you need to cache additional routes, it can be done via the admin config: SwagStoreAPICache.config.additionalCacheableRoutes
.
As usual, ensure soft-purges are enabled.
Please note that we're actively working on moving the store-api
requests from POST
to GET
to make them cacheable, so the use of this plugin would no longer be required.
More details in the Epic.
Composable Frontend caching
To get the best performance, Frontend caching must be enabled.
There are a few steps to get there:
Configure a Fastly service on top of each Frontend. It can be one Fastly service per Frontend, or it can be a single Fastly service with multiple domains and hosts configured.
Update
nuxt.config.ts
soroutesRules
, using Incremental Static Regeneration (ISR
), have the required cache headers. Example:
'/': {
isr: 60 * 60 * 24,
headers: {
'cache-control': 'public, s-maxage=3600, stale-while-revalidate=1800'
}
},
'/**': {
isr: 60 * 60 * 24,
headers: {
'cache-control': 'public, s-maxage=3600, stale-while-revalidate=1800'
}
},
s-maxage
and stale-while-revalidate
can be adjusted.s-maxage
represents how long in seconds the content will be cached on Fastly.stale-while-revalidate
represents how long a stale page (aka an expired page) can be kept and served, so when a client requests this page, the stale object is served while a request to update it is done in the background, so the next client will have an updated version of the page.
::: Note
The cache invalidation process is only on the Fastly Backend service. The Shopware instance is not "aware" of the Frontend instance. It cannot trigger cache invalidation. Items will remain in cache for the s-maxage
duration.
:::
Get rid of the OPTIONS requests (CORS)
When using a different domain for backend requests, browsers are forced to send OPTIONS
requests. Those requests, also named preflight
requests, are due to CORS
checks. Every time the browser needs to send a request to the backend, it must first confirm it's authorized to do so.
OPTIONS
requests are by default not cacheable as the responses may vary depending on the request's headers. There is a possibility to include an Access-Control-Max-Age
header in the OPTIONS
responses, so it forces the browser to cache the answer for a longer period than the default 5 seconds.
But the recommended action is to remove those CORS
checks completely. To do so, all the requests to the Shopware backend must be sent on the same domain as the Frontend, so the browser only sees one single domain.
For this, the Frontend Fastly service can be configured to serve both the Frontend and the Backend requests.
The config is pretty simple. With the additional host, the logic is only four lines of code:
if (req.url.path ~ "^/store-api/") {
set req.http.host = "backend.mydomain.com";
set req.backend = F_Backend__Shopware_instance_;
return (pass);
}
The return (pass)
is very important. We must not add a cache layer on the Frontend Fastly service to avoid invalidation issues. The Backend Fastly service remains the one responsible for caching.
Optimize the Fastly Backend hit-ratio
Once an item has been set into the cart, a new cookie named sw-cache-hash
is sent. The default VCL hash snippet includes the content of this cookie in the hash (aka the cache key). It means that the first backend request that was cached will no longer be cached when requested once an item has been added to the cart.
If rules based pricing is not used in the Shopware instance, the following section can be commented out in the VCL hash snippet:
# Consider Shopware http cache cookies
#if (req.http.cookie:sw-cache-hash) {
# set req.hash += req.http.cookie:sw-cache-hash;
#} elseif (req.http.cookie:sw-currency) {
# set req.hash += req.http.cookie:sw-currency;
#}
Check the results using the Developer Tools
Once everything is configured, check for the Age
header to confirm the responses are cached.