first commit
This commit is contained in:
103
docs/foundation/data/packer-browser/src/prefetch/prefetch.md
Normal file
103
docs/foundation/data/packer-browser/src/prefetch/prefetch.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# `prefetch` — BackgroundFetch integration
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `prefetch` module wraps the Chromium `BackgroundFetchManager` API so
|
||||
an application can preload an archive on idle without holding the page
|
||||
open. The page side calls `prefetchPackedArchive(url, opts)` to kick off
|
||||
the registration; the Service Worker listens for
|
||||
`backgroundfetchsuccess` and calls `handleBackgroundFetchSuccess` to
|
||||
drain the records into the same cache the rest of `@suaveplan/packer-browser`
|
||||
uses. Failures and aborts route through `handleBackgroundFetchFailure`.
|
||||
|
||||
These helpers are PACKER-BROWSER-20's production surface. They are
|
||||
feature-detected — if the browser does not implement BackgroundFetch
|
||||
(`navigator.serviceWorker.ready.backgroundFetch` is undefined and no
|
||||
`backgroundFetch` is injected), `prefetchPackedArchive` resolves with
|
||||
`null` and the caller's flow continues with a regular fetch.
|
||||
|
||||
## Features
|
||||
|
||||
- API feature-detection — graceful `null` when BackgroundFetch is absent
|
||||
- Pluggable `backgroundFetch` injection for tests
|
||||
- OTel counters: `packed_resource_prefetch_success_total` and
|
||||
`packed_resource_prefetch_failure_total`
|
||||
- Cache-drain helper writes every record's response into the configured
|
||||
cache (default `packed-resources-v1`) so the SW's existing fetch
|
||||
handler hits cached entries on the next request
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { prefetchPackedArchive } from "@suaveplan/packer-browser/prefetch";
|
||||
|
||||
// Page side:
|
||||
const reg = await prefetchPackedArchive("/big.bundle.asset");
|
||||
if (reg !== null) console.log("BG fetch started:", reg.id);
|
||||
```
|
||||
|
||||
```ts
|
||||
// Service worker side:
|
||||
import { handleBackgroundFetchSuccess } from "@suaveplan/packer-browser/prefetch";
|
||||
|
||||
self.addEventListener("backgroundfetchsuccess", (event) => {
|
||||
event.waitUntil(
|
||||
handleBackgroundFetchSuccess(event, {
|
||||
observability,
|
||||
cacheName: "packed-resources-v1",
|
||||
})
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
handleBackgroundFetchFailure,
|
||||
handleBackgroundFetchSuccess,
|
||||
prefetchPackedArchive,
|
||||
} from "@suaveplan/packer-browser/prefetch";
|
||||
|
||||
const reg = await prefetchPackedArchive("/heavy.bundle.asset", {
|
||||
id: "heavy-asset",
|
||||
options: {
|
||||
title: "Pre-loading heavy asset",
|
||||
icons: [{ src: "/icon-192.png", sizes: "192x192" }],
|
||||
},
|
||||
observability,
|
||||
});
|
||||
|
||||
// Failure listener — counts every abort.
|
||||
self.addEventListener("backgroundfetchfail", (event) =>
|
||||
handleBackgroundFetchFailure(event, { observability })
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `prefetchPackedArchive(archiveUrl, opts?): Promise<BackgroundFetchRegistrationLike | null>`
|
||||
- `handleBackgroundFetchSuccess(event, { caches?, cacheName?, observability }): Promise<void>`
|
||||
- `handleBackgroundFetchFailure(event, { observability }): void`
|
||||
|
||||
Every helper accepts a fully injectable cache storage / background
|
||||
fetch manager so tests can exercise real failure modes (cache write
|
||||
rejection, missing API, registration with zero records) without any
|
||||
mocking.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `prefetchPackedArchive` never reads the `navigator` global directly:
|
||||
production callers receive the `BackgroundFetchManager` from
|
||||
`await navigator.serviceWorker.ready` and pass it in. This keeps the
|
||||
helper safe to call from non-DOM contexts (workers, tests).
|
||||
- The success handler clones every response before writing to the cache
|
||||
so the body stream is consumed exactly once.
|
||||
- Failure counter increments are emitted from BOTH
|
||||
`prefetchPackedArchive` (when the underlying `fetch()` rejects) AND
|
||||
`handleBackgroundFetchFailure` (for SW-side abort events) so dashboards
|
||||
show every failure regardless of which layer caught it.
|
||||
Reference in New Issue
Block a user