Skip to content

fix(react): serve a workspace-linked void as source in dev - #720

Merged
cpojer merged 1 commit into
voidzero-dev:mainfrom
yangshun:fix/react-linked-void-optimize-deps
Nov 5, 2026
Merged

cpojer merged 1 commit into
voidzero-dev:mainfrom
yangshun:fix/react-linked-void-optimize-deps

Conversation

@yangshun

@yangshun yangshun commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

What changed

Locally, React Pages apps in this repo could stop hydrating after vp run build. The browser threw:

SyntaxError: The requested module '/node_modules/.vite/deps/void_pages-client.js?v=…'
does not provide an export named 'isVoidActionError'

The client entry never loaded, so #app was never marked hydrated. websockets-playground.test.ts timed out on /chat and /notifications (noted in #719). CI passed because it starts with no Vite cache.

Cause

In dev, the React adapter listed void/pages-client and void/pages-prefetch in the client optimizeDeps.include (#620). It listed void/live/client in the worker include. Here void is a linked workspace package. Vite serves a linked package as source unless it is listed in include, and a listed one is pre-bundled into node_modules/.vite. That cache is keyed by the lockfile, config and NODE_ENV, not by the linked package's files, so rebuilding Void left the old copy in place.

#715 added isVoidActionError to void/pages-client and re-exported it from @void/react. Any cache written before #715 then broke the client.

Fix

installedDependencies() keeps a Void entry in include only when it resolves into node_modules:

void install Before After
From the registry (node_modules) pre-bundled pre-bundled (keeps #620's cold-start fix)
Linked workspace package pre-bundled, stale after a rebuild served as source, always the current build

This only changes dev behavior for linked installs. Apps that install void from npm see no difference.

For reviewers

  • Served as source: in a linked install, these entries pull in only @void/edge, which is linked too and has no imports. Serving them as source therefore can't trigger a late dependency discovery or a full reload.
  • void/live/client: the worker include had the same stale-copy hazard, so the same rule applies there.
  • Resolution: import.meta.resolve from @void/react. void is a peer dependency, so this finds the same void the app uses.

Verification

  • Replayed the failure: built void at feat(pages): export isVoidActionError() to recognize action errors at every status #715's parent and ran the websockets suite to fill the cache. Then I rebuilt on this branch and ran it again. Before this change: 2 failed. After: 3/3 passed on two runs.
  • packages/react/test/unit/plugin-pages.test.ts: 34 passed. A new unit test covers installed paths (pnpm, npm, Windows) and a linked path. The dev-config test now checks that this workspace's linked void is not pre-bundled.
  • vp run check, lint and format are clean.
  • Full vp test run: 774 of 777 files passed (1 skipped). The other 2 files were the Vue and Svelte *-pages-client preview suites. They reuse an existing playground dist, and this worktree's predated their newest fixtures. After deleting those dist folders, both passed (94 tests).

To clear a stale cache without this change:

rm -rf playground/<app>/node_modules/.vite

🤖 Generated with Claude Code

React Pages dev listed void/pages-client and void/pages-prefetch (and
void/live/client for the worker) in optimizeDeps.include. For a linked
void, as in this workspace, that makes Vite pre-bundle a copy of
packages/void/dist into node_modules/.vite. Vite keys that cache by the
lockfile and config, not by the linked files, so rebuilding void leaves
the old copy in place.

After voidzero-dev#715 added isVoidActionError to void/pages-client and re-exported
it from @void/react, a cache built before voidzero-dev#715 broke every page:

    SyntaxError: The requested module
    '/node_modules/.vite/deps/void_pages-client.js?v=…' does not provide
    an export named 'isVoidActionError'

The client entry never loads, so #app is never marked hydrated. The
websockets playground suite timed out on /chat and /notifications
locally while CI, which starts with no cache, passed.

Include Void's own entries only when they resolve into node_modules. An
installed void is still pre-bundled up front, which keeps the voidzero-dev#620
cold-start fix. A linked void is served as source, as Vite does for
linked packages, so dev always uses the current build.

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

@cpojer cpojer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. I feel like all of this is a huge mess tbh and it keeps breaking. I don't know why this has to be so complex with Vite. There must be a much simpler way?

@cpojer
cpojer merged commit 7eb2144 into voidzero-dev:main Nov 5, 2026
17 checks passed
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