Skip to content

Ship one copy of each WebAssembly runtime instead of seven - #182

Merged
YurMil merged 2 commits into
mainfrom
claude/vercel-site-size-deploy-hcdb6w
Sep 21, 2026
Merged

YurMil merged 2 commits into
mainfrom
claude/vercel-site-size-deploy-hcdb6w

Conversation

@YurMil

@YurMil YurMil commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #180. That PR stopped each deployment shipping six locale copies of static/ (~2.1 GB → ~440 MB). This one removes the duplication that remains inside static/: ~440 MB → 291 MB.

The duplication

The pre-built utility apps each bundle their own copy of the same WebAssembly runtimes:

Payload Copies Wasted
opencascade.full-BROZOezB.wasm (48 MB) 3 96 MB
replicad_single-BXInhmaQ.wasm (10.3 MB) 4 31 MB
replicad_single-ko7rBbsE.wasm (10.4 MB) 3 21 MB

One of those copies is simply dead: static/utility-apps/webstep-viewer/opencascade.full-BROZOezB.wasm, sitting next to assets/ rather than in it. Nothing loads it — assets/worker-Br7ins6r.js resolves the file with new URL("opencascade.full-BROZOezB.wasm", import.meta.url), which lands inside assets/, where the real copy is. scripts/sync-webstep-viewer-embed.js never wrote the root copy either (it syncs assets/, app.html and three occt-* files), so it will not come back.

Changes

  • Delete the unreferenced root copy in webstep-viewer (48 MB out of the repo).
  • scripts/dedupe-shared-assets.js, chained into postbuild after dedupe-locale-static.js: hashes every file ≥ 1 MB under utility-apps/ and mini-games/, keeps the lexicographically first copy of each distinct payload and deletes the others from build/ (99.6 MB); vercel.json rewrites the deleted URLs to the copy that stays. .html is never collapsed — identical markup at two URLs is two real pages.
  • Six rewrites in vercel.json, placed above the locale static rewrite.

Design notes

The rules are derived from static/, which Docusaurus copies verbatim and which this script never touches; only the deletions look at build/. That keeps validation a pure function of the committed tree however often the script runs, so it can be strict: the build fails when vercel.json is missing a rule, keeps one that is no longer a current duplicate, or orders one after the locale rewrite (first match wins, so such a rule would be shadowed for localized URLs). All three are reported together, since a rename trips two of them at once. The deletion loop skips what is already gone, so a second run over the same build is a no-op.

Each rule carries its own optional locale prefix (/:locale(ru|ua|de|es|et)?/…) instead of relying on the locale rewrite feeding into it, since only one rewrite applies per request.

The 1 MB threshold covers 99.6 of the 100.2 MB of duplication with six rules; going lower would add ~15 rules for the last 0.6 MB.

Verification

  • Full pnpm build green: Removed 2530 duplicated static files from locale builds (1447.9 MB). then Removed 6 duplicated app assets shared between utility apps (99.6 MB). A second run of the script reports Removed 0.
  • Build output 291 MB (was ~440 MB). No duplicate ≥ 1 MB remains; all six rewrite destinations exist in build/, all six sources are gone.
  • Routing replayed through path-to-regexp: /utility-apps/qr-nameplate/assets/replicad_single-ko7rBbsE.wasm and /ru/… both resolve to the blind-flange-calculator copy; /ru/utility-apps/metal-bending/… and /ru/utility-apps/pdf-master/… still fall through to the existing locale rewrite; /ru/docs/intro/ is untouched.
  • Guards exercised against a deliberately broken tree: a rule missing from vercel.json, a rule ordered after the locale rewrite, an asset renamed to a new content hash, and an asset deleted outright. Each fails the build with the offending rules printed; the rename reports both the stale rule and the missing one in the same run.
  • pnpm lint 0 errors (162 pre-existing warnings in src/), pnpm typecheck clean.

Note

As with the locale dedupe, the deleted URLs resolve through vercel.json and so 404 under docusaurus serve; pnpm start is unaffected.

At 291 MB the 10 GB Hobby quota holds ~34 deployments instead of ~22. Setting a Deployment Retention policy for preview/canceled/errored deployments is still the lever that stops storage accumulating at all, and is not part of this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ao3WhHUZQ3z7Y5L1XHwMVN

Two utility apps bundle the same 48 MB OpenCascade build and seven bundle
replicad, so every deployment carried ~149 MB of byte-identical files.
On top of that, webstep-viewer kept a second copy of OpenCascade next to
its assets/ directory that nothing loads: its worker resolves the file
relative to import.meta.url, which lands in assets/, and the sync script
never wrote the root copy either. Build output drops from ~440 MB to
291 MB, so the 10 GB Hobby quota now holds ~34 deployments instead of 22.

- Delete the unreferenced root copy in webstep-viewer (48 MB).
- postbuild: keep one copy of each payload >= 1 MB under utility-apps/
  and mini-games/, drop the rest (99.6 MB); vercel.json rewrites the
  deleted URLs to the copy that stays. HTML is never collapsed, since
  identical markup at two URLs is two real pages.
- The script derives the rules from the build and fails when vercel.json
  is missing one, keeps one that stopped matching, or orders one after
  the locale static rewrite, which would shadow it.
- Each rule carries its own optional locale prefix rather than relying on
  the locale rewrite feeding it, because only the first match applies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ao3WhHUZQ3z7Y5L1XHwMVN
@vercel

vercel Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cadautoscript-com Ready Ready Preview Sep 21, 2026 4:26pm UTC

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-21T04:04:14.562509Z eca7c7c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@supabase

supabase Bot commented Sep 21, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project bkcimygtsnckzexbfqxh because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eca7c7c6ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/dedupe-shared-assets.js Outdated
The drift guard validated vercel.json against build/, the one tree the
script mutates, so it had to tolerate a missing source to stay a no-op on
a second run. An app rebuild that renames a formerly duplicated asset hit
that same case: source gone, canonical destination still there, rule
silently kept. Renames are how these hashed bundle names change, so the
guard missed the drift it exists to catch.

Derive the rules from static/ instead, which Docusaurus copies verbatim
and which this script never touches. Validation is then a pure function
of the committed tree and rejects any rule that is not a current
duplicate, while the deletions skip what is already gone, so a second run
is still a no-op.

Also report the missing, stale and misordered rules together: a rename
trips two of them at once, and the build takes minutes to reach here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ao3WhHUZQ3z7Y5L1XHwMVN
@YurMil
YurMil merged commit 1d726d4 into main Sep 21, 2026
8 checks passed

This branch was successfully deployed

1 active deployment
Preview — f4cf80d7 Deployed Sep 21, 2026 by vercel[bot]
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.

2 participants