Skip to content

chore(core): remove deadweight dependencies#3368

Open
orrgottlieb wants to merge 1 commit into
masterfrom
chore/remove-deadweight-deps
Open

chore(core): remove deadweight dependencies#3368
orrgottlieb wants to merge 1 commit into
masterfrom
chore/remove-deadweight-deps

Conversation

@orrgottlieb

@orrgottlieb orrgottlieb commented May 21, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

Removes three dependencies from @vibe/core that core does not use directly:

Package Usage in core/src Action
react-inlinesvg ^4.1.3 0 imports Removed from `dependencies`. Mock target in `vitest.setup.ts` still resolves via `@vibe/icon`'s transitive dep.
style-inject ^0.3.0 0 imports Removed from `dependencies`.
react-is ^16.9.0 1 usage (`isForwardRef` in `MenuButton.tsx`) Removed from `dependencies`; replaced with a 3-line inline helper using `Symbol.for("react.forward_ref")`. Also drops `@types/react-is`.

yarn.lock is unchanged because these packages are still pulled in transitively where actually needed (e.g. @vibe/icon brings react-inlinesvg).

Why

From a performance audit (item #7): every dep declared in @vibe/core/package.json ships to consumers. Three of these are dead weight that we can drop without affecting runtime behavior.

Estimated bundle savings: ~25-38 KB gz combined for consumers that previously walked the dep graph through core.

Test plan

  • CI: @vibe/core builds (the inline isForwardRef matches react-is's implementation)
  • CI: @vibe/core tests pass (mock target for react-inlinesvg still resolves)
  • MenuButton continues to detect forwardRef components correctly

🤖 Generated with Claude Code


PR Type

Enhancement


Description

  • Remove three unused dependencies from @vibe/core package

  • Replace react-is with inline isForwardRef helper function

  • Reduce bundle size by ~25-38 KB gzip for downstream consumers

  • Dependencies still available transitively where needed


Diagram Walkthrough

flowchart LR
  A["@vibe/core dependencies"] -->|remove unused| B["react-inlinesvg"]
  A -->|remove unused| C["style-inject"]
  A -->|replace with inline| D["react-is"]
  D -->|inlined as| E["isForwardRef helper"]
  F["@vibe/icon"] -->|still provides| B
  G["MenuButton.tsx"] -->|uses| E
Loading

File Walkthrough

Relevant files
Dependencies
package.json
Remove three unused package dependencies                                 

packages/core/package.json

  • Removed react-inlinesvg from dependencies (unused in core source)
  • Removed react-is from dependencies (replaced with inline helper)
  • Removed style-inject from dependencies (unused in core source)
  • Removed @types/react-is from devDependencies
+1/-5     
Refactoring
MenuButton.tsx
Inline isForwardRef helper to replace react-is                     

packages/core/src/components/MenuButton/MenuButton.tsx

  • Removed import of isForwardRef from react-is
  • Added inline isForwardRef helper function using
    Symbol.for("react.forward_ref")
  • Helper checks if component's $$typeof matches React's forward ref
    symbol
  • Maintains identical functionality with 3-line implementation
+6/-1     

Removes three dependencies from `@vibe/core` that are not used directly
by core's source:

- `react-inlinesvg ^4.1.3` — 0 production imports in `packages/core/src/`.
  Only mocked in `vitest.setup.ts`; the mock target still resolves
  because `@vibe/icon` continues to depend on it.
- `style-inject ^0.3.0` — 0 imports anywhere in core source.
- `react-is ^16.9.0` — single usage (`isForwardRef`) in `MenuButton.tsx`,
  inlined as a 3-line helper using
  `Symbol.for("react.forward_ref")`. Also drops `@types/react-is`.

These three packages are still pulled in transitively where actually
needed, so `yarn.lock` does not change. The win is for downstream
consumers: dropping them from `@vibe/core`'s declared deps means a
consumer importing only Button/Avatar/etc. doesn't pay for them.

Estimated bundle savings: ~25-38 KB gz combined.

Audit finding #7.
@orrgottlieb orrgottlieb requested a review from a team as a code owner May 21, 2026 23:11
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0)

Grey Divider


Remediation recommended

1. Undeclared mocked dependency 🐞 Bug ☼ Reliability
Description
packages/core/vitest.setup.ts still references "react-inlinesvg" via vi.mock, but this PR removed it
from @vibe/core/package.json. This makes core tests depend on react-inlinesvg being available
transitively (currently via @vibe/icon) and can break if transitive deps/hoisting change or if
@vibe/icon drops the dependency.
Code

packages/core/package.json[115]

Evidence
The core test setup still mocks react-inlinesvg, while core no longer declares it in its
dependency lists; this creates a direct reference without a direct dependency contract.

packages/core/vitest.setup.ts[17-25]
packages/core/package.json[91-119]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`@vibe/core` test setup mocks `react-inlinesvg` (a direct module reference), but `react-inlinesvg` was removed from `@vibe/core`'s declared dependencies.

Even if it currently resolves via `@vibe/icon` transitively, this is fragile for the `@vibe/core` workspace/tests because it depends on transitive availability rather than explicit declaration.

## Issue Context
- `vitest.setup.ts` runs for every core test run and contains `vi.mock("react-inlinesvg", ...)`.
- After this PR, `react-inlinesvg` is no longer listed in `@vibe/core/package.json`.

## Fix
Add `react-inlinesvg` to `@vibe/core` **devDependencies** (not dependencies) so tests have an explicit contract without increasing runtime deps shipped to consumers.

## Fix Focus Areas
- packages/core/package.json[91-140]
- packages/core/vitest.setup.ts[17-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@github-actions

Copy link
Copy Markdown
Contributor

📦 Bundle Size Analysis

✅ No bundle size changes detected.

Unchanged Components
Component Base PR Diff
@vibe/button 17.3KB 17.29KB -9B 🟢
@vibe/clickable 5.95KB 5.96KB +3B 🔺
@vibe/dialog 52.14KB 52.16KB +14B 🔺
@vibe/icon-button 66.09KB 66.1KB +13B 🔺
@vibe/icon 12.92KB 12.89KB -32B 🟢
@vibe/layer 2.96KB 2.96KB 0B ➖
@vibe/layout 9.82KB 9.83KB +11B 🔺
@vibe/loader 5.64KB 5.65KB +10B 🔺
@vibe/tooltip 61.33KB 61.32KB -7B 🟢
@vibe/typography 63.47KB 63.43KB -47B 🟢
Accordion 6.31KB 6.29KB -14B 🟢
AccordionItem 66.43KB 66.39KB -47B 🟢
AlertBanner 70.83KB 70.9KB +71B 🔺
AlertBannerButton 18.76KB 18.76KB -2B 🟢
AlertBannerLink 15.26KB 15.26KB +4B 🔺
AlertBannerText 63.95KB 63.91KB -38B 🟢
AttentionBox 74.35KB 74.29KB -61B 🟢
Avatar 66.84KB 66.72KB -119B 🟢
AvatarGroup 93.29KB 92.87KB -424B 🟢
Badge 43.19KB 43.17KB -24B 🟢
BreadcrumbItem 64.7KB 64.64KB -61B 🟢
BreadcrumbMenu 68.57KB 68.09KB -495B 🟢
BreadcrumbMenuItem 77.07KB 77KB -69B 🟢
BreadcrumbsBar 5.68KB 5.68KB -1B 🟢
ButtonGroup 68.32KB 68.3KB -17B 🟢
Checkbox 66.83KB 66.92KB +99B 🔺
Chips 75.05KB 75.01KB -36B 🟢
ColorPicker 74.47KB 74.45KB -26B 🟢
ColorPickerContent 73.73KB 73.7KB -28B 🟢
Combobox 84.08KB 84.03KB -50B 🟢
Counter 42.21KB 42.28KB +65B 🔺
DatePicker 112.41KB 112.49KB +82B 🔺
Divider 5.42KB 5.46KB +44B 🔺
Dropdown 95.35KB 95.26KB -97B 🟢
EditableHeading 66.63KB 66.53KB -104B 🟢
EditableText 66.46KB 66.42KB -38B 🟢
EmptyState 70.48KB 70.39KB -97B 🟢
ExpandCollapse 66.22KB 66.19KB -32B 🟢
FormattedNumber 5.86KB 5.84KB -13B 🟢
GridKeyboardNavigationContext 4.65KB 4.65KB -4B 🟢
HiddenText 5.4KB 5.39KB -15B 🟢
Info 72.06KB 72.06KB +3B 🔺
Label 68.65KB 68.67KB +21B 🔺
Link 14.91KB 14.88KB -30B 🟢
List 72.88KB 72.84KB -43B 🟢
ListItem 65.54KB 65.49KB -59B 🟢
ListItemAvatar 66.88KB 66.92KB +40B 🔺
ListItemIcon 13.97KB 13.97KB +5B 🔺
ListTitle 65.02KB 64.95KB -69B 🟢
Menu 8.65KB 8.64KB -19B 🟢
MenuDivider 5.56KB 5.57KB +7B 🔺
MenuGridItem 7.16KB 7.19KB +36B 🔺
MenuItem 76.95KB 77.06KB +105B 🔺
MenuItemButton 70.11KB 70.06KB -55B 🟢
MenuTitle 65.35KB 65.34KB -11B 🟢
MenuButton 66.08KB 65.61KB -482B 🟢
Modal 79.14KB 79.06KB -84B 🟢
ModalContent 4.72KB 4.71KB -1B 🟢
ModalHeader 65.79KB 65.77KB -19B 🟢
ModalMedia 7.51KB 7.5KB -3B 🟢
ModalFooter 67.72KB 67.68KB -35B 🟢
ModalFooterWizard 68.6KB 68.56KB -40B 🟢
ModalBasicLayout 8.96KB 8.9KB -57B 🟢
ModalMediaLayout 8.08KB 8.06KB -19B 🟢
ModalSideBySideLayout 6.3KB 6.29KB -4B 🟢
MultiStepIndicator 52.96KB 52.95KB -11B 🟢
NumberField 72.87KB 72.87KB -6B 🟢
ProgressBar 7.34KB 7.35KB +7B 🔺
RadioButton 65.9KB 65.9KB +3B 🔺
Search 70.65KB 70.61KB -46B 🟢
Skeleton 6KB 6.01KB +4B 🔺
Slider 73.86KB 73.84KB -19B 🟢
SplitButton 66.48KB 66.52KB +46B 🔺
SplitButtonMenu 8.8KB 8.76KB -34B 🟢
Steps 71.31KB 71.36KB +57B 🔺
Table 7.26KB 7.25KB -13B 🟢
TableBody 66.68KB 66.69KB +11B 🔺
TableCell 65.22KB 65.26KB +36B 🔺
TableContainer 5.31KB 5.32KB +16B 🔺
TableHeader 5.64KB 5.64KB +1B 🔺
TableHeaderCell 72.2KB 72.15KB -43B 🟢
TableRow 5.56KB 5.55KB -8B 🟢
TableRowMenu 68.87KB 68.35KB -534B 🟢
TableVirtualizedBody 71.42KB 71.38KB -39B 🟢
Tab 64KB 63.93KB -73B 🟢
TabList 8.89KB 8.86KB -30B 🟢
TabPanel 5.3KB 5.29KB -14B 🟢
TabPanels 5.86KB 5.86KB -2B 🟢
TabsContext 5.48KB 5.51KB +29B 🔺
TextArea 66.26KB 66.25KB -3B 🟢
TextField 69.43KB 69.43KB -2B 🟢
TextWithHighlight 64.35KB 64.3KB -48B 🟢
ThemeProvider 4.36KB 4.36KB -1B 🟢
Tipseen 71.17KB 71.15KB -21B 🟢
TipseenContent 71.6KB 71.6KB -2B 🟢
TipseenMedia 71.27KB 71.3KB +26B 🔺
TipseenWizard 73.93KB 73.8KB -137B 🟢
Toast 74.1KB 73.94KB -168B 🟢
ToastButton 18.59KB 18.62KB +33B 🔺
ToastLink 15.05KB 15.08KB +31B 🔺
Toggle 66.62KB 66.59KB -27B 🟢
TransitionView 5.42KB 5.45KB +30B 🔺
VirtualizedGrid 12.54KB 12.54KB +2B 🔺
VirtualizedList 12.28KB 12.26KB -12B 🟢
List (Next) 8.17KB 8.16KB -15B 🟢
ListItem (Next) 69.88KB 69.82KB -62B 🟢
ListTitle (Next) 65.31KB 65.29KB -21B 🟢

📊 Summary:

  • Total Base Size: 4.75MB
  • Total PR Size: 4.75MB
  • Total Difference: 3.38KB

const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
const isForwardRef = (component: unknown): boolean =>
component != null && (component as { $$typeof?: symbol }).$$typeof === REACT_FORWARD_REF_TYPE;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems a bit risky. We're saving ~1.5 KB gz but coupling to an undocumented React internal (Symbol.for("react.forward_ref")). If React changes this in a future major version, the inline helper silently breaks with no build-time error. I'd keep react-is and just remove the other two deps - that's still the majority of the savings with none of the risk.

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