-
Notifications
You must be signed in to change notification settings - Fork 0
Review 4310
#4310 fix(core): lazy-load usePopover in SideNavHeading (#264) by jibin7jose (bucket: contributor)
3b5ce5f839541715340a4ec8fbd891581f0dec67
LOOP VERSION: 1.6.0 AUDIT RUBRIC: 1.13
LANE: full WHY: promoted immediately — aged community fork PR, refreshed merge conflict, interactive runtime change, and bundle behavior needs more than one decisive check.
WHY 1: The author wants a static SideNav heading to avoid loading the popover/layer code when there is no menu. WHY 2: That hurts builders because pages using a simple heading pay for interaction code they did not use. WHY 3: SideNav is app chrome; its baseline bundle cost is paid on app entry, before users do anything. USER-FACING PROBLEM: A person opening an app with a plain SideNav can wait on menu/layer code even though that navigation header has no menu. PROBLEM SEVERITY: harmful friction — extra app-entry code cost, not a broken task.
VERDICT: clear
The heading now chooses between a simple renderer and a menu renderer. The menu renderer is put behind a lazy boundary so it should only load when the caller passes menu content. Shared styles move to a separate style file so both renderers can keep the same appearance without importing the menu behavior.
SOLUTION (2 decisions · ~800 moved/runtime lines of 1,815 changed lines)
- Put the menu-capable SideNavHeading renderer behind
React.lazywhenmenuis present — serves the stated bundle problem. - Split shared static rendering/styles into separate files — supports decision 1.
BURDEN: medium — no public API change and no new effects, but this changes runtime loading and the test story for every menu path. BURDEN MATCH: proportionate — lazy-loading is the intended fix for bundle cost, but it has to preserve both tests and the static dependency graph.
VERDICT: BLOCKS — the implementation drops menu behavior in the Suspense fallback and still loads Layer through Tooltip on the static path.
OWNER: SideNavHeading owns the split between static heading and menu heading.
TIER 1: Layer/Popover/Tooltip must stay out of the static path unless the rendered state actually needs them.
TIER 2: none.
SEAMS: no-menu heading, heading link, menu trigger, collapsed icon tooltip, collapsed menu trigger.
BEHAVIOR UNIT: inline split — the behavior boundary is testable by rendering with and without menu and by inspecting the module graph.
| seam | driven result |
|---|---|
| static no-menu story | real Chromium loads the story, but module graph still includes Tooltip/Layer through the static renderer |
| menu story | real Chromium eventually renders Open menu, but focused jsdom tests initially see the fallback without a menu trigger |
| collapsed tooltip | still uses Tooltip, which is a valid behavior need only for collapsed mode |
The split lives in the right component, but the static renderer imports Tooltip at module top. Because Tooltip imports useTooltip, and useTooltip imports useLayer, the static import chain still pulls the layer system before a caller asks for a menu.
VERDICT: BLOCKS — the static path still owns a layer dependency.
The change reaches every builder who renders SideNavHeading; no API changes, but the bundle promise is the whole point of the PR. At this head, a simple heading still pulls Layer/useLayer.tsx through SideNavHeadingStatic → Tooltip, so the user-facing bundle problem is not actually removed. Menu users also inherit a failing test path where the lazy fallback renders the static heading without the menu trigger.
VERDICT: BLOCKS — stated benefit is not delivered and menu behavior is not test-stable.
No API change.
| change | public? | class | doc'd? | verdict | |
|---|---|---|---|---|---|
| — | no prop/export/type/default changed | — | — | — | ok |
OSSIFICATION: no new public surface.
VERDICT: clear
The PR moves the existing SideNavHeading styles into SideNavHeading.stylex.ts; it does not add or rename theme targets. Token usage is copied from current main; the existing side-nav-heading target still lands on the root in both split files.
VERDICT: clear
BEHAVIOR: yes — the menu path suspends to <SideNavHeadingStatic {...rest} />, which strips menu and renders no trigger until the lazy component resolves; the focused SideNav test file fails 10 menu/collapsed-menu tests on exact head.
API: no — no exported signatures changed.
VISUAL: no intended visual change; real Chromium shows the menu story can eventually render an Open menu trigger, so the block is behavior/test, not a visual regression claim.
THEME: no — target name and token values copied from current main.
VERDICT: BLOCKS — existing menu tests fail because the fallback is behaviorally static.
EFFECTS: zero added/changed Effects in the diff; existing popover/tooltip effects moved with their modules.
| Effect + deps | external system | why render/handler cannot do it | measured render cost | lifetime + cleanup | focused test |
|---|---|---|---|---|---|
| none added/changed | — | — | — | — | — |
RENDER: not measured beyond focused test behavior.
LISTENERS/OBSERVERS: no new listener/observer code added by the split.
LAYOUT: no new geometry rule; copied styles only.
BUNDLE: esbuild split check importing SideNavHeading still puts Layer/useLayer.tsx, Tooltip.tsx, and useTooltip.tsx in statically imported shared chunks before the lazy SideNavHeadingWithMenu chunk.
VERDICT: BLOCKS — the static import graph still includes the layer stack.
VISUAL CHECK: manual frames not required
WHY: no visual finding is being made; the review blocks on exact-head focused tests and module graph. I still ran exact-head Storybook on port 64310 and drove Chromium against core-sidenav--default and core-sidenav--with-header-menu; the browser observed Open menu after the lazy load, while the default story also requested layer modules.
VERDICT: clear
REMEDY SEARCH: not triggered — no proven visual defect
Existing a11y semantics for the menu path are covered by SideNav tests, and those tests currently fail before they can assert the menu trigger/popover semantics. No new catalog keys or strings are introduced by the PR.
VERDICT: BLOCKS — exact-head SideNav a11y/interaction tests fail before menu semantics are reachable.
| slot | verdict |
|---|---|
| PROBLEM | clear |
| SOLUTION | BLOCKS — fallback and static dependency graph miss the stated behavior |
| ARCHITECTURE | BLOCKS — static path still owns a layer dependency |
| IMPACT | BLOCKS — stated bundle benefit is not delivered |
| API | clear |
| THEMING | clear |
| BREAKING | BLOCKS — exact-head focused tests fail |
| PERFORMANCE | BLOCKS — static import graph still includes Layer |
| VISUAL | clear |
| A11Y & I18N | BLOCKS — menu tests fail before semantics are reachable |
GOAL: not met — vitest run packages/core/src/SideNav/SideNav.test.tsx fails 10 tests, and esbuild shows Layer/useLayer.tsx in a statically imported chunk for an entry that imports only SideNavHeading.
DISPOSITION: failing menu tests → blocks now; static Tooltip/Layer import → blocks now.
ADVICE: bounded outcome criteria — menu tests should pass at exact head, and an entry importing SideNavHeading without rendering a menu should not statically import Tooltip/Layer.
AUTHOR CAN PROCEED: yes — fix the fallback/test story and lazy-load the collapsed tooltip/layer path as well.
WORST OUTCOME: “A person opening an app with a plain SideNav can wait on menu/layer code even though that navigation header has no menu.” → request changes.
JUDGEMENT NEEDED: none — defect fix against the existing lazy-loading goal.
request changes
-
[BLOCKS] The lazy fallback strips the menu path → menu users have no trigger in the first render path, and the exact-head SideNav suite now fails 10 menu/collapsed-menu tests · packages/core/src/SideNav/SideNavHeading.tsx:87
-
[BLOCKS] The static renderer still imports Tooltip at module load → a plain no-menu SideNavHeading still pulls
useTooltip/useLayer, so #264's bundle goal is not met · packages/core/src/SideNav/SideNavHeadingStatic.tsx:6
Thanks for refreshing this. I don't think it's ready yet: the menu path currently suspends to the static heading, so the SideNav tests render no trigger and 10 menu cases fail. The static path also still imports Tooltip, which pulls useLayer, so the no-menu bundle goal is not met yet. Can you make the fallback/test path preserve the menu affordance and keep Tooltip/Layer out of the static branch too? If you'd rather talk it through with someone, we're in Discord.
- packages/core/src/SideNav/SideNavHeading.tsx:87 — This fallback drops the menu trigger; the existing menu tests see only the static heading.
- packages/core/src/SideNav/SideNavHeadingStatic.tsx:6 — This still pulls Tooltip/useLayer into the no-menu path.
- CI workflows for the fork head are still action_required, so GitHub has not run the full suite yet.
- Real Chromium on Storybook port 64310 eventually finds
Open menuincore-sidenav--with-header-menu, so the user-facing menu is not permanently absent after the lazy chunk loads. - The Vercel check is failing, but I did not inspect it because the local focused failures are already blocking.
TIME total 10m setup/rules 1m kit, public wiki rules, versions, safety preflight install/build/server 3m warm main reused: yes; fast-install seed; @astryxdesign/build; Storybook :64310 browser/a11y 2m Chromium probes for default/menu SideNav stories focused tests 1m SideNav.test.tsx exact-head run (10 failed, 184 passed) code/history 3m issue #264, diff, import graph, line anchors, prior reviews critique/wiki 1m presentation, self-critic, wiki record prep CI wait 0m checked status only; workflows action_required waste 2m bad gh/vitest flags and one screenshot click blocked by hover-open popover
- I did not run a production package build or inspect Vercel logs; local focused tests and module graph already found blocking failures.
Not posted — read-only review task.