Skip to main content

Module cache

Module cache 

Source
Expand description

Cross-process disk cache for compiled QuickJS bytecode.

Compiling a bundle to bytecode costs real time per process, and the bundle step before it more. An in-memory cache only helps within one process; a fresh start pays again. This persists the bytecode (plus its source map and a caller sidecar) to disk so an unchanged source tree skips BOTH the bundler and the compile entirely.

§Soundness

Module::load on bytecode is unsafe: it trusts the input was produced by an identical QuickJS build with native endianness. A disk cache crosses process (and machine) boundaries, so every entry lives under an abi_tag-named directory folding the QuickJS version (which tracks the on-disk BC_VERSION), target arch, endianness, and pointer width. Bytecode is only ever loaded from the directory matching the running toolchain – a mismatched build simply misses and recompiles. Bumping rquickjs changes JS_GetVersion() and thus the directory, so stale bytecode is never loaded.

§Freshness

A bundle inlines its whole import graph, so the entry file’s stamp is not enough – an edited (but still-imported) helper must invalidate. Each entry records a stamp of every transitive input; a load re-checks them all and misses on any change, addition, or deletion.

Structs§

BytecodeCache
Where compiled bytecode is kept between processes. A value, so two hosts in one process can keep separate caches and a host that wants none says so.
CacheEntry
One cached compile: the bytecode plus the auxiliary data each caller needs to reconstruct its result without re-running rolldown.

Functions§

abi_tag
Toolchain fingerprint. Bytecode under one tag is safe to Module::load only by an identical toolchain. fjbc<N> is our own format version – bump it on any change to the record shape, or to anything baked into the bytecode that a reader now depends on.
entry_key
A stable key for a set of entry paths (canonicalized, order-independent). The transitive content check on load is what actually guards freshness; this only needs to be collision-free across distinct bundle requests.
input_set
The transitive input set for a bundle: the entry files plus every module rolldown reported in the chunk’s graph, canonicalized and deduped.
inputs_fingerprint
Content fingerprint over a transitive input set, for an in-process cache tier that has to answer the same freshness question BytecodeCache::load answers on disk: has ANY input changed, not just the entry file.
source_stamp
Identity of a module’s source WITHOUT reading it: modification time and length, folded together.