Caching frontend web application
Web applications (or websites) are often these days rendered right on the user's computer. The server just provides the application and some API. Some of the most popular frameworks which make this possible are React, Angular and Vue.js. Being able to cache this application is pretty important. Fully downloading the application every time the user makes a visit would be wasteful.
On the other hand, an application can be updated on the server, yet still be outdated on the client, because a caching policy has a long timeout interval. There are different solutions how to choose an optimal caching strategy, but the one which worked really well for us is the solution based on changing resource names.
The idea is to set the cache interval to the longest on all files except the index.html, which is downloaded every time. During the build process, all changed files will have a different name, so the browser will download them. Of course, we don’t want to do it all manually.
To bundle all frontend files together, we use Webpack. The tool unsurprisingly have our needs covered. We just need to change the name of the output file from app.js to app.[contenthash].js. The [contenthash] is the substitution parameter, which will be replaced by a hash calculated from the file content. Should the content change, the name of the file will change too.
Webpack has multiple different substitution parameters relevant to our case:
- [fullhash] - hash of whole compilation - different build will have different hash (same on all files)
- [chunkhash] - hash of chunk calculated from all chunk files
- [contenthash] - hash of specific file calculated from the content of this file
There is still a problem that index.html references app.js, which is no longer the correct name, as the name will change. To solve this, we can use the HTML Webpack Plugin to generate index.html. It will automatically include our app.js to the output index.html. Because we already have index.html pretty customized, we need to user parameter template during the plugin configuration to use the file as a template. Don’t forget to remove hardcoded app.js reference from a template. We no longer need it, the plugin will automatically include it.
This is how the configuration can look like. Nothing complicated.
During the build, Webpack will generate app.js file with some hash, the plugin will take the template index.html and include the script with the correct name. This works well when the frontend is built, but I wasn’t able to make the plugin work with DevServer. Webpack as a server is serving files from memory so I’m not even sure if HTMLWebpackPlugin should even work.
At the end of the day, caching doesn’t really matter during the development, so this configuration is used only in the production configuration script. A little inconvenience is two index files we need - one with and one without hardcoded app.js reference.
Author: Luděk Novotný