Skip to main content

Lesson 8: Performance

Benchmarks, bundle size comparisons, and optimization strategies.

Bundle size

We replaced react-day-picker with @gentleduck/calendar. Comparison against the major React calendar libraries:

Bundle size across all competitors

LibraryBundle (gzipped)Improvement
@gentleduck/calendar4.9 KBWinner
react-calendar15.0 KB3.1x larger
react-day-picker v920.0 KB4.1x larger
react-datepicker32.0 KB6.5x larger
react-aria DatePicker45.0 KB9.2x larger

Dependencies

LibraryRuntime Dependencies
@gentleduck/calendar0
react-calendar0
react-day-picker1 (date-fns)
react-datepicker3
react-aria8

Render performance

Core function benchmarks (average of 2000 iterations):

OperationTime
buildCalendarMonth~8 us
buildMultiMonth(3)~22 us
buildMultiMonth(12)~78 us
applySelection~11 us

Generate benchmarks locally:

cd packages/duck-calendar && bun run benchmark

Package quality

ToolResult
publintAll good
attw (are-the-types-wrong)Types correct for node10, node16, bundler
ESMPure ESM, "type": "module"

Optimizations

These are the changes that took the core bundle from 7.0 KB down to 4.9 KB gzipped (75% smaller than react-day-picker):

  • Intl.DateTimeFormat caching: formatters cached per locale+options, avoiding expensive re-instantiation.
  • Stable keyboard callback: configRef pattern, zero recreation cost.
  • Pre-computed time field orders: 4 static arrays replace Array.filter() on every keystroke.
  • Frozen selection constants: one UNSELECTED object shared across unselected days.
  • Dev JSX elimination: production build uses createElement directly, no jsxDEV metadata.

Why it's fast

  • Pure functions: grid building and selection allocate no closures and hold no subscriptions.
  • No date library dependency: NativeAdapter uses native Date and Intl.DateTimeFormat.
  • Tree-shakeable: import only what you need; if it's just buildCalendarMonth, the rest goes.
  • Minimal React overhead: hooks use useMemo to avoid rebuilding grids on every render.
  • No CSS runtime: no CSS-in-JS overhead, no stylesheet injection.

Optimization tips