Self-heal a stale cached bundle via a build version
Phones kept running old JS because their cached index.html pointed at an old hashed asset. Both images now bake the commit SHA as BUILD_VERSION; the backend exposes it at GET /api/version and the client reloads once with a cache-busting query when its own baked version differs. Guarded by sessionStorage so it cannot loop. /api/version is unauthenticated like /api/health.
This commit is contained in:
1 parent
7ad14449ce
commit
7b97f010c9
11 files changed
+80
-4
No files matched your search
@@ -1,5 +1,9 @@
|
||||
FROM node:22-alpine AS build
|
||||
|
||||
# Same value as the backend's BUILD_VERSION so the client can compare them.
|
||||
ARG BUILD_VERSION=unknown
|
||||
ENV VITE_BUILD_VERSION=${BUILD_VERSION}
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --no-audit --no-fund
|
||||
|
||||
@@ -133,7 +133,27 @@ function handleMessage(message) {
|
||||
}
|
||||
}
|
||||
|
||||
// If the server is running a newer build than this (possibly cached) bundle,
|
||||
// reload once with a cache-busting query so phones pick up deploys without a
|
||||
// manual hard-refresh. Guarded so it can never loop.
|
||||
async function ensureFreshBuild() {
|
||||
try {
|
||||
const { version } = await api.getVersion()
|
||||
if (!version || version === 'unknown') return
|
||||
if (version === __BUILD_VERSION__) return
|
||||
const key = `reloaded:${version}`
|
||||
if (sessionStorage.getItem(key)) return
|
||||
sessionStorage.setItem(key, '1')
|
||||
const url = new URL(window.location.href)
|
||||
url.searchParams.set('v', version)
|
||||
window.location.replace(url.toString())
|
||||
} catch {
|
||||
// ignore; not worth blocking the app
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
ensureFreshBuild()
|
||||
await Promise.all([
|
||||
loadStrategies(),
|
||||
loadPresets(),
|
||||
|
||||
@@ -2,6 +2,7 @@ import axios from 'axios'
|
||||
|
||||
const http = axios.create({ baseURL: '/api', timeout: 10000 })
|
||||
|
||||
export const getVersion = () => http.get('/version').then((r) => r.data)
|
||||
export const getStatus = () => http.get('/status').then((r) => r.data)
|
||||
export const getStrategies = () => http.get('/strategies').then((r) => r.data)
|
||||
export const getPositions = () => http.get('/positions').then((r) => r.data)
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { execSync } from 'node:child_process'
|
||||
|
||||
// Short git SHA (or a timestamp fallback) baked into the bundle so the client
|
||||
// can detect when the server is running a newer build and reload itself.
|
||||
let buildVersion = process.env.VITE_BUILD_VERSION || String(Date.now())
|
||||
if (!process.env.VITE_BUILD_VERSION) {
|
||||
try {
|
||||
buildVersion = execSync('git rev-parse --short HEAD').toString().trim()
|
||||
} catch {
|
||||
// not a git checkout; keep the timestamp
|
||||
}
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__BUILD_VERSION__: JSON.stringify(buildVersion),
|
||||
},
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 5173,
|
||||
|
||||
Reference in new issue
Block a user