fix: stop shadowing the repo pnpm lockfile on Vercel (both apps) - #24
Merged
Conversation
All three Vercel projects set rootDirectory to a package (ripguard and ripguard-testnet -> packages/app, ripguard-sol -> packages/app-sol), so `pnpm install` runs inside the package directory. pnpm resolves its workspace root to the nearest pnpm-workspace.yaml, which was the one in the package itself -- so the repo-root pnpm-lock.yaml was never used and every dependency was re-resolved from its semver range at deploy time. That drift is what broke ripguard.xyz: fresh resolution now yields rainbowkit 2.2.11 -> @wagmi/connectors 6.2.0 -> @base-org/account 2.4.0 -> @coinbase/cdp-sdk 1.54.0, whose x402 module dynamically imports the @x402/* optional peer dependencies. They are legitimately absent, and Turbopack turns the unresolvable specifiers into build errors. The lockfile pins @coinbase/cdp-sdk 1.45.0, which has no such import, so CI and local builds stayed green. packages/app-sol carried the identical marker. It builds today only because its tree has not yet drawn a broken upstream release, so remove both rather than leave the second one armed. Removing the nested markers lets pnpm find the root workspace and lockfile from either package, making both deploys reproducible and identical to CI. The ignoredBuiltDependencies they carried were the same two entries and move to the root pnpm-workspace.yaml. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this PR exists
PR #23 carried this fix but accidentally targeted base
fable/fresh-eyesinstead ofmain, so it landed on an already-merged feature branch andmainis still broken —packages/app/pnpm-workspace.yamlis still present onmainand ripguard.xyz still fails to build. This retargets the fix tomain.It also expands the fix to
packages/app-sol, which carries the identical trap.The last green EVM production deploy was ~38 days ago. This predates the support-Telegram-link merge (PR #22) and is unrelated to it —
c005209..dcaaa9dtouched nopackage.jsonand nopnpm-lock.yaml.The failure on
main:Root cause
The deploys were never using the committed lockfile.
Every Vercel project sets
rootDirectoryto a package directory, with include source files outside the root directory enabled:ripguardpackages/apppnpm install)ripguard-testnetpackages/apppnpm install)ripguard-solpackages/app-solpnpm installSo Vercel runs
pnpm installinside the package directory. pnpm resolves its workspace root to the nearestpnpm-workspace.yamlwalking up from the cwd — and both packages had one (each carrying the same twoignoredBuiltDependenciesentries). That made each package its own workspace root, so the repo-rootpnpm-lock.yamlwas invisible and every dependency was re-resolved from its semver range on each deploy.That is why the break is latent and time-triggered rather than commit-triggered. Fresh resolution today walks
@rainbow-me/rainbowkit ^2.2.10→2.2.11→@wagmi/connectors 6.2.0→@base-org/account 2.4.0→@coinbase/cdp-sdk 1.54.0. That version's x402 module does:@x402/core,@x402/evm,@x402/svm,@x402/extensionsare declared optional peer dependencies ofcdp-sdk, so they are legitimately absent — but Turbopack statically analyses the dynamicimport()and turns each unresolvable specifier into a hard build error (8 of them). The committed lockfile pins@coinbase/cdp-sdk 1.45.0, which has no such import, which is why CI and local builds stayed green the whole time.The smoking gun in the failed deploy log is the store path:
./packages/app/node_modules/.pnpm/.... A workspace-root install puts the store at the repo root, not inside the package.packages/app-solis exposed to exactly the same mechanism. It builds green today only because its dependency tree has not yet drawn a broken upstream release — that is luck, not safety, so it is fixed here rather than left armed.Fix
Delete both
packages/app/pnpm-workspace.yamlandpackages/app-sol/pnpm-workspace.yaml, and move theirignoredBuiltDependenciesto the rootpnpm-workspace.yaml. The two files were byte-identical (sharp,unrs-resolver) — nothing app-specific is lost.pnpm now walks up from either package to the repo root, finds the workspace and
pnpm-lock.yaml, and installs the pinned tree. Vercel setsCI=1, so pnpm additionally defaults to--frozen-lockfile. Production, CI, and local now resolve identically.No lockfile change was needed —
pnpm install --frozen-lockfileat the root is clean, andCI=1 pnpm installfrom inside each package succeeds against the existing lockfile.Why not the alternatives
@x402/*packages. They are optional peers of a transitive dependency of a wallet connector RipGuard never invokes. It would pull a Coinbase payments SDK — including@x402/svmand its Solana stack — into the EVM app to satisfy an import that only exists to be caught and rethrown. It also leaves the deploys resolving fresh semver, so the next upstream release breaks prod again.@coinbase/cdp-sdkvia an override. Treats the symptom, freezes a transitive dep the app doesn't use, and still leaves every other transitive dep free to drift on deploy.serverExternalPackages/ a Turbopack alias. A bundler workaround for a dependency-resolution problem, and likewise leaves the builds non-reproducible.Restoring lockfile-driven installs is the actual root cause and is strictly the smaller change.
Verification
Both apps were verified against Vercel's real command sequence, not CI's, from a clean
node_modules:packages/appbefore: 8 ×Module not found: Can't resolve '@x402/...', resolving@coinbase/cdp-sdk@1.54.0, store atpackages/app/node_modules/.pnpm.packages/appafter: clean build, resolving@coinbase/cdp-sdk@1.45.0, store at the repo root. Routes/,/create,/vaultsall compile.packages/app-solafter: clean build, no nested store, same route set. Pinning it to the lockfile does not regress it.No wallet-connect regression in either app. Client chunks still contain:
walletConnect38 files,metaMask28,injected8,coinbaseWallet5,baseAccount4,rainbowkit4.x402appears in 0 client chunks — it was only ever reached through the SSR pass of@base-org/account's node entry.wallet-adapter7 files,solflare5,WalletMultiButton5,phantom4,backpack1.Also green for both packages:
tsc --noEmit,lint, andtest(115 app / 168 app-sol).For reference, the equivalent change on PR #23 produced a green
Vercel – ripguardpreview deploy — the same pipeline whose last production run onmain(ripguard-6pu8nnjtz) is still inERROR. The preview builds on this PR are the check that matters here.I did not view a rendered page in a browser: preview URLs are behind Vercel deployment protection and I did not authenticate through it. The claim is a green build and deploy, not a visual check of the running app.
Scope
Config only. No app source touched.
AGENTS.mdrecords therootDirectory+ nested-workspace gotcha so it does not get reintroduced.🤖 Generated with Claude Code