fix(react-call): Fast Refresh accepts Callables in the published bundle#111
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
2fd0cb9 to
2b889e6
Compare
The minified bundle renamed the returned component function to a lowercase identifier, failing react-refresh's isLikelyComponentType name check. The truthy minified `name` also shadowed `displayName`, so neither a manual displayName nor the react-call/vite plugin could work around it — editing a Callable's own source closed any open call via a full reload. createCallable now pins an uppercase `name` on the Callable (dev-only; production output is byte-for-byte unchanged). A guard test in the dist vitest project asserts the built artifact passes isLikelyComponentType; a source-level test cannot, since source keeps the `Root` name. That test loads the built dist through a runtime dynamic import (typed against the source barrel) so it type-checks without the build present. Refs ADR-0022. Closes #110.
2b889e6 to
46a7013
Compare
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.
Summary
Editing a Callable's own source while a call is open closed the open call (the dialog disappeared) and Vite logged
Could not Fast Refresh ("X" export is incompatible)— for real consumers, even withdisplayNameset or thereact-call/viteplugin enabled. Closes #110.Root cause
React Fast Refresh decides component-ness via react-refresh's
isLikelyComponentType, which for a function gates on/^[A-Z]/.test(fn.name || fn.displayName).ADR-0009 made the Callable a function (
RootviaObject.assign) to clear that bar — but the bar is on the runtime name, and the library's own build minifiesfunction Rootto a lowercase identifier (p). So the export react-refresh sees hasname === "p", fails the regex, and the boundary is rejected → full reload → the open call resets.This is also why
displayNamenever helped:fn.name || fn.displayNameshort-circuits on the truthy minifiedfn.namebeforedisplayNameis read. And why it slipped through CI for a whole release line: every playground aliasesreact-callto source (ADR-0005), whereRootkeeps its uppercase name and Fast Refresh accepts. The bug only exists in the minified artifact consumers install.Fix
createCallablepins an uppercasenameon the returned Callable inside the existing dev-only block:Dev-only, so production output is byte-for-byte unchanged (DCE, per ADR-0011;
size-limitmain.jsstays 810 B). Decision recorded in ADR-0022; ADR-0009 gets a header note correcting its framing (the function shape is necessary but not sufficient for the published artifact).After the fix, Fast Refresh acceptance is unconditional and the
displayName/registry layer (ADR-0010/0011/0012) is purely about HMR state persistence — orthogonal concerns.Testing
distvitest project (fast-refresh-compat.test.ts): imports the builtdist/main.jsand asserts a verbatim copy ofisLikelyComponentTypeaccepts the Callable. 🔴 against the old dist (name === "p"), 🟢 after the fix. A source-level test cannot catch this — which is exactly the blind spot that let issue Hot Reload Issues #31's original fix regress.@vitejs/plugin-react6 — noincompatiblewarning, dialog survives edits, JSX hot-updates in place.pnpm lint,check:types, unit (137) and dist (7) suites all green.