Native support for deployment pinning / skew protection #23196
emiliosheinz
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
What I'm trying to do
We deploy a Vite SPA to Vercel many times a day. Each deployment re-hashes asset filenames, which means a tab left open on an older deployment can start returning 404s as soon as it lazy-loads a chunk.
The standard solution is skew protection: every asset request from a given build is tagged with that build’s deployment ID, for example
?dpl=<id>. This keeps an older tab pinned to its original asset graph, allowing it to continue loading immutable files from the deployment it was built against.Vercel already serves these pinned assets. Next.js supports this out of the box through
deploymentIdThis isn’t specific to Next.js, either. SvelteKit supports asset pinning natively through its Vercel adapter, and Astro 5.15 added a first-class
assetQueryParamshook for appending a per-deployment token to emitted asset URLs.Vite is the remaining piece without first-class support.
What it takes today
experimental.renderBuiltUrlgets you part way. It rewritesnew URL(...)-style asset references and public assets, so I can pin .js/image/font URLs there:But
renderBuiltUrldoes not touch the static or dynamic import specifiers that connect emitted chunks. Those are precisely the requests that 404 across deployments, and therefore, the URLs skew protection needs to pin.To cover them today, I have to post-process the bundle myself:
generateBundlepass over every JavaScript chunk, usees-module-lexerto locate relative import/export specifiers, and append?dpl=usingmagic-string.order: 'post', after Vite’s own import-analysisgenerateBundlestep. If the URLs are rewritten earlier, Vite can no longer resolve the chunk dependencies correctly and silently drops them from themodulepreloadlist.edited → chunkmap with Vite’schunk → sourcemap to produce a correctedited → sourcemap, while preserving inlined source content. This requires@jridgewell/gen-mappingand@jridgewell/trace-mapping.build.sourcemap: 'inline'cannot be supported with this approach. BygenerateBundle, I can only rewrite an external.mapasset, so the plugin has to hard-error when inline sourcemaps are enabled.So what sounds like “append a query string to asset URLs” actually requires a WASM lexer, source rewriting, sourcemap recomposition, and a specific plugin-ordering constraint. Purely to modify URLs that Vite already emits and controls.
The ask
Would the team consider adding native support for deployment pinning?
For example, Vite could expose a built-in option such as
build.deploymentIdorversionQuerythat appends a caller-supplied token to every emitted asset URL, including inter-chunk imports:modulepreloadlinksIdeally, this would happen inside Vite’s URL-emission pipeline, where things like sourcemaps and
.cssdetection are already handled correctly.This would be similar in shape to Next.js’s
deploymentIdor Astro’sassetQueryParams.Alternatively, perhaps this could be supported through a first-party
vercelSkewProtection-style plugin.Happy to share the full plugin implementation, including the sourcemap-composition code, if that would be useful.
All reactions