3 ms·
Fingerprinting with content-based hashing in the filename works, but it’s not ideal. You’ve got to make it work for basically every static asset regardless of h
by JimDabell 3y ago
Fingerprinting with content-based hashing in the filename works, but it’s not ideal. You’ve got to make it work for basically every static asset regardless of how it is generated.
Generally speaking, I’ve found it’s better to remove this from the build logic and treat it as an infra / deployment issue. Dump all of your static assets into your object store using the Git hash of the current version as a prefix. So if you are deploying foo.js, then you might serve it as https://static.example.com/<git https://static.example.com/<git hash>/foo.js.
This means that you can set all of your assets as permanently cacheable and still have your cache invalidated for everything every time you deploy something new. And it doesn’t matter what you use to build your assets; your build pipeline doesn’t need to know anything about this, it can just generate assets normally.
- jstummbillig 3y agoSounds interesting. How do you handle that? How do you select the correct/latest ref of each asset to send to the user? It feels like you would have to do the same amount of work that you would have to do with fingerprinting.
- JimDabell 3y agoWith fingerprinting, each asset has a URL you need to ultimately get from your bundler individually. With a URL prefix, your assets retain their original filenames. In some contexts you’ll need to know the prefix, but it’s the same for every asset. And in other contexts you can just use relative URLs and not think about it at all.
- jstummbillig 3y agoYou would need the correct git hash, no? Instead of /rndotherhash_filename.ext you are looking for /rndgithash/filename.ext I fail to understand how resolving that is simpler.
- JimDabell 3y agoSupport you have the following assets: - /js/foo.js - /css/bar.css - /img/baz.png With a content-based hash, end up with something like the following: - /js/foo.abc123.js - /css/bar.def456.css - /img/baz.ghi789.png This means that for each and every asset you have, you need to keep track of their unique filename for that deployment and you need to be able to access that whenever you want to refer to the asset. In practice that means most people rely on their bundler to rewrite every place they refer to those assets, which can make it awkward if they need to refer to them from non-JavaScript contexts. Also in practice, people often seem to ignore anything other than JavaScript or CSS, meaning you get stale assets if they aren’t JavaScript or CSS. With a Git hash prefix, you would have something like: - /abcdef/js/foo.js - /abcdef/css/bar.css - /abcdef/img/baz.png This means you only have one single reference to manage, which you can keep track of without relying on your JavaScript bundler. It also means that in a lot of contexts you don’t need the reference at all, for instance in your stylesheets you can just refer to url(../img/baz.png) and there’s no rewriting necessary to get the right behaviour. Your build process and your infrastructure caching are two separate concerns; it’s easier if they aren’t tightly coupled.
- idbehold 3y agoIt might be easier, but it's strictly worse caching since all static assets get invalidated every deployment instead of just the assets which changed.
- jstummbillig 3y agoThat would be my objection as well.
- comradesmith 3y agoThat means that after a deployment all my users will find themselves refetching everything on the next page load regardless of if it has changed.
- deleted 3y ago[deleted]
- supriyo-biswas 3y agoIf you’re using Webpack you can emit chunks by their content hash, which means the file names don’t change even when your commit changes. This way, a new deployment of your application doesn’t cause new assets to be served to users, and maintains the speed of your website.
- JimDabell 3y ago> If you’re using Webpack you can emit chunks by their content hash You’re talking about this in terms of chunks of JavaScript, but static asset caching is something you should be doing for all static assets, not just JavaScript. Whenever I’ve seen somebody use Webpack content hashing for this, they’ve done it for JavaScript and CSS and forgot about basically every other type of file. And also, now you are tied to only referencing those assets via JavaScript because you have to get the URLs from Webpack, whereas with a URL prefix you can just use relative URLs which work in other contexts as well.
- supriyo-biswas 3y agoYeah, for this I like to append the deployment time to the asset paths from within my application; however in the case of static websites it can be a problem.
- jdsleppy 3y agoYou aren't tied to only referencing things from JS: you can have Webpack emit a manifest file with a JSON object mapping from the original filename to the hashed one. Then oldschool web app code can reference these fingerprinted files using the manifest. To fingerprint files you normally wouldn't import in JS, you can 1) import them in JS anyway just for the bundling side effect or 2) use a Webpack copy plugin to copy all font files, for example, to the build directory and fingerprint them.
- andix 3y agoFor static assets also query keys can be used (/image.webp?hash=abcd). Most web servers just ignore everything after the question mark for static files and browsers use the full URL as cache key.