-
-
Notifications
You must be signed in to change notification settings - Fork 428
Cache busting with url versioning params #179
Comments
+1 for cachebusting utilities in sapper
<link rel='icon' type='image/png' href='/favicon.png?v=%sapper.cachebust%'> When the cachebusting directive is found, it tries to find the filename in question, loads the file, calculates the hash and fills it in. |
Sapper isn't actually serving your favicon; that's (typically) done by serve-static. My understanding was that it won't supply cache headers unless you tell it to, and then it will use ETags to ensure that it doesn't serve stale assets. Maybe favicons are treated slightly differently by browsers? So any cache-busting mechanism would be favicon-specific, rather than based on a hash of the file in question. Maybe a |
Yeah I definitely recall stuff about different browsers caching favicons super aggressively, much more so than other files. Searching for 'favicon caching' yields a lot of results about people trying to purge the favicon cache in various browsers. |
@Rich-Harris I concur around The point is there's no easy mechanism in place to deliberately break cache when one needs to, and the easiest method I have (traditionally) found for doing this is with a simple I'm on the fence about what @thgh is proposing. If it's a super simple equation / hash to keep track of all those changes, fine. But if it's kind of an intense thing to build, I favor getting this done sooner with a simpler single cache update var across the board. |
The <link rel='icon' type='image/png' href='/favicon.png?v=%sapper.cachebust("favicon.png")%'> ...would be slightly better, but it still basically means implementing a templating language rather than doing a nice simple (and fast!) string replace. Even Isn't manually incrementing the cache busting number the right solution here? If you know that you need to forcibly cache-bust a specific asset, you can just append
My understanding is that when you create a new cache in the service worker (which in sapper-template happens on each new build, because of |
I'm not sure I follow, but it may also be that I need to understand exactly what the cache headers do; admittedly I'm not 100% schooled in it all. When I researched it prior for a project that needed tight control of caching, I was on a bit of a deadline that didn't allow a thorough investigation...I may need to brush up... (Starting here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) |
Well...here's an interesting philosophy:
Arguably, Would it be crazy to keep a manual manifest somewhere? That would at least keep things in one place...that admittedly is also a bit cray cray... Maybe we should just document this somewhere and call it good? 🤔 |
Don't take my word as gospel, but I think it goes like this: you open a page that registers a service worker, and the service worker is byte-different from the previously registered one, so the browser installs it. During installation, the service worker deletes the old cache and creates a new one (because it has a different name, It adds all the assets that are specified in the manifest to the new cache. But it doesn't go directly to the server, it goes to the HTTP cache (this part is transparent and out of our control). Say the service worker wants The same logic applies after the cache has been populated, if the I think documentation is the proper response here, but I'm slightly hesitant to let the Sapper docs become a repository for general advice about building web apps — there are lots of places that explain this stuff far more thoroughly (and correctly, probably) than we could attempt. |
I had the same thought about general documentation—send them elsewhere. However, if people (like me) keep bumping into (for example) the favicon not updating, etc., lets at least give them a "what for" (and why we don't self-manage it) and send 'em off to learn about it elsewhere. Since I'm the one spoutin' here, I'm happy to do that PR. ;) |
Hi guys, I'm also running into this. Currently, whenever I change a static file, I tell the users to hard-refresh the page (Shift+F5) to clear caches. It would be cool if sapper could incorporate automatic cache busting for statically linked assets, similar to how nuxt.js does it: https://nuxtjs.org/guide/assets Thoughts? |
Facing the same issue for CSS invalidation on the |
I believe the standard way to do cache busting is to ask the bundler to add a hash to the filename. I raised an issue in the template to add hashes to the static filenames and provided the code to do so there. If I don't hear any objections I'll send it as a PR. |
You could still do a simple string replacement if we are given a place to register which files need to be hashed. <link rel='icon' type='image/png' href='%sapper.cachebust.favicon%'>
<link rel="stylesheet" href="%sapper.cachebust.globalCss%" /> I don't know where that'd be. A new module.exports = {
// paths are from static root
cachebust: {
globalCss: "css/global.css",
favicon: "favicon.png"
}
} |
Or if there was a place to hook into the string replacement in general, at build time, we could add necessary build steps to populate it. (maybe this already exists?) |
As a POC, I added the following to import templateConfig from '../../../sapper.config' // This would have to change, but still...
/// snip
const body = template()
.replace('%sapper.base%', () => `<base href="${req.baseUrl}/">`)
.replace('%sapper.scripts%', () => `<script${nonce_attr}>${script}</script>`)
.replace('%sapper.html%', () => html)
.replace('%sapper.head%', () => head)
.replace('%sapper.styles%', () => styles)
.replace(/%sapper\.cspnonce%/g, () => nonce_value);
res.statusCode = status;
res.end(templateConfigReplace(body)); // <-- that is the new bit: templateConfigReplace
/// snip
function templateConfigReplace(body) {
return templateConfig.replacements.reduce((acc, { find, replace }) => {
return acc.replace(find, replace)
}, body)
} And then created the new file I referenced called import fs from "fs"
import crypto from "crypto"
function hashFile(pathToFile) {
return (
pathToFile + "?v=" + crypto
.createHash("md5")
.update(fs.readFileSync("static/" + pathToFile, "utf-8"))
.digest("hex")
)
}
export default {
replacements: [
{
find: "%sapper.cachebust.indexCss%",
replace: () => hashFile("index.css"),
},
],
} Then in my <link rel="stylesheet" href="%sapper.cachebust.indexCss%" /> It all worked just fine. I know it's been a while since this topic has been discussed, but giving a low-level way to do this might be nice. You could even drop it further and just allow us to provide |
Even more control would be to provide |
So I just ran into the favicon not updating unless I manually break the cache like so:
Without
?v=2
it wasn't picking up my changed icon. I think this is something fundamental enough it ought to be built in to the platform, some sort of cache breaking mechanism. Potentially this sort of thing:Would it be as simple as picking up package.json major version (semver) upgrades
0.x.x
? I suppose it ought to be a manual break, though, because I can imagine people wanting to be able to manage cache busting (images, css, js, etc.). Still, it would be convenient to have a single env var or some file or some mechanism somewhere in one place that we could update easily and have it ripple out through the whole app.Thoughts?
The text was updated successfully, but these errors were encountered: