|
14 | 14 | yarn add react-clear-browser-cache |
15 | 15 | ``` |
16 | 16 |
|
| 17 | +Requires React 18 or newer. The `generate-build-meta` CLI needs Node.js 18.3 or newer. |
| 18 | + |
17 | 19 | ## Add script in package.json |
18 | 20 |
|
19 | | -Generate `meta.json` file with latest build version. |
| 21 | +Generate a `meta.json` file with a fresh build version before every build. |
20 | 22 |
|
21 | 23 | ```json |
22 | 24 | { |
23 | | - "prebuild": "npm run generate-build-meta", |
24 | | - "generate-build-meta": "node ./node_modules/react-clear-browser-cache/bin/cli.js" |
| 25 | + "prebuild": "generate-build-meta" |
25 | 26 | } |
26 | 27 | ``` |
27 | 28 |
|
| 29 | +The file is written to `./public/meta.json` by default; pass |
| 30 | +`--destination <path>` to write it elsewhere (for example |
| 31 | +`generate-build-meta --destination static/meta.json`). The command exits with |
| 32 | +code 1 when it cannot write the file. |
| 33 | + |
28 | 34 | ## Usage |
29 | 35 |
|
30 | 36 | ### Using `Boundary`: |
31 | 37 |
|
32 | 38 | `ClearBrowserCacheBoundary` has context provider for child elements (`useClearBrowserCache`), add him after your `ErrorBoundary`, because `ClearBrowserCacheBoundary` only handles certain errors like `ChunkLoadError`. |
33 | 39 |
|
34 | 40 | ```tsx |
35 | | -import React from 'react'; |
36 | | -import ReactDOM from 'react-dom'; |
| 41 | +import { createRoot } from 'react-dom/client'; |
37 | 42 |
|
38 | 43 | import { ClearBrowserCacheBoundary } from 'react-clear-browser-cache'; |
39 | 44 |
|
40 | 45 | import App from './App'; |
41 | 46 | import ErrorBoundary from './ErrorBoundary'; |
42 | 47 |
|
43 | | -ReactDOM.render( |
| 48 | +createRoot(document.getElementById('root')!).render( |
44 | 49 | <ErrorBoundary> |
45 | 50 | <ClearBrowserCacheBoundary auto fallback='Loading' duration={60000}> |
46 | 51 | <App /> |
47 | 52 | </ClearBrowserCacheBoundary> |
48 | | - </ErrorBoundary>, |
49 | | - document.getElementById('root') |
| 53 | + </ErrorBoundary> |
50 | 54 | ); |
51 | 55 | ``` |
52 | 56 |
|
| 57 | +### How it decides to reload |
| 58 | + |
| 59 | +- On mount the boundary shows `fallback` and fetches the meta file. On the first |
| 60 | + visit it records that version and renders the app. If a newer build is found |
| 61 | + later, it clears Cache Storage and reloads the page — on mount always, while |
| 62 | + polling only when `auto` is set; otherwise it sets `isLatestVersion` to |
| 63 | + `false` and leaves the reload to you (`clearCacheAndReload`). |
| 64 | +- Polling runs every `duration` ms while the window has focus. |
| 65 | +- When a child throws an error that looks like a stale build (a missing chunk, |
| 66 | + or a chunk URL answered with `index.html`), the boundary checks the version: |
| 67 | + if a new build is out it reloads, otherwise the error goes on to your |
| 68 | + `ErrorBoundary`. Recognised out of the box: webpack `ChunkLoadError` and CSS |
| 69 | + chunk errors, Vite CSS preload errors, native `import()` failures in |
| 70 | + Chrome, Firefox and Safari, and `SyntaxError: Unexpected token '<'`. |
| 71 | +- A meta file that is missing, has no `version`, or is answered with HTML by an |
| 72 | + SPA fallback is reported to `debug` and otherwise ignored; the app still |
| 73 | + renders. |
| 74 | + |
53 | 75 | ## Props |
54 | 76 |
|
55 | | -| Name | Type | Default | More info | |
56 | | -| :------------ | :------- | :----------- | :---------------------------------------------------------------------------------------------------------------- | |
57 | | -| duration | number | | You can set the duration when to fetch for new updates. | |
58 | | -| auto | boolean | false | Set to true to auto-reload the page whenever an update is available. | |
59 | | -| fallback | any | null | You can set fallback data when fetching new version - preloader etc. | |
60 | | -| storageKey | string | APP_VERSION | Storage key for saving app version. | |
61 | | -| storage | object | localStorage | You can use another storage to save and get the version of app like [store](https://www.npmjs.com/package/store). | |
62 | | -| filename | string | meta.json | Filename for fetching new app version. | |
63 | | -| errorCheckers | array | [] | You can set custom error checkers for catching errors concerned with invalid browser caches. | |
64 | | -| debug | function | | You can debug state and errors. | |
| 77 | +| Name | Type | Default | More info | |
| 78 | +| :------------ | :------- | :----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 79 | +| duration | number | | You can set the duration when to fetch for new updates. | |
| 80 | +| auto | boolean | false | Set to true to auto-reload the page whenever an update is available. | |
| 81 | +| fallback | any | null | You can set fallback data when fetching new version - preloader etc. | |
| 82 | +| storageKey | string | APP_VERSION | Storage key for saving app version. | |
| 83 | +| storage | object | localStorage | Any `{ get(key), set(key, value) }` object, e.g. [store](https://www.npmjs.com/package/store). | |
| 84 | +| filename | string | meta.json | Meta file to fetch. A bare name is fetched from the site root; a path starting with `/`, `./` or `../`, or a full URL, is used as is (e.g. `` `${import.meta.env.BASE_URL}meta.json` `` for an app under a sub-path). | |
| 85 | +| errorCheckers | array | [] | Extra `(error) => boolean` checks for errors caused by a stale build, added to the defaults. `createErrorChecker(name, regexp)` builds one. | |
| 86 | +| debug | function | | You can debug state and errors. | |
65 | 87 |
|
66 | 88 | ### Using `hook`: |
67 | 89 |
|
@@ -99,6 +121,44 @@ function App() { |
99 | 121 | | disabled | boolean | Indicates if the boundary component is disabled, stopped all requests, doesn't handle errors, just render children because of internal errors. | |
100 | 122 | | clearCacheAndReload | function | Clear CacheStorage and reload the page. | |
101 | 123 |
|
| 124 | +## `lazyRetry` |
| 125 | + |
| 126 | +Retries a failing dynamic import before giving up: |
| 127 | + |
| 128 | +```tsx |
| 129 | +import { lazy } from 'react'; |
| 130 | +import { lazyRetry } from 'react-clear-browser-cache'; |
| 131 | + |
| 132 | +const Settings = lazy(() => lazyRetry(() => import('./Settings'), 2, 1000)); |
| 133 | +``` |
| 134 | + |
| 135 | +`lazyRetry(fn, retries = 2, interval = 1000)` calls `fn`, and while it rejects |
| 136 | +calls it again up to `retries` more times, `interval` ms apart. |
| 137 | + |
| 138 | +## Migrating from 0.2 |
| 139 | + |
| 140 | +- React 18 or newer is required, and the package ships ESM and CommonJS builds |
| 141 | + with type declarations through `exports`. |
| 142 | +- `lazyRetry(fn, retries)` now makes `retries` extra attempts (the default is |
| 143 | + three attempts in total, it used to be two), and `retries = 0` no longer |
| 144 | + retries forever. |
| 145 | +- The stored version is only updated when the cache is actually cleared, so |
| 146 | + `isLatestVersion` stays `false` until the user reloads through |
| 147 | + `clearCacheAndReload`. |
| 148 | +- `storage` is typed as `{ get, set }`; the `@ts-ignore` the old type needed can |
| 149 | + go. |
| 150 | + |
| 151 | +## Development |
| 152 | + |
| 153 | +Use Node.js 24 (`.nvmrc`) and pnpm. |
| 154 | + |
| 155 | +```bash |
| 156 | +pnpm install |
| 157 | +pnpm test # lint, typecheck, unit tests, build, e2e |
| 158 | +pnpm test:unit # Vitest |
| 159 | +pnpm test:e2e # Playwright against the example app in Chromium, Firefox and WebKit |
| 160 | +``` |
| 161 | + |
102 | 162 | ## License |
103 | 163 |
|
104 | 164 | MIT © [arenuzzz](https://github.com/arenuzzz) |
0 commit comments