interface VersionerInterface
Records which revision of each compiled asset is current, so that a URL can be cache-busted and a client can tell when what it loaded was superseded.
Implementations are swappable — pointing the assets disk at S3 or sharing it between instances are both reasons to store revisions somewhere other than beside the files. What follows is what the compilers rely on, and what any replacement therefore has to provide. **A write must not disturb another file's revision.** Several instances record revisions at once — every one of them rebuilds a dirty asset set on its next request — and {[\Flarum\Frontend\Compiler\JsDirectoryCompiler::pruneStaleRevisions()} writes](../../../Flarum/Frontend/Compiler/JsDirectoryCompiler.html) once per stale chunk from `getUrl()`, so writes happen during ordinary page renders too. An implementation that saves the whole map back on every write loses whichever revisions were recorded since it last read: the writes report success, and because {[\Flarum\Frontend\Compiler\RevisionCompiler::getUrl()}](../../../Flarum/Frontend/Compiler/RevisionCompiler.html) only recompiles when a revision is *missing*, nothing notices the loss until the next admin action. Store each revision independently, or serialise the read-modify-write. **Writing an unchanged value must not write at all.** Pruning runs on renders, so a render that prunes nothing has to cost nothing. **Errors must propagate.** A read that fails but reports "no revision" makes `getUrl()` recompile on every request and then return null, dropping the stylesheet or bundle from the page; a write that fails but reports success leaves the old revision in place with nothing to trigger a retry. **Reads may be memoised for the lifetime of the instance, and no longer.** Rendering a page reads the map around thirty times and individual revisions around sixty-five, all through one shared instance, so caching within a request is expected. Caching beyond it would serve revisions that another instance has since replaced. A write must leave the memo agreeing with storage, so `getRevision()` returns what was just written. **`allRevisions()` must agree with `getRevision()`** for every file it contains: the map is inlined into the page for the client, and hashed into the asset revision token, so a disagreement shows up as a spurious reload prompt or a chunk the client cannot resolve.
Methods
Record the current revision of a file, or forget it when null.
Collect writes until {flushWrites()} instead of storing each one as it arrives, so a rebuild that records every asset in turn can store them together.
Details
at
line 56
void
putRevision(string $file, string|null $revision)
Record the current revision of a file, or forget it when null.
at
line 68
void
deferWrites()
Collect writes until {flushWrites()} instead of storing each one as it arrives, so a rebuild that records every asset in turn can store them together.
Buffered writes are still visible to this instance's own reads, and a read of anything buffered stores the buffer first, so nothing can observe a revision that has been recorded but not saved. An implementation with nothing to gain from batching may treat both methods as no-ops.
at
line 75
void
flushWrites()
Store anything {deferWrites()} collected, and stop deferring.
Safe to call when nothing was deferred.
at
line 80
string|null
getRevision(string $file)
The recorded revision, or null when there is none.
at
line 87
array
allRevisions()
Every recorded revision, keyed by file.