|
| 1 | +# Automatic Cache Clearing for Firebase Deployments |
| 2 | + |
| 3 | +This document explains the multi-layered cache busting strategy implemented to automatically clear browser caches when deploying to Firebase. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +When deploying updates to Firebase Hosting, browsers may serve cached versions of your app, preventing users from seeing the latest changes. This solution implements multiple strategies to ensure users always get the latest version. |
| 8 | + |
| 9 | +## Implementation Components |
| 10 | + |
| 11 | +### 1. HTTP Cache Headers (firebase.json) |
| 12 | + |
| 13 | +**Purpose**: Prevents browsers from caching HTML files |
| 14 | + |
| 15 | +**What was changed**: |
| 16 | + |
| 17 | +- Added cache-control headers for HTML files to prevent caching |
| 18 | +- Kept asset caching (CSS, JS, images) for performance |
| 19 | + |
| 20 | +```json |
| 21 | +{ |
| 22 | + "source": "**/*.@(html)", |
| 23 | + "headers": [ |
| 24 | + { |
| 25 | + "key": "Cache-Control", |
| 26 | + "value": "no-cache, no-store, must-revalidate" |
| 27 | + }, |
| 28 | + { |
| 29 | + "key": "Pragma", |
| 30 | + "value": "no-cache" |
| 31 | + }, |
| 32 | + { |
| 33 | + "key": "Expires", |
| 34 | + "value": "0" |
| 35 | + } |
| 36 | + ] |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +### 2. HTML Meta Tags |
| 41 | + |
| 42 | +**Purpose**: Additional layer of cache prevention at the HTML level |
| 43 | + |
| 44 | +**What was changed**: |
| 45 | + |
| 46 | +- Added meta tags to both `src/frontend/index.html` and `src/admin/index.html` |
| 47 | + |
| 48 | +```html |
| 49 | +<meta |
| 50 | + http-equiv="Cache-Control" |
| 51 | + content="no-cache, no-store, must-revalidate" |
| 52 | +/> |
| 53 | +<meta http-equiv="Pragma" content="no-cache" /> |
| 54 | +<meta http-equiv="Expires" content="0" /> |
| 55 | +``` |
| 56 | + |
| 57 | +### 3. Version Checker Utility |
| 58 | + |
| 59 | +**Purpose**: Automatically detects new deployments and prompts users to reload |
| 60 | + |
| 61 | +**Files created**: |
| 62 | + |
| 63 | +- `src/frontend/src/utils/versionChecker.ts` |
| 64 | +- `src/admin/src/utils/versionChecker.ts` |
| 65 | + |
| 66 | +**How it works**: |
| 67 | + |
| 68 | +1. Checks for a `version.json` file every 5 minutes |
| 69 | +2. Compares the current version with the deployed version |
| 70 | +3. Shows a user-friendly notification when a new version is detected |
| 71 | +4. Clears all caches (Cache API, Service Workers, localStorage) before reload |
| 72 | + |
| 73 | +**Features**: |
| 74 | + |
| 75 | +- Non-intrusive notification with "Reload Now" and "Later" options |
| 76 | +- Automatic cleanup of all browser caches |
| 77 | +- Configurable check interval |
| 78 | + |
| 79 | +### 4. Build-Time Version Generation |
| 80 | + |
| 81 | +**Purpose**: Creates a version file during build that changes with each deployment |
| 82 | + |
| 83 | +**Files created**: |
| 84 | + |
| 85 | +- `src/frontend/scripts/generate-version.js` |
| 86 | +- `src/admin/scripts/generate-version.js` |
| 87 | + |
| 88 | +**What it does**: |
| 89 | + |
| 90 | +- Generates a `version.json` file in the dist folder |
| 91 | +- Contains build timestamp and version number |
| 92 | +- Runs automatically during the build process |
| 93 | + |
| 94 | +**Example version.json**: |
| 95 | + |
| 96 | +```json |
| 97 | +{ |
| 98 | + "version": "1.0.0", |
| 99 | + "buildTime": "2025-11-09T10:30:00.000Z", |
| 100 | + "buildTimestamp": 1699527000000 |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +### 5. Build Script Updates |
| 105 | + |
| 106 | +**Purpose**: Automatically generates version file during build |
| 107 | + |
| 108 | +**Modified files**: |
| 109 | + |
| 110 | +- `src/frontend/package.json` |
| 111 | +- `src/admin/package.json` |
| 112 | + |
| 113 | +**Changes**: |
| 114 | + |
| 115 | +```json |
| 116 | +"build": "tsc && vite build && node ./scripts/generate-version.js" |
| 117 | +``` |
| 118 | + |
| 119 | +## How It Works Together |
| 120 | + |
| 121 | +1. **During Development**: Normal caching behavior for fast development |
| 122 | +2. **During Build**: Version file is generated with current timestamp |
| 123 | +3. **After Deployment**: |
| 124 | + - HTML files are never cached (HTTP headers + meta tags) |
| 125 | + - Assets (JS, CSS) are cached with hashed filenames for performance |
| 126 | + - Version checker periodically checks for new deployments |
| 127 | +4. **When Update Detected**: |
| 128 | + - User sees a friendly notification |
| 129 | + - Can reload immediately or later |
| 130 | + - All caches are cleared before reload |
| 131 | + |
| 132 | +## Deployment Workflow |
| 133 | + |
| 134 | +No changes needed! The cache clearing happens automatically: |
| 135 | + |
| 136 | +```bash |
| 137 | +# Build your apps |
| 138 | +cd src/frontend && npm run build |
| 139 | +cd ../admin && npm run build |
| 140 | + |
| 141 | +# Deploy to Firebase (from project root) |
| 142 | +firebase deploy --only hosting |
| 143 | +``` |
| 144 | + |
| 145 | +## Configuration |
| 146 | + |
| 147 | +### Change Check Interval |
| 148 | + |
| 149 | +Edit `versionChecker.ts` to change how often it checks for updates: |
| 150 | + |
| 151 | +```typescript |
| 152 | +const VERSION_CHECK_INTERVAL = 5 * 60 * 1000; // 5 minutes (default) |
| 153 | +// Change to: 10 * 60 * 1000 for 10 minutes |
| 154 | +``` |
| 155 | + |
| 156 | +### Customize Notification |
| 157 | + |
| 158 | +The notification styling can be customized in the `showUpdateNotification()` function in `versionChecker.ts`. |
| 159 | + |
| 160 | +### Disable Version Checking |
| 161 | + |
| 162 | +If needed, you can disable version checking by commenting out the initialization in `main.tsx`: |
| 163 | + |
| 164 | +```typescript |
| 165 | +// initVersionChecker(); // Commented out to disable |
| 166 | +``` |
| 167 | + |
| 168 | +## Testing |
| 169 | + |
| 170 | +### Test Locally |
| 171 | + |
| 172 | +1. Build and deploy your app |
| 173 | +2. Open the app in your browser |
| 174 | +3. Open DevTools Console - you should see: `📦 App version: [timestamp]` |
| 175 | +4. Make a change and rebuild |
| 176 | +5. Deploy again |
| 177 | +6. Wait 5 minutes (or force refresh the page multiple times) |
| 178 | +7. The update notification should appear |
| 179 | + |
| 180 | +### Force Check Manually |
| 181 | + |
| 182 | +You can force a version check from the browser console: |
| 183 | + |
| 184 | +```javascript |
| 185 | +import { checkForUpdates } from "./utils/versionChecker"; |
| 186 | +const hasUpdate = await checkForUpdates(); |
| 187 | +console.log("Has update:", hasUpdate); |
| 188 | +``` |
| 189 | + |
| 190 | +## Browser Support |
| 191 | + |
| 192 | +- ✅ Chrome/Edge (full support) |
| 193 | +- ✅ Firefox (full support) |
| 194 | +- ✅ Safari (full support) |
| 195 | +- ✅ Mobile browsers (full support) |
| 196 | + |
| 197 | +## Benefits |
| 198 | + |
| 199 | +1. **Automatic**: No manual cache clearing needed |
| 200 | +2. **User-Friendly**: Clear notification when updates are available |
| 201 | +3. **Performance**: Assets are still cached for fast loading |
| 202 | +4. **Reliable**: Multiple layers ensure cache is always cleared |
| 203 | +5. **Transparent**: Users are informed about updates |
| 204 | + |
| 205 | +## Troubleshooting |
| 206 | + |
| 207 | +### Version checker not working |
| 208 | + |
| 209 | +1. Check if `version.json` exists in the deployed app: `https://your-app.web.app/version.json` |
| 210 | +2. Check browser console for errors |
| 211 | +3. Verify the build script ran successfully |
| 212 | + |
| 213 | +### Users still seeing old version |
| 214 | + |
| 215 | +1. Verify cache headers are applied (check Network tab in DevTools) |
| 216 | +2. Try a hard refresh (Ctrl+Shift+R or Cmd+Shift+R) |
| 217 | +3. Clear browser cache manually once |
| 218 | +4. Check if service workers are properly unregistered |
| 219 | + |
| 220 | +### Notification not appearing |
| 221 | + |
| 222 | +1. Check browser console for JavaScript errors |
| 223 | +2. Verify `initVersionChecker()` is called in `main.tsx` |
| 224 | +3. Wait at least 5 minutes for the first check to run |
| 225 | + |
| 226 | +## Additional Notes |
| 227 | + |
| 228 | +- The version.json file is small (~100 bytes) and has minimal impact on performance |
| 229 | +- The periodic check happens in the background and doesn't affect UI performance |
| 230 | +- Service workers from OneSignal are not affected by this implementation |
| 231 | +- The solution works with HashRouter and BrowserRouter |
| 232 | + |
| 233 | +## Future Enhancements |
| 234 | + |
| 235 | +Possible improvements for the future: |
| 236 | + |
| 237 | +1. Add analytics to track how many users reload after updates |
| 238 | +2. Implement a "What's New" modal after reload |
| 239 | +3. Add version comparison to show changelog |
| 240 | +4. Store update notification preference in localStorage |
| 241 | +5. Add a manual "Check for Updates" button in settings |
0 commit comments