Identical source code produces different dist/_astro/*.js filenames across consecutive astro build runs. This breaks CDN caching because the same unchanged code gets different URLs on each deploy.
pnpm install
pnpm test # runs 10 builds and compares outputExpected: all 10 builds produce identical output. Actual: ~60% of consecutive build pairs produce different JS filenames.
Example output:
Build 1: 8bc47ea55d5d13a6359f0d39b2461712
Build 2: 8bc47ea55d5d13a6359f0d39b2461712
Build 3: 7c17b92b2df44911065cc8e19abf7622
^^^ DIFFERS from build 2:
Only in build3/_astro: SvelteWidget0.CHZtD1E3.js
Only in build2/_astro: SvelteWidget0.DNGJBpKz.js
Only in build3/_astro: SvelteWidget1.C_-Zw1cq.js
Only in build2/_astro: SvelteWidget1.Ch6lmidG.js
(4 total differences)
RESULT: Non-deterministic! 6 of 9 consecutive comparisons differed.
In packages/astro/src/core/build/static-build.ts, the client build entry points are passed to Rollup via Array.from(internals.clientInput). clientInput is a Set whose iteration order depends on the order components were discovered during the prerender phase.
The discovery order is non-deterministic because:
- The
plugin-analyzeriteratesthis.getModuleIds()in thegenerateBundlehook getModuleIds()returns modules in Map insertion order- Insertion order depends on async module resolution timing in Rollup's
fetchStaticDependencies(which usesPromise.all)
When Rollup receives entry points in different order, chunk assignment and hash collision resolution produce different output filenames.
Sort the client input array before passing it to Rollup:
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
builder.environments.client.config.build.rollupOptions.input = Array.from(
internals.clientInput
- );
+ ).sort();Apply it manually to the installed Astro package:
# Find and patch the file
ASTRO_BUILD=$(find node_modules -path "*/astro/dist/core/build/static-build.js" | head -1)
# On macOS:
sed -i '' 's/Array\.from(\n*\s*internals\.clientInput\n*\s*)/Array.from(internals.clientInput).sort()/g' "$ASTRO_BUILD"
# Or manually: find the line that says
# builder2.environments.client.config.build.rollupOptions.input = Array.from(
# internals.clientInput
# );
# and add .sort() after the closing parenthesis of Array.from().
# Then re-run the test:
pnpm testAfter the fix, all 10 builds produce identical output.
- astro: 6.1.7
- vite: 7.3.2
- rollup: 4.60.1
- Node.js: v24
- OS: macOS (Darwin)