fix(deploy): resolve node_modules by walking up to monorepo root#121
Closed
harrisrobin wants to merge 4 commits intocloudflare:mainfrom
Closed
fix(deploy): resolve node_modules by walking up to monorepo root#121harrisrobin wants to merge 4 commits intocloudflare:mainfrom
harrisrobin wants to merge 4 commits intocloudflare:mainfrom
Conversation
detectPackageManager only checked for bun.lockb (the old binary lockfile), missing bun.lock — the text-based format introduced in Bun v1.0. It also only checked the immediate project directory, causing it to fall back to npm in monorepo setups where the lock file lives at the workspace root. Both issues together produce a confusing "npm error Invalid Version:" failure when running vinext deploy from a Bun monorepo workspace. Changes: - Add bun.lock check alongside the existing bun.lockb check - Walk up parent directories until a lock file is found (same behaviour as npm/pnpm/yarn when resolving workspace roots) - Apply the same two fixes to detectPackageManagerName - Add unit tests covering: pnpm, yarn, bun.lock, bun.lockb, npm fallback, monorepo root traversal, and closest-wins precedence
Node.js fs/promises.glob requires options.exclude to be a function. Passing an array throws TypeError on Node.js v23 and was never correct per the API spec (introduced in Node.js v22). PR cloudflare#52 migrated both routers from the glob npm package to the built-in but accidentally left array literals in the exclude option for both app-router.ts and pages-router.ts. Changes: - app-router.ts: `exclude: ["**/@*"]` → function that returns true when the entry's basename starts with "@" - pages-router.ts: `exclude: ["api", "**/_*"]` → function that returns true when the entry's basename is "api" or starts with "_" Behaviour is identical — parallel slot directories (@slot) and private pages (_app, _document, etc.) are still excluded from route scanning.
In monorepos, packages are hoisted to the workspace root's node_modules
rather than installed in each app's own node_modules. vinext was checking
for @cloudflare/vite-plugin, @vitejs/plugin-rsc, wrangler, and @mdx-js/rollup
only in the immediate {root}/node_modules, causing false negatives for all of
them and an ENOENT crash in runWranglerDeploy when the binary was only
present at the workspace root.
Changes:
- Add findInNodeModules(start, subPath) helper to utils/project.ts that
walks up parent directories until it finds node_modules/{subPath},
mirroring the same approach used for lock file detection
- Use it in detectProject for hasCloudflarePlugin, hasRscPlugin, hasWrangler
- Use it in getMissingDeps for hasMdxRollup
- Use it in runWranglerDeploy to locate the wrangler binary
Add unit tests covering: direct lookup, binary lookup, null fallback,
monorepo root traversal, and closest-wins precedence.
This was referenced Feb 26, 2026
Contributor
Author
harrisrobin
added a commit
to harrisrobin/vinext
that referenced
this pull request
Feb 26, 2026
…factored) Replaces the individual cloudflare#119 and cloudflare#121 fixes with the combined version from PR cloudflare#122. Introduces walkUpUntil<T> as a shared primitive, with detectPackageManager and findInNodeModules both built on top of it.
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.
Problem
vinext deployfails in monorepos with an ENOENT crash when the wrangler binary is hoisted to the workspace root rather than installed in the app's ownnode_modules:Three separate places hardcode
path.join(root, "node_modules", ...)and fail to find hoisted packages:detectProject—hasCloudflarePlugin,hasRscPlugin,hasWranglerall check the app-levelnode_modulesonly, producing false negatives for all three in a monorepo.getMissingDeps—hasMdxRolluphas the same issue.runWranglerDeploy— constructs the wrangler binary path from the app root, crashing with ENOENT when the binary is at the workspace root.The false negatives in (1) and (2) also cause vinext to try to re-install packages that are already present, adding unnecessary install steps.
Fix
Add
findInNodeModules(start, subPath)toutils/project.ts— it walks up parent directories until it findsnode_modules/{subPath}, returning the absolute path ornull. This mirrors the same approach already used for lock file detection indetectPackageManager.All four callsites are updated to use it:
Tests
5 new unit tests for
findInNodeModules:pnpm run typecheckandpnpm run lintpass clean./bonk