Skip to content

fix(app): stop shadowing the repo pnpm lockfile on Vercel - #23

Merged
fielding merged 1 commit into
fable/fresh-eyesfrom
fm/ripguard-evm-build-fix-s1
Jul 27, 2026
Merged

fix(app): stop shadowing the repo pnpm lockfile on Vercel#23
fielding merged 1 commit into
fable/fresh-eyesfrom
fm/ripguard-evm-build-fix-s1

Conversation

@fielding

@fielding fielding commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Why

The ripguard (EVM) Vercel project has been failing to build. The last green EVM production deploy was ~38 days ago — this predates the support-Telegram-link merge (PR #22) and is unrelated to it. The diff c005209..dcaaa9d touched no package.json and no pnpm-lock.yaml. packages/app-sol was never affected, so sol.ripguard.xyz stayed green.

The failure:

Module not found: Can't resolve '@x402/core/client'
  @coinbase/cdp-sdk@1.54.0/_esm/actions/x402/signX402Payment.js
  <- @base-org/account 2.4.0
  <- @wagmi/connectors 6.2.0 (baseAccount)
  <- @rainbow-me/rainbowkit 2.2.11        [Client Component SSR]

Root cause

The deploy was never using the committed lockfile.

The Vercel project is configured with rootDirectory = packages/app, no custom install command, and include source files outside the root directory enabled — so Vercel runs pnpm install inside packages/app. pnpm resolves its workspace root to the nearest pnpm-workspace.yaml walking up from the cwd, and packages/app/pnpm-workspace.yaml existed (it carried two ignoredBuiltDependencies entries). That made packages/app its own workspace root, so the repo-root pnpm-lock.yaml was 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.102.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:

importX402Dependency("@x402/core/client", () => import("@x402/core/client"))

@x402/core, @x402/evm, @x402/svm, @x402/extensions are declared optional peer dependencies of cdp-sdk, so they are legitimately absent — but Turbopack statically analyses the dynamic import() 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.

Fix

Delete packages/app/pnpm-workspace.yaml and move its ignoredBuiltDependencies to the root pnpm-workspace.yaml.

pnpm now walks up from packages/app to the repo root, finds the workspace and pnpm-lock.yaml, and installs the pinned tree. Vercel sets CI=1, so pnpm additionally defaults to --frozen-lockfile. Production, CI, and local now resolve identically.

Why not the alternatives

  • Add the @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/svm and its Solana stack — into the EVM app to satisfy an import that only exists to be caught and rethrown. It also leaves the deploy resolving fresh semver, so the next upstream release breaks prod again.
  • Pin @coinbase/cdp-sdk via 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 build non-reproducible.

Restoring lockfile-driven installs is the actual root cause and is strictly the smaller change.

Verification

Reproduced and fixed against Vercel's real command sequence, not CI's:

cd packages/app && CI=1 pnpm install && ./node_modules/.bin/next build
  • Before: 8 × Module not found: Can't resolve '@x402/...', resolving @coinbase/cdp-sdk@1.54.0, store at packages/app/node_modules/.pnpm.
  • After: clean build, resolving @coinbase/cdp-sdk@1.45.0, store at the repo root. Routes /, /create, /vaults all compile.

No connector regression: the client chunks still contain walletConnect (11 files), injected (6), coinbaseWallet (5), metaMask (4), baseAccount (3), and RainbowKit. x402 appears in 0 client chunks — it was only ever reached through the SSR pass of @base-org/account's node entry.

Also green: tsc --noEmit, lint, test (115 app / 168 app-sol), and pnpm --filter app-sol build — the root pnpm-workspace.yaml change does not disturb the Solana app.

The Vercel preview deploy for this branch is green. The Vercel – ripguard check on this PR built and deployed successfully — the same pipeline whose last production run (ripguard-6pu8nnjtz, main) is still sitting in ERROR. All 6 PR checks pass: app, app-sol, Vercel – ripguard, Vercel – ripguard-sol, Vercel – ripguard-testnet, Vercel Preview Comments.

I did not view the rendered page in a browser: the preview URL is behind Vercel deployment protection and I did not authenticate through it. The claim here is a green build and deploy, not a visual check of the running app.

Follow-up (not in this PR)

packages/app-sol/pnpm-workspace.yaml still exists and carries the identical trap: sol.ripguard.xyz is also deploying from unpinned resolution and is one upstream release away from the same class of failure. It builds today, so I left it alone rather than touch a green deploy. Noted in AGENTS.md.

🤖 Generated with Claude Code

The ripguard (EVM) Vercel project has rootDirectory=packages/app and no
custom install command, so `pnpm install` runs inside packages/app. pnpm
resolves its workspace root to the nearest pnpm-workspace.yaml, which was
packages/app/pnpm-workspace.yaml -- 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 the build: 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.

Removing the nested workspace marker lets pnpm find the root workspace
and lockfile from packages/app, making the deploy reproducible and
identical to CI. The ignoredBuiltDependencies it carried moves to the
root pnpm-workspace.yaml.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
ripguard Ready Ready Preview, Comment Jul 27, 2026 4:02am
ripguard-sol Ready Ready Preview, Comment Jul 27, 2026 4:02am
ripguard-testnet Ready Ready Preview, Comment Jul 27, 2026 4:02am

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.

1 participant