Repository navigation
fix(router): resolve the plugin-rsc static.edge vendor entry through @rangojs/router under pnpm - #1051
Merged
Conversation
…@rangojs/router under pnpm
commit: |
This was referenced Oct 4, 2026
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.
Closes #1050
Problem
A project that installs only
@rangojs/router,react,react-domandvite(the README's promise) printed this on everypnpm devwith pnpm's strictnode_modules, in all three templates (cloudflare,basic,vercel):The app still served (
GET /200).@vitejs/plugin-rscadds five@vitejs/plugin-rsc/vendor/react-server-dom/*entries to the environments'optimizeDeps.include; Vite resolves them from the project root, where pnpm does not link plugin-rsc.rango()already redirected four of them throughresolve.alias(absolute paths resolved from this package), but missedstatic.edge, which only the rsc environment includes.Before vs. after
Consumer
package.json(unchanged in both):pnpm devoutputFailed to resolve dependency: @vitejs/plugin-rsc/vendor/react-server-dom/static.edge ...static.edgenot pre-bundledstatic.edgepre-bundled indeps_rsc/_metadataEnd-to-end consumer example
Scaffold with
pnpm create rango@latest my-app --template cloudflare --package-manager pnpm,pnpm install,pnpm dev. Before: warning above. After (router tarball built from this branch installed in place of 0.20.0, app still not listing@vitejs/plugin-rsc): no warning,/answers 200,pnpm buildpasses.Semantics
Entries in each environment's
optimizeDeps.includethat start with@vitejs/plugin-rsc/(scaffolded cloudflare app, 0.20.0), and whether each resolves from the project root under pnpm:node_modules.../vendor/.../client.browser.../vendor/.../client.edge.../vendor/.../server.edge.../vendor/.../client.edge.../vendor/.../static.edgereact,react-dom,react/jsx-*,react-dom/{client,server.edge,static.edge}resolve from the root (the app lists react/react-dom). The@rangojs/router > ...nested entries (rsc-html-stream, plugin-rsc client.edge/server.edge) resolve through the router and do not warn.An app that lists
@vitejs/plugin-rscitself: the alias target resolves to the same file the root's copy resolves to when the versions agree (pinned by a unit test with a symlinked root install). Same behavior as the four existing entries; with a different plugin-rsc version in the root, the router's copy wins for these entries, as before.Code change
packages/rangojs-router/src/vite/utils/package-resolution.ts: one line added to thespecslist ingetVendorAliases().rango.tsmerges those aliases intoresolve.aliasfor both presets (rango.ts:151, used at:211cloudflare and:432node).Why alias and not a per-root
createRequirecheck or theA > Bnested form: the alias is already the mechanism for the other four entries, it covers every environment and both presets at once, and it needs no root-dependent branch. The nested form would add a second optimizer entry for the same file (the existing nested client.edge/server.edge entries already do, visible as duplicate keys indeps_ssr/deps_rsc_metadata.json; left as is here).Test plan
src/vite/__tests__/optimize-deps-vendor-resolution.test.ts(new): resolves the realrango()config (node and cloudflare presets) and asserts every@vitejs/plugin-rsc/include entry of client/ssr/rsc has an alias to an existing file when the root has no plugin-rsc, and that the alias target equals the root's own resolution when plugin-rsc is installed there. Red on origin/main (4 failures), e.g.AssertionError: node/rsc: no alias for @vitejs/plugin-rsc/vendor/react-server-dom/static.edge: expected undefined to be truthyatoptimize-deps-vendor-resolution.test.ts:90; green with the change.package-resolution.test.ts:getVendorAliases()hasstatic.edge.pnpm pack, scaffolded cloudflare app under pnpm, dev: no warning,/200;pnpm buildpasses.node_modules), published 0.20.0: no warning (plugin-rsc is hoisted to the root).test:unit:all, lint, format,check:e2e-bucketing,check:e2e-parity --strict,check:docs-api.test:hmr-routes-localequivalent: 20 passed, 1 flaky (an invalid transition({ when }) edit prints the error and shows the Vite overlay, passed on retry).hook-render-stabilityin packages/rangojs-router (8 passed) and tests/cloudflare-basic (4 passed).Notes
static.edge(router sources usereact-dom/static.edge), so the only effect was that module missing from the rsc pre-bundle. I did not construct a case where an app imports it unoptimized.packages/rangojs-router/package.jsonlists@vitejs/plugin-rsc^0.5.35underdependenciesand underpeerDependencies, not inpeerDependenciesMeta, so it is a required peer. The README (README.md:61: "rango()includes@vitejs/plugin-rsc") and the install commands (READMEnpm install @rangojs/router@latest react react-dom/npm install -D vite;skills/cloudflare/SKILL.md:21-22;skills/migrate-nextjs/SKILL.md:118-119) do not install it; after this fix they agree with behavior. The declaration is what disagrees with the docs. Recommendation for the maintainer: drop it frompeerDependenciesand keep it as a dependency. As a peer it signals "install this yourself" and makes npm auto-install it at the root, which is why npm never showed the warning, while the README says the opposite. Not changed here.@vitejs/plugin-rscwins over an app's own copy at another version. That was already true for the other four; the helper's doc comment now says it.exportsdoes not work (it exports one./*wildcard, and its vendor directory holds files the plugin never includes). Applied: the doc comment ongetVendorAliases. Skipped: a sharedresolveRangoConfigtest helper (the same few lines exist in two sibling tests; out of scope here).telemetry.test.ts("safeEmit with no-op sink performs no work", a 50 ms budget for 10k calls) took 51.5 ms while the machine had a load average of 17; alone it passes, and this change does not touch telemetry.