@particle-academy/fancy-app-update
v0.1.1
Published
Framework-agnostic 'a new version is available — refresh' detector for any React app. Detect a redeploy (changed build) while the page is open and prompt a refresh. No Inertia, no PHP, no backend required — bring your own API, a version string, or just po
Maintainers
Readme
@particle-academy/fancy-app-update
"A new version is available — refresh" for any React app.
When you redeploy, users with the page already open keep running the old JS/CSS bundle until they refresh — missing fixes and risking subtle mismatches against your new backend. This detects a new build while the page is open and prompts a refresh.
Framework-agnostic — no Inertia, no PHP, no specific backend. Bring your own API, a build-version string, or just let it poll the page's ETag. ~2 kB, React peer only.
Install
npm install @particle-academy/fancy-app-updateDrop-in component
import { AppUpdateAlert } from "@particle-academy/fancy-app-update";
// Mount once near your app root — renders nothing until an update is detected.
<AppUpdateAlert />By default it's a small, self-contained, dismissible card with a Refresh button (bottom-right). No CSS framework required.
Pick a detection strategy
Three ways, in priority order — choose whichever fits your stack:
1. Your own API (check) — most flexible:
<AppUpdateAlert check={async () => (await fetch("/api/version").then(r => r.json())).stale} />2. Version compare — your running build id vs the deployed one:
<AppUpdateAlert
currentVersion={import.meta.env.VITE_BUILD_ID}
latestVersion={() => fetch("/build-id.txt").then(r => r.text())}
/>3. ETag (default, zero-config) — polls the page URL and compares its
ETag / Last-Modified to the value seen on load. Works for any statically
served SPA with no backend code at all (your host changes index.html's
validators on every deploy):
<AppUpdateAlert /> // polls location.href
<AppUpdateAlert pingUrl="/" /> // or a specific URLCustomize the prompt
<AppUpdateAlert
title="We just shipped an update"
description="Refresh to get the latest."
refreshLabel="Reload"
dismissLabel="Not now"
position="bottom" // bottom-right | bottom-left | top-right | top-left | bottom | top
accent="#2563eb"
interval={30_000} // poll cadence (ms); default 60_000
onRefresh={() => myStore.flush().then(() => location.reload())} // custom action
/>Replace the whole UI with a render-prop — your own banner, modal, toast:
<AppUpdateAlert
render={({ refresh, dismiss }) => (
<MyBanner onRefresh={refresh} onDismiss={dismiss}>A new version is available.</MyBanner>
)}
/>Headless hook
import { useAppUpdate } from "@particle-academy/fancy-app-update";
function VersionBar() {
const { updateAvailable, refresh, dismiss } = useAppUpdate({ interval: 30_000 });
if (!updateAvailable) return null;
return (
<div>
A new version is available.
<button onClick={refresh}>Refresh</button>
<button onClick={dismiss}>Dismiss</button>
</div>
);
}| Option | Default | Notes |
|---|---|---|
| enabled | true | Turn detection on/off |
| interval | 60_000 | Poll cadence (ms) |
| pollOnFocus | true | Also re-check when the tab regains focus |
| check | — | Custom detector → true when an update is available |
| currentVersion + latestVersion | — | Version compare |
| pingUrl | page URL | ETag/Last-Modified fallback target |
| onUpdateAvailable | — | Fired once on first detection |
Returns { updateAvailable, refresh, dismiss, check }. SSR-safe; polling stops
once an update is detected (or after dismiss()).
Using Inertia + Laravel?
@particle-academy/fancy-inertia
builds on this with a zero-config Inertia asset-version default (detects a
409 from a stale X-Inertia-Version — no endpoint needed) and a react-fancy
styled prompt.
License
MIT
⭐ Star Fancy UI
If this package is useful to you, a quick ⭐ on the repo really helps us build a better kit. Thank you!
