fix(deploy): cache the PowerSync wasm and stop caching the SPA shell - #1205
fix(deploy): cache the PowerSync wasm and stop caching the SPA shell#1205njbrake wants to merge 3 commits into
Conversation
_Note: this PR description was drafted by Claude via back-and-forth with @njbrake. The reasoning and decisions are his; the prose is Claude's._ Two nginx caching gaps that pull in opposite directions. **`/@powersync/` was matched by no location block**, so PowerSync's wa-sqlite assets fell through to `location /` with no caching directives at all. That is roughly 17MB of content-hashed files revalidated on every boot, when they are as immutable as anything under `/assets/`. **`index.html` had the opposite problem.** It is the shell that names the hashed entry chunk, so a cached copy pins a client to an old build after a deploy. It now sends `no-cache`, which still permits a conditional request, so the common case is a 304 rather than a re-download. Deep links pick this up too: the SPA fallback is a URI, so nginx does an internal redirect and re-runs location matching, and a request for `/settings` ends up in the `location = /index.html` block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6e4f0f8 to
e92aa24
Compare
|
Preview environment deployed 🚀
Stack: Auto-destroys on PR close/merge. Login via the bundled Keycloak realm — |
ital0
left a comment
There was a problem hiding this comment.
Thanks for this one. The diagnosis is right, and the index.html part checks out: the 304 flow and the internal redirect for deep links both work as described.
My one concern is the /@powersync/ block. That folder isn't all content-hashed: the two workers (worker/WASQLiteDB.umd.js, worker/SharedSyncImplementation.umd.js) have stable names and are loaded by fixed path in src/db/powersync/database.ts:108,113, so a year of immutable can leave Safari web clients on an old worker after a @powersync/web upgrade. That's the same stale-build problem the index.html half of this PR fixes. More in the line comment.
Two smaller notes: the ~17MB figure includes .map files the map rule already 404s (what can be served is closer to 10MB), and oauth-callback.html plus the other public/ statics still have no cache policy. Both may well be intentional, just flagging.
| # `3322bc84de986b63c2cd.wasm`, so they are as immutable as /assets/ -- and they | ||
| # total ~17MB, which is worth not revalidating on every boot. Without this they | ||
| # fall through to `location /`, which sets no caching directives at all. | ||
| location /@powersync/ { |
There was a problem hiding this comment.
One thing worries me here: not everything in this folder is content-hashed. copy-assets also emits index.umd.js and two workers (worker/WASQLiteDB.umd.js, worker/SharedSyncImplementation.umd.js) with stable names, and src/db/powersync/database.ts:108,113 loads those workers by fixed path (the config Safari uses on the web). With immutable for a year, a Safari client can stay on an old worker long after a @powersync/web upgrade, which is the same stale-build problem the index.html block below is fixing.
There was a problem hiding this comment.
Addressed in cbfad77. Split the block so ~ ^/@powersync/.*\.umd\.js$ serves the stable-named workers (and index.umd.js) no-cache, revalidating like index.html; only the content-hashed wasm keeps immutable. A @powersync/web upgrade can no longer strand a client on an old worker. Also gave oauth-callback.html its own no-cache rule; left the other public/ statics (favicons, capture-worklet.js) falling through, since they aren't content-hashed and the worklet loads by fixed path.
Note: this reply was drafted by Claude Opus 4.8 via back-and-forth with @njbrake. The reasoning and decisions are his; the prose is Claude's.
| # PowerSync's wa-sqlite wasm/worker assets, copied into public/@powersync by | ||
| # the `copy-powersync-assets` Vite plugin. Content-hashed filenames like | ||
| # `3322bc84de986b63c2cd.wasm`, so they are as immutable as /assets/ -- and they | ||
| # total ~17MB, which is worth not revalidating on every boot. Without this they |
There was a problem hiding this comment.
Small thing: the ~17MB counts the .map files, and the .map rule below already 404s those. What can actually be served is closer to 10MB.
There was a problem hiding this comment.
- The .umd.js workers have stable, fixed-path names, so `immutable` would pin clients to an old worker across a @powersync/web upgrade. Serve them no-cache (cheap 304) like index.html; keep immutable only for the content-hashed wasm. - The oauth-callback.html entry document should reflect the latest deploy, so revalidate it instead of letting it fall through uncached.
Note: this PR description was drafted by Claude via back-and-forth with @njbrake. The reasoning and decisions are his; the prose is Claude's.
Two nginx caching gaps that pull in opposite directions.
/@powersync/was matched by no location block, so PowerSync's wa-sqlite assets fell through tolocation /with no caching directives at all. That is roughly 17MB of content-hashed files revalidated on every boot, when they are as immutable as anything under/assets/.index.htmlhad the opposite problem. It is the shell that names the hashed entry chunk, so a cached copy pins a client to an old build after a deploy. It now sendsno-cache, which still permits a conditional request, so the common case is a 304 rather than a re-download.Deep links pick this up too: the SPA fallback is a URI, so nginx does an internal redirect and re-runs location matching, and a request for
/settingsends up in thelocation = /index.htmlblock.