Skip to content

Move version into payload to avoid rotating client chunks#16271

Closed
Axeldeblen wants to merge 10 commits into
sveltejs:version-3from
Axeldeblen:version-chunk-rotation-fix
Closed

Move version into payload to avoid rotating client chunks#16271
Axeldeblen wants to merge 10 commits into
sveltejs:version-3from
Axeldeblen:version-chunk-rotation-fix

Conversation

@Axeldeblen

Copy link
Copy Markdown

closes
#12260
#9576


Somewhat adjacent to #14176

Context

For context we're running a svelte kit app and deploying many times per day. Currently svelte kit places the version into the client bundle, causing the chunks to rotate their hashes invalidating the caching whenever we deploy as described in #12260. This contributes to a degraded user experience in our case .e.g. a user will open a modal but the chunk will 404's the client chunks because the server version has rotated. We're using our git SHA as our version.

Description

This PR aims to solve the bundle rotating by refactoring the mechanism of how svelte kit defines and deliver the version within each client / server context.

Here is a simple visual flow of how the current version leaks into the client bundle via two seperate sources.

[see](https://vite.dev/config/shared-options#define) for how __SVELTEKIT_PAYLOAD__ is replaced by vite

kit.version.name  = 'version-alpha'
        │
        ├─▶ __sveltekit/environment emits  export const version = "version-alpha"
        │       └─▶ imported by runtime/client/utils.js (the `updated` poll)
        │
        └─▶ version_hash = hash(name)  ─▶  __SVELTEKIT_PAYLOAD__ (vite define  replacement)
                                            = globalThis.__sveltekit_<version_hash> -▶ __sveltekit__99avfu
        │
        ▼
both inlined into ONE shared client chunk   ←  its bytes change resulting in its content hash changing
        │ 
        ▼
every chunk that imports it gets a new hash  ← causes cascade effect across the entire client bundle
(entry/app, entry/start, nodes/*, other shared chunks)

Because the client uses the version hash as part of the global definition we need to keep it stable if we want to avoid the cascade effect.

For that reason we are using a combination of config values to avoid any global collisions in embedded sveltekit version like in #14176

hash(`${name}\n${kit.paths.base}\n${kit.appDir}`);

(Open to other suggestions on other combinations here)

Now the version_hash is stable on globalThis between deploys we pass the actual version through the payload.

Then we pass the version as a prop within the payload

	const properties = [
			`base: ${base_expression}`,
			`version: ${devalue.uneval(__SVELTEKIT_APP_VERSION__)}`
		];

N.B Perhaps version_hash needs to be renamed now as our definitions of "version" diverge a bit. I'd like to get a bit more feedback on the general approach here before continuing further refactoring.

Tests

I've added some tests to demonstrate the current issue. In these tests we build multiple versions of the app with different version inputs and compare the content of the built chunks to avoid running into situations similar to #12779 (even though we are not using post build plugins).

Production testing

Our app is currently pinned to a slightly older version of kit but we're happy to test the core of these changes out on a subset of production traffic to help verify.


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

I haven't made a change set yet but I will on confirmation the maintainers are happy with the direction of this PR.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

creating the test harness to validate client chunk rotation issue by testing chunk file names as well as chunk content
In the client we now read via the global version property rather than changing the name of the global object itself which was the source of bundle rotations
@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 8, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 37b34b0:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/37b34b0afcf35dc139ec60ae351a4eb2e4699fd9

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16271

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 37b34b0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Axeldeblen Axeldeblen marked this pull request as ready for review July 10, 2026 01:27
Comment thread packages/kit/src/core/utils.js Outdated
@dummdidumm

dummdidumm commented Jul 10, 2026

Copy link
Copy Markdown
Member

We might be able to solve this differently - moving the global access outside the modules that rarely change -; working on something locally. Then we can compare solutions.
FWIW I think this could also work but I'm not sure if we should just rely on the things used here. hashing the package.json contents could deduplicate better.

@teemingc

Copy link
Copy Markdown
Member

Going to close this in favour of #16324 which solves this without the need for hashing the app version

@teemingc teemingc closed this Jul 13, 2026
Rich-Harris pushed a commit that referenced this pull request Jul 14, 2026
…#16324)

The global `__sveltekit__abc123` is removed from the JS code in the
client runtime, it now only exists in the on-the-fly-generated rendered
HTML for app initialization and streaming chunks.

That way the SvelteKit runtime stays stable between redeploys as long as
it doesn't change, resulting in more cache hits.

It's achieve by creating a new payload file, which the global value is
passed to, and the other files then use the exported variable to get it.
Because some eagerly require it we have to split up the dynamic imports.
This should not matter because preloading loads and parses them in
parallel anyway.

Fixes #12260

Alternative to #16271

---------

Co-authored-by: Tee Ming Chew <chewteeming01@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

svelte.config.js version changes cause most client chunks to generate a new hash despite no other changes

3 participants