# Heavy libraries use dynamic imports (not loaded on every page)

- **Pattern:** `ab-002062` (`performance-load.bundle.dynamic-imports`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002062
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002062)

## Why it matters

A charting library like Recharts (180KB gzipped) or a rich text editor like Monaco (2MB) statically imported in a shared layout loads on every page — even the marketing homepage, authentication screens, and error pages that never render a chart or editor. This adds hundreds of milliseconds of unnecessary parse time to routes where the library is invisible. ISO 25010 performance-efficiency.time-behaviour requires time-behaviour to be proportionate to the task being performed; serving 2MB of editor JavaScript to a user reading a blog post is not proportionate.

## Severity rationale

Low because heavy static imports increase parse time on unrelated pages, but they do not prevent functionality and often go unnoticed until measured.

## Remediation

Move heavy library imports from static top-level imports to dynamic imports scoped to the component or route that actually uses them. Use `next/dynamic` in Next.js or `React.lazy` elsewhere, combined with a skeleton placeholder.

```tsx
// Before — loads Monaco on every page
import MonacoEditor from '@monaco-editor/react'

// After — loads only on /editor route
import dynamic from 'next/dynamic'
const MonacoEditor = dynamic(() => import('@monaco-editor/react'), {
  loading: () => <Skeleton className="h-64 w-full" />,
  ssr: false // Monaco doesn't support SSR
})

// Before — Recharts in layout.tsx
import { BarChart, BarChartData } from 'recharts'

// After — in the specific dashboard component
const AnalyticsChart = dynamic(
  () => import('./AnalyticsChart'), // AnalyticsChart wraps recharts
  { loading: () => <Skeleton />, ssr: false }
)
```

Verify the split worked by confirming recharts/monaco no longer appears in the main chunk in your bundle analyzer output.

## Detection

- **ID:** `dynamic-imports`
- **Severity:** `low`
- **What to look for:** List all dependencies over 100KB bundled size (common examples: recharts, chart.js, pdf-lib, monaco-editor, draft-js, quill, three.js, mapbox-gl). For each, count the number of pages/routes that import it. If a library is imported in a shared layout or top-level file but used on fewer than 50% of routes, it should use a dynamic import. Enumerate: "X heavy libraries detected, Y are dynamically imported."
- **Pass criteria:** At least 80% of heavy libraries (over 100KB bundled) that are used on fewer than 50% of routes are loaded via dynamic imports (`next/dynamic`, `React.lazy`, or equivalent). No more than 1 heavy library is statically imported in a shared layout while used on only 1-2 pages. Report: "X of Y heavy libraries use dynamic imports."
- **Fail criteria:** 2 or more large libraries over 100KB are imported at the top level of every page (via shared layout or global import), even though fewer than 50% of pages use them.
- **Skip (N/A) when:** Project has no dependencies over 100KB bundled, or total bundle is under 100KB gzipped.
- **Detail on fail:** `"0 of 3 heavy libraries use dynamic imports — recharts (180KB) imported in layout.tsx but used only on /dashboard, pdf-lib (200KB) used only on /export"` or `"monaco-editor (2MB) statically imported in app layout but only used in /editor route"`
- **Remediation:** Use dynamic imports for heavy libraries:

  ```tsx
  // Before — loaded everywhere
  import { BarChart } from 'recharts'
  export default function App() { ... }

  // After — loaded only when needed
  const AnalyticsChart = dynamic(() => import('./AnalyticsChart'), {
    loading: () => <Skeleton />,
    ssr: false // disable SSR if not needed
  })

  export default function App() {
    return <AnalyticsChart />
  }
  ```

## External references

- iso-25010 performance-efficiency.time-behaviour

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-002062
