Issue #3614077: Serve the venue background SVG as its own resource instead of inlining it per configuration
What moved
The venue's background artwork left the map document. VenueMapBuilder no longer
reads the file at all, and the picker page names the file's own URL next to the
map URL, so the browser fetches the drawing and the picture at the same moment
and folds them together.
Measured on a 1,422-seat hall: each document loses 35,643 bytes (as drawn 259,754 -> 224,111; the reduced-capacity configuration 186,233 -> 150,590). That is more than the file's own 19,939 bytes, because JSON-escaping SVG markup nearly doubles it, and that overhead is now gone entirely. The artwork is one 19,939-byte request shared by every configuration and every production in the hall, where before each configuration's document carried its own escaped copy.
Injected, not linked, and that is a requirement
The artwork is fetched and injected into the page rather than referenced as an
<img>. Two things depend on it being a live part of the document:
- a seat is drawn as
<use href="#place-glyph">, resolving against a<symbol>the artwork defines; - a pooled area's clickable zone is a shape inside the artwork, looked up by
id and given classes and an
aria-label.
An <img> would leave every seat invisible and every zone dead, which is why
this does not separate the sprites out of the file the way the issue first
proposed. The file stays whole, and initPlaceMap() is untouched: the bootstrap
puts the markup back where the renderer has always looked for it.
The stamp
The URL carries the artwork's modification time. A web server serves a static file with a long lifetime (a year, on the site this was measured on), so without a stamp, moving the picture behind a stable URL would have traded a stale copy in Drupal's cache for a stale copy in every visitor's browser.
Uploading through the venue form needs no stamp, since core renames on collision
and a new upload is a new file with a new name. The venue importer is the
case that does: it overwrites the artwork in place with FileExists::Replace.
The file entity's own changed time is not enough there, because ChangedItem
moves it only when some other field value moves too, so replacing a picture with
one of the same byte length would go unnoticed.
The stamp is built on the picker page rather than inside the map document, because that document is cached until an entity tag retires it and this page is rebuilt on every view. It also means both fetches can start at once instead of one after the other.
Tests
VenueMapFetchTestgains two browser tests: the artwork arrives from its own stamped URL with its<symbol>present in the page and the seats referencing it, and artwork that answers 404 shows the failure message rather than a hall of seats drawn in the wrong places.VenueMapEndpointTestgains a test that the page names the artwork with a stamp and that replacing the file the way the importer does moves the URL. Its existing test now asserts the document carries no<svgat all.- The kernel assertions that read the artwork out of the payload now read it from the file, which is where that relationship lives.
16 browser tests and 6 functional tests pass, run twice; phpcs, phpstan and
cspell are clean. No new translatable strings, so fr.po is unchanged: the
failure path reuses the existing message.
Still open, deliberately
The picker page itself stays uncacheable, since it carries the visitor's own held seats. That was noted in #3614076 and is unchanged here.