'Firebase hosting: How to prevent caching for the index.html of an SPA
I'm hosting an SPA on firebase where almost all paths get rewritten to index.html
. I'm using webpack hash based cache busting, so I want to always prevent caching of my index.html
but not any other files. I'm finding it surprisingly difficult to do so. Specifically, my file layout looks like this
/
├── index.html
├── login.html
├── js
│ ├── login.ba22ef2579d744b26c65.bundle.js
│ └── main.6d0ef60e45ae7a11063c.bundle.js
└── public
└── favicon-16x16.ico
I started naively with "sources": "index.html"
before reading this quote from the docs.
Each definition must have a source key that is matched against the original request path regardless of any rewrite rules using glob notation.
Ok, so instead of a simple glob that specifies the files I want these headers on, I guess I need one on paths. Since most paths redirect to index.html, I need a glob that excludes all the paths I do not want to put these headers on.
For reference, my firebase.json
hosting section looks like this:
{
"hosting": {
"public": "dist",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"cleanUrls": true,
"trailingSlash": false,
"headers": [
{
"source": <<<WHAT-GOES-HERE?>>>,
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
},
{
"key": "Pragma",
"value": "no-cache"
},
{
"key": "Expires",
"value": "0"
}
]
}
]
}
}
So, to give some examples that redirect to index.html and should not be cached
mysite.com
mysite.com/
mysite.com/foo/bar/baz
mysite.com/index.html
Note: I could live if that last one got cached since it doesn't get used in practice.
And the things that do not redirect to index.html and should not be cached
**/*.* (ideally excluding index.html)
mysite.com/login
The closest I've gotten on my own is **/!(login|*.*)
which works for almost everything listed above, but inexplicably does not work on mysite.com
or mysite.com/
. Those 2 pages are not getting matched by this glob and I cannot figure out why.
Solution 1:[1]
Here is the config that I'm using. The logic is to use cache for all static files like images, css, js
etc.. For all others, i.e "source": "/**"
set cache as no-cache. So for all other files, that maybe example.com, example.com/index.html, example.com/about-us, example.com/about-us.html cache will not be applied.
{
"hosting": {
"public": "dist",
"headers": [
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
},
{
"source":
"**/*.@(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=604800"
}
]
}
],
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
}
}
Solution 2:[2]
Be wary with the configuration, if your app also includes a service worker (we had a P1 issue escalated within the firebase org, and this is what we found). You need to ensure that the service worker is NOT cached, and firebase hosting works using a "last rules wins", so you need to ensure your service worker rule is last. Prefer something like this:
{
"hosting": {
"public": "dist",
"headers": [
{
"source":
"**/*.@(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=604800"
}
]
},
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
},
{
"source": "/service-worker.js",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
}
],
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
}
}
Especially because your service worker might do pre-caching, so even though your index.html will not be cached at the CDN level, and HTTP request would get a new copy, with the pre-caching of the service worker, you might still serve an old copy of the index.html
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | jules testard |