Skip to content

Tree-shaking & bundle size

How to keep bundles small when consuming Cynosure.

Cynosure is authored to be as friendly to tree-shaking as a modern ESM library can be. Here’s how to get the smallest possible bundles.

// Smallest possible
import { Button } from '@arshad-shah/cynosure-react/button';
import { Input } from '@arshad-shah/cynosure-react/input';

Each component has its own tsup entry. The barrel (@arshad-shah/cynosure-react) also tree-shakes with modern bundlers, but per-component imports are a guarantee: no matter which bundler version you’re on, you only pull in the subpath you reach for.

Every per-component JS entry imports its own CSS at the top:

dist/button.js
import './core.css';
import './button.css';
export { Button } from './chunk-….js';

So import { Button } from '@arshad-shah/cynosure-react/button' pulls in exactly the rules Button needs. core.css carries the shared rules used by 2+ components (layout-prop cascade, typography base, focus ring, the @property registrations) — your bundler deduplicates it across any number of per-component imports.

Footprint at the consumer’s bundler:

  • Monolithic path: import '@arshad-shah/cynosure-react/styles.css' → 31 KB gzip for every Cynosure rule in the library.
  • One component only: ~20 KB gzip (core.css + that component’s rules, which are typically <1 KB on their own).
  • Many components: 20 KB + the per-component rules you actually use.

For a single bundled file (one <link> tag, no imports to wire up), @arshad-shah/cynosure-react/all.css ships tokens + components together (33 KB gzip).

Cynosure packages declare sideEffects: ["**/*.css"]. Bundlers drop any JS file whose only effect is its module graph, while keeping the CSS imports the components rely on.

pnpm size runs size-limit against every component in the library:

Terminal window
pnpm size

The root .size-limit.json defines per-component gzipped budgets. Open a PR that exceeds a budget → CI fails with a diff showing which component grew and by how much.

  • Vite: vite build --mode production + vite preview + DevTools Network panel.
  • Rollup visualiser: rollup-plugin-visualizer on your own build.
  • Next.js: @next/bundle-analyzer.

Cynosure’s peers (react, react-dom, react-aria-components, and the four remaining Radix menu packages — @radix-ui/react-{dropdown-menu,context-menu,menubar,navigation-menu}) must exist once in your graph. If you see duplicated copies, run pnpm why <pkg> and align the version via your package manager’s hoisting / catalog.