Firebase Hosting Deployment Solution
If you deploy code on any system and need a co-worker or client to see the most recent version of your app, you will run into the need to tell them how to clear their cache.
Asking a user to clear their cache is not a great user experience.
I am working on a startup, and currently have dev, demo and production versions (and domains) running on firebase. I deploy to these via codeship.io and git branches. I am finding I have to tell both my co-founder and beta users, ‘please clear your cache’. This is a terrible user experience, so I have worked out a setup of configurations for apps on firebase that take this issue way.
So to be clear, the goal is to be able to deploy code to firebase, and have users see the most recent version within a few minutes (or seconds), with no need to clear browser caches. Just a simple browser refresh. This is not tricky setup and uses old school web techniques. Once I started using this, I have found that all my projects and apps needed it. While this can be used for any framework, (Drupal, Heroku + ExpressJs, etc) I am outlining the setup for firebase hosting, because it so damn easy.
- Setup Index.html in Firebase.json hosting to `max-age=0, no-cache`
Adding this code to the hosting headers for the index page will ensure that browsers will never cache the index.html page. This does mean that every time the user visits the app, it will need to download the index.html. But since the Index.html is tiny in most single page applications, this is not terrible.
2. Setup the Js, Css files with a max-age=3600
Note: I set the max-ages to 3300 and 3500 seconds, to ensure that when I check the file cache settings in a browser’s console I can be certain that the settings is working. Firebase defaults max-age to 3600 seconds.
3. Add in Cache Buster Variable in the Index.html.
This step means that on deployment you need to write a version or commit sha id to your index.html file. I do this via a gulp task that uses the current git brand and commit, as well as the package.json version number.
This gulp task runs on deployment and generates an index file with the following added to the
css references. The gulp command passes version data into a template file to create a production index.html file. The deployment ready index.html gets written to the dist/index.html. This works both for local development, and from a codeship.io deployment process.
- Using cache busting variables in the html resources is not new. Its been used since the early days of the interwebs.
- Having a ‘max-age=0’ in your cache might cause your Ops guys unhappy. And might not be great for a production app. If you set the max-age to a larger time value, it just means that the app will take longer to refresh.
- Firebase might not honor the cache for html5Mode apps for some urls, so there might need a need to add in more header setups to handle wildcard paths. Still testing this.
So how does this all work? When the code is deployed to firebase hosting, the firebase.json settings are used to set the header cache settings for each file type. The index.html cache is set to never (i.e. max-age=0, no-cache). The js and css files are set to specific values.
When a user visits the app, their browser is forced to download a new version. In the index.html the cache busting variables tell the users browser to cache its resources. When a new version/commit is deployed, the users browser will either have a cached version of the resources, or will not, and will get a new version.
Note: For now I have put the version number in the index.html title, so that my users knows what version they are on. I will take this out once we are out of beta. For now, having the version update within seconds of deployment removes the need to tell new users; ‘clear your cache’.