fix(build): break the vendor <-> vendor-react chunk cycle - #45
Open
a-effort wants to merge 2 commits into
Open
Conversation
manualChunks matched packages by bare substring, so /react-dom/ also caught @floating-ui/react-dom and swept it into vendor-react, which then imported @floating-ui/dom back out of vendor. Rollup reported the result as "Circular chunk: vendor -> vendor-react -> vendor", one warning among the chunk-size advice it prints on every build. A cycle leaves rollup to pick an execution order, and the losing side evaluates against a namespace object that does not exist yet. When that order flips, the app dies at module-eval with "Cannot set properties of undefined (setting 'Activity')" — Activity being a React 19 export — and serves a blank page with no other console output. Nothing about the message points at bundling, so it reads like a React or auth fault. Anchor the match to the package root so only the real react packages land in vendor-react, and hold that chunk to react, react-dom, scheduler and react-is. A leaf chunk imports nothing from its siblings and so cannot be one end of a cycle, whatever else moves between chunks later. react-intl, @formatjs, sonner and the react-remove-scroll family move to vendor, alongside the helpers they already import from there. This was latent rather than new: rollup happened to pick a working order for as long as chunk composition held still. Any unrelated change that shifts it can flip the order, so the failure surfaces attached to whichever commit disturbed the bundle rather than to this one. Signed-off-by: Anna Effort <anna.effort@ibm.com>
The header profile trigger rendered an empty rounded square, since no
avatar data exists to put in it. Fill it with a lucide UserRound behind
an Avatar primitive, so the frame that already reserved the space reads
as a person rather than a gap.
Colors come from the muted / muted-foreground tokens, which index.css
redefines under .dark, so light and dark need no conditional logic here
and no dark: variants. A test asserts the fallback carries no dark:
prefix, to keep a future hardcoded override from creeping back in.
UserAvatar owns the fallback ladder rather than HeaderProfileMenu
inlining an icon, and takes an optional src. The API exposes no avatar
field today, so that leg is unused — but Radix Avatar is what handles
the image load/error swap, which is the part that gets ugly to retrofit
once profile pictures land. The primitive comes from the radix-ui
umbrella package, already a dependency, so this adds none.
Sizing stays size-6 rounded-md with overflow-hidden: an image later
fills the same box and the header geometry does not move. The trigger
button already carries aria-label={displayName}, so the icon is
decorative and adds no second accessible name and no new i18n strings.
Signed-off-by: Anna Effort <anna.effort@ibm.com>
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.
What
manualChunksinvite.config.tsmatched packages by bare substring, soid.includes("/react-dom/")also caught@floating-ui/react-domand swept it intovendor-react— which then imported@floating-ui/domback out ofvendor.That makes the two chunks circular. Rollup has said so on every build for a while, buried among the chunk-size advice:
Why it matters
A cycle leaves rollup to pick an execution order, and the losing side evaluates against a namespace object that doesn't exist yet. When that order flips, the app dies at module-eval and serves a blank page whose only console output is:
Activityis a React 19 export, so nothing in that message points at bundling — it reads like a React or auth fault. This is how it was found: an unrelated one-component change shifted chunk composition, flipped the order, and took the whole app down.The cycle is latent, not new. Any change that disturbs the bundle can flip it, so the failure attaches to whichever commit happened to disturb it rather than to the real cause.
The fix
Anchor the match to the package root so only the real react packages land in
vendor-react, and hold that chunk toreact,react-dom,scheduler,react-is. A leaf chunk imports nothing from its siblings, so it can't be one end of a cycle no matter what moves between chunks later.react-intl,@formatjs,sonnerand thereact-remove-scrollfamily move tovendor, alongside helpers they already import from there.Verification
Because no CI job builds (see below), I verified the actual failure by loading the built entry chunk under jsdom and catching module-eval throws — it reproduces the browser error exactly. Before:
FAIL … setting 'Activity'. After:PASS.No workflow runs
npm run build:client-lint-testgenerate,format:check,lint,test:coverageclient-generategenerate,tsc -b --noEmitclient-e2enpm run dev:e2e— the Vite dev servermanualChunksis a rollup build-only option, so the dev server never applies it and E2E can't see this class of bug. A PR that reintroduces the cycle goes green on every check.Adding
npm run buildtoclient-lint-testwould have caught this in seconds. Filing that separately rather than bundling it here.Related
Blocks the avatar PR, which trips this cycle and cannot merge before this lands.