@astrapi69/pwa-update-react
v0.2.0
Published
React UI for PWA update detection: update banner, check-for-updates control, version card and deploy-safe lazy routes — messages-, slot- and store-injectable
Maintainers
Readme
@astrapi69/pwa-update-react
React UI for @astrapi69/pwa-update:
a discreet update banner, an active "check for updates" control, a version
card, and deploy-safe lazy routes.
npm install @astrapi69/pwa-update @astrapi69/pwa-update-reactQuick start
import { createUpdateStore } from "@astrapi69/pwa-update";
import { PwaUpdateProvider, UpdateBanner } from "@astrapi69/pwa-update-react";
const store = createUpdateStore({
build: { version: __APP_VERSION__, buildHash: __BUILD_HASH__ },
manifestUrl: `${import.meta.env.BASE_URL}version.json`,
storageNamespace: "my-app",
});
export function App() {
return (
<PwaUpdateProvider store={store}>
<Routes />
<UpdateBanner />
</PwaUpdateProvider>
);
}Both surfaces read the SAME store, so a passively detected update shows up on the settings control without a press, and applying at either place clears both.
useAppUpdate (and therefore UpdateBanner) wires the store's proactive
polling automatically — configure it on the store via polling, and the hook
starts and stops it with the component lifecycle.
Components
| Export | What it is |
|---|---|
| UpdateBanner | Connected banner — mount once at the app root. Renders nothing until an update is detected. |
| UpdatePrompt | The presentational bar behind it. All copy and callbacks are props; use it directly for a custom flow. |
| UpdateCheckControl | Active "check for updates" button, result line and last-checked footer. |
| VersionCard | Version / build hash (optionally linked to the commit) / build date. Takes an UpdateCheckControl as a child. |
| lazyWithReload | React.lazy that survives a stale deploy — one automatic reload on a chunk-load failure, loop-guarded. |
| useAppUpdate | The banner's state, if you render your own. |
| useUpdateState | Raw store snapshot via useSyncExternalStore. |
| useOnlineStatus | Coarse navigator.onLine signal. |
i18n
All strings live in one messages object with English defaults. Override
only what you need:
<PwaUpdateProvider store={store} messages={{ apply: "Aktualisieren" }} locale="de" />If your app already has an i18n system, build the object in one line —
MESSAGE_KEYS documents the keys so they can live in your catalogs:
import { messagesFromTranslate } from "@astrapi69/pwa-update-react";
<PwaUpdateProvider store={store} messages={messagesFromTranslate(t)} locale={lang} />Styling
Components carry token-backed utility classes and a stable semantic class
name on every element (pwa-update-prompt, pwa-update-prompt-apply,
pwa-update-check, pwa-version-card, …). Two ways to fit your design:
- Tailwind + design tokens — define
--bg-surface,--fg-primary,--accent,--borderetc. and the components inherit your theme. - Plain CSS — target the semantic class names and ignore the utilities.
Buttons additionally go through a slot, so a design-system primitive drops in:
<PwaUpdateProvider store={store} Button={MyButton} />The slot Button receives variant (default | outline | ghost) and
size (default | sm); the default renders a plain <button> carrying
them as data-variant / data-size.
The iOS restart hint
On an installed iOS PWA, skipWaiting() + reload often does not activate the
new worker — only a full app close-and-reopen does. UpdateBanner shows the
fullRestartHint message in exactly that situation, driven by the store's
needsFullRestart state rather than a host-side check, so it cannot be
forgotten. Background: the "Platform quirks this package encodes" section of
the core package README.
License
MIT © Asterios Raptis
