first commit
This commit is contained in:
91
docs/api-stack/api/api-loader/src/cache-bust/cache-bust.md
Normal file
91
docs/api-stack/api/api-loader/src/cache-bust/cache-bust.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# `bustSpecifier`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Compute the cache-busted ESM specifier used by the API plugin host during a
|
||||
hot reload. Bun's ESM cache is keyed on the full specifier string (including
|
||||
query parameters), so `file:///plugin/index.js` and
|
||||
`file:///plugin/index.js?v=2` are distinct cache entries even though both
|
||||
resolve to the same file on disk. `bustSpecifier` is the canonical helper
|
||||
the host calls on every reload to produce a fresh specifier — bumping the
|
||||
importing module's URL forces Bun to re-evaluate the entire transitive
|
||||
dependency subgraph without paying for an explicit cache invalidation API.
|
||||
|
||||
The function is pure and idempotent under monotonically-increasing version
|
||||
inputs: repeated calls **replace** the existing `?v=N` segment rather than
|
||||
concatenate, so a long-lived host can bust the same plugin thousands of
|
||||
times without growing the specifier string. This is the canonical algorithm
|
||||
referenced by design §8.2.
|
||||
|
||||
## Features
|
||||
|
||||
- Replaces (never concatenates) the `?v=N` query suffix.
|
||||
- Preserves unrelated query parameters and hash fragments.
|
||||
- Works with `file://`, `http://`, `https://`, and `data:` URLs.
|
||||
- Side-effect-free, allocation-light (one `URL` instance per call).
|
||||
- Strict input contract: throws synchronously on a malformed URL.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { bustSpecifier } from "@suaveplan/api-loader/cache-bust";
|
||||
|
||||
const specifier = bustSpecifier("file:///opt/plugin/index.js", 1);
|
||||
// → "file:///opt/plugin/index.js?v=1"
|
||||
const next = bustSpecifier(specifier, 2);
|
||||
// → "file:///opt/plugin/index.js?v=2" (NOT "?v=1?v=2")
|
||||
const mod = await import(next);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Within a reload loop, the host keeps a monotonically-increasing counter and
|
||||
busts the specifier on every flip. Other parameters (e.g. an integrity hash)
|
||||
survive the rewrite:
|
||||
|
||||
```ts
|
||||
import { bustSpecifier } from "@suaveplan/api-loader/cache-bust";
|
||||
|
||||
let reload = 0;
|
||||
const base = "file:///opt/plugin/index.js?integrity=abc";
|
||||
function nextSpecifier(): string {
|
||||
reload += 1;
|
||||
return bustSpecifier(base, reload);
|
||||
}
|
||||
// 1st call → "file:///opt/plugin/index.js?integrity=abc&v=1"
|
||||
// 2nd call → "file:///opt/plugin/index.js?integrity=abc&v=2"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
```ts
|
||||
export function bustSpecifier(url: string, version: number): string;
|
||||
```
|
||||
|
||||
- `url`: an absolute URL (a `file://` URL is typical inside the loader, but
|
||||
any URL supported by the WHATWG `URL` parser works).
|
||||
- `version`: a non-negative integer reload counter. Zero is permitted as a
|
||||
boundary case (used by the host on the initial load).
|
||||
|
||||
Returns the input URL with its `v` query parameter set to the string form of
|
||||
`version`. Other query parameters, the path, the fragment, and the
|
||||
authority are preserved verbatim.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The implementation uses the WHATWG `URL` API (`URL` and `URLSearchParams`)
|
||||
because it round-trips correctly: `URLSearchParams.set("v", ...)` replaces
|
||||
any existing `v` entry rather than appending a duplicate. Hand-rolled string
|
||||
concatenation (`${url}?v=${version}`) was rejected because it cannot detect
|
||||
an existing suffix — repeated busts under that approach would grow the
|
||||
specifier without bound (`?v=1?v=2?v=3`), and Bun's cache would treat each
|
||||
mutation as a distinct module forever, defeating the GC contract the
|
||||
rollback journal relies on.
|
||||
|
||||
The function throws `TypeError` from the WHATWG parser on a malformed URL
|
||||
input; the host's reload path catches and rewraps as
|
||||
`LOADER.MODULE_IMPORT_FAILED`.
|
||||
Reference in New Issue
Block a user