Skip to content

Commit b352f8d

Browse files
authored
Merge pull request #6 from devmaxxx/chore/modernize-react18-tsdown
Modernize tooling, require React 18 and fix cache boundary bugs
2 parents 1df08e0 + 1fbdd68 commit b352f8d

53 files changed

Lines changed: 4770 additions & 23561 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.eslintignore‎

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎.eslintrc‎

Lines changed: 0 additions & 34 deletions
This file was deleted.

‎.github/workflows/ci.yml‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
8+
jobs:
9+
check:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: pnpm/action-setup@v4
14+
- uses: actions/setup-node@v4
15+
with:
16+
node-version-file: .nvmrc
17+
cache: pnpm
18+
- run: pnpm install --frozen-lockfile
19+
- run: pnpm lint
20+
- run: pnpm build
21+
- run: pnpm typecheck
22+
23+
unit:
24+
runs-on: ubuntu-latest
25+
strategy:
26+
matrix:
27+
react: ['18.0.0', '18.3.1', '19']
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: pnpm/action-setup@v4
31+
- uses: actions/setup-node@v4
32+
with:
33+
node-version-file: .nvmrc
34+
cache: pnpm
35+
- run: pnpm install --frozen-lockfile
36+
- name: Use React ${{ matrix.react }}
37+
if: matrix.react != '19'
38+
run: pnpm add -D -w react@${{ matrix.react }} react-dom@${{ matrix.react }}
39+
- run: pnpm test:unit
40+
41+
cli:
42+
runs-on: ubuntu-latest
43+
strategy:
44+
matrix:
45+
node: [18, 20, 22, 24]
46+
steps:
47+
- uses: actions/checkout@v4
48+
- uses: actions/setup-node@v4
49+
with:
50+
node-version: ${{ matrix.node }}
51+
- run: node bin/cli.js --destination tmp/meta/meta.json
52+
- run: node -e "const {version} = require('./tmp/meta/meta.json'); if (!/^[0-9a-f-]{36}$/.test(version)) process.exit(1)"
53+
54+
e2e:
55+
runs-on: ubuntu-latest
56+
steps:
57+
- uses: actions/checkout@v4
58+
- uses: pnpm/action-setup@v4
59+
- uses: actions/setup-node@v4
60+
with:
61+
node-version-file: .nvmrc
62+
cache: pnpm
63+
- run: pnpm install --frozen-lockfile
64+
- run: pnpm exec playwright install --with-deps chromium firefox webkit
65+
- run: pnpm test:e2e
66+
- uses: actions/upload-artifact@v4
67+
if: failure()
68+
with:
69+
name: playwright-report
70+
path: test-results

‎.gitignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ yarn-error.log*
3232

3333
# vim
3434
*.swp
35+
36+
# playwright
37+
playwright-report
38+
test-results

‎.htmlvalidate.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["html-validate:recommended", "html-validate:prettier"]
3+
}

‎.nvmrc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24

‎.prettierignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
dist
2+
coverage
3+
pnpm-lock.yaml
4+
playwright-report
5+
test-results
6+
example/public/meta.json

‎.prettierrc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"semi": true,
55
"tabWidth": 2,
66
"bracketSpacing": true,
7-
"jsxBracketSameLine": false,
7+
"bracketSameLine": false,
88
"arrowParens": "always",
99
"trailingComma": "none"
1010
}

‎.travis.yml‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎README.md‎

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,54 +14,76 @@ or
1414
yarn add react-clear-browser-cache
1515
```
1616

17+
Requires React 18 or newer. The `generate-build-meta` CLI needs Node.js 18.3 or newer.
18+
1719
## Add script in package.json
1820

19-
Generate `meta.json` file with latest build version.
21+
Generate a `meta.json` file with a fresh build version before every build.
2022

2123
```json
2224
{
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"
2526
}
2627
```
2728

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+
2834
## Usage
2935

3036
### Using `Boundary`:
3137

3238
`ClearBrowserCacheBoundary` has context provider for child elements (`useClearBrowserCache`), add him after your `ErrorBoundary`, because `ClearBrowserCacheBoundary` only handles certain errors like `ChunkLoadError`.
3339

3440
```tsx
35-
import React from 'react';
36-
import ReactDOM from 'react-dom';
41+
import { createRoot } from 'react-dom/client';
3742

3843
import { ClearBrowserCacheBoundary } from 'react-clear-browser-cache';
3944

4045
import App from './App';
4146
import ErrorBoundary from './ErrorBoundary';
4247

43-
ReactDOM.render(
48+
createRoot(document.getElementById('root')!).render(
4449
<ErrorBoundary>
4550
<ClearBrowserCacheBoundary auto fallback='Loading' duration={60000}>
4651
<App />
4752
</ClearBrowserCacheBoundary>
48-
</ErrorBoundary>,
49-
document.getElementById('root')
53+
</ErrorBoundary>
5054
);
5155
```
5256

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+
5375
## Props
5476

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. |
6587

6688
### Using `hook`:
6789

@@ -99,6 +121,44 @@ function App() {
99121
| disabled | boolean | Indicates if the boundary component is disabled, stopped all requests, doesn't handle errors, just render children because of internal errors. |
100122
| clearCacheAndReload | function | Clear CacheStorage and reload the page. |
101123

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+
102162
## License
103163

104164
MIT © [arenuzzz](https://github.com/arenuzzz)

0 commit comments

Comments
 (0)