Skip to content

fix: stop baking the build date into the client bundle - #9

Merged
Marius1311 merged 1 commit into
mainfrom
fix/reproducible-bundle
Aug 27, 2026
Merged

Marius1311 merged 1 commit into
mainfrom
fix/reproducible-bundle

Conversation

@Marius1311

Copy link
Copy Markdown
Member

Closes #2.

src/LandingPage.js inlined new Date().toDateString() through preval, so the bundle's content
hash changed on any build on a new day even when the client source was byte-identical.

Still live as of today. The release I cut an hour ago reproduced it: client source is identical
between quadbio-1.1.61.post2 and quadbio-1.1.61+quadbio.3 (git diff over src/ public/ package.json yarn.lock is empty), yet the shipped bundle went main.9857844c.js →
main.3ed24ed0.js.

Fix — show the package version instead of the date. The landing page already had a
REACT_APP_VERSION block, but nothing ever set it, so the date was the only thing rendering
there. The build script now wires it from $npm_package_version.

Verified by building the same source under two timezones that are on different calendar days:

build calendar day bundle
TZ=Pacific/Kiritimati Thu Aug 27 2026 main.e9cc62a6.js
TZ=Etc/GMT+12 Wed Aug 26 2026 main.e9cc62a6.js

Identical. No date string survives in the bundle (grep for Aug 27 2026, Aug 26 2026, Thu Aug, Wed Aug, Tue Aug → 0 hits), and Version: + 1.1.61 are present instead. The bundle is
252 bytes smaller.

For contrast, before this change: post1 (Aug 25) → main.ca3f787c.js, post2 (Aug 26) →
main.9857844c.js, from identical sources.

Also, per the issue's aside: release.yml now uses yarn install --frozen-lockfile, matching
FORK.md's local Euler recipe. A release job should not be free to resolve around the lockfile.

preval.macro is left in devDependencies deliberately — removing it would mean regenerating
yarn.lock, and a large lockfile churn is not worth it inside a fix whose whole point is build
reproducibility. Worth a follow-up.

LandingPage inlined `new Date().toDateString()` via preval, so the bundle's
content hash changed on any build on a new day even when the client source was
byte-identical. Every release invalidated every viewer's cached bundle, the
bundle name could not answer "did the client change?", and release artifacts
were not reproducible.

Show the package version instead -- the landing page already had a
REACT_APP_VERSION block, but nothing ever set it, so the date was the only
thing rendered. The build script now wires it from $npm_package_version.

Also make release.yml use `yarn install --frozen-lockfile`, matching FORK.md's
local recipe; a release job should not be free to resolve around the lockfile.

Verified: built under TZ=Pacific/Kiritimati (Thu Aug 27) and TZ=Etc/GMT+12
(Wed Aug 26) -- both give main.e9cc62a6.js, and no date string survives in the
bundle. Previously post1 (Aug 25) gave main.ca3f787c.js and post2 (Aug 26)
main.9857844c.js from identical sources.

Closes #2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BQnnW5jCKXnefXA89eBDoL
@Marius1311
Marius1311 merged commit ff4a0a7 into main Aug 27, 2026
2 checks passed
@Marius1311
Marius1311 deleted the fix/reproducible-bundle branch August 27, 2026 08:31
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.

Client bundle hash changes every calendar day: build date is baked in

1 participant