Dynamic imports for heavy UI components
Why it matters
Charting libraries (Recharts, Chart.js), code editors (Monaco), and rich-text editors routinely weigh 100–300KB gzipped each. Importing any of them statically means that weight lands in the initial bundle, inflating Time to Interactive for every page — including pages where the component never renders. ISO 25010:2011 time-behaviour captures the latency hit; the business impact is users abandoning a landing page because a chart used only on the analytics dashboard was eagerly loaded.
Severity rationale
Medium because heavy UI components inflate the initial bundle and delay interactivity even on pages where those components are not displayed, though the impact is proportional to the library sizes involved.
Remediation
Wrap any component over 50KB gzipped in a dynamic import with a loading fallback. In Next.js, use next/dynamic with ssr: false for browser-only libraries like canvas-based charts.
// components/analytics-chart.tsx
import dynamic from 'next/dynamic'
const LineChart = dynamic(
() => import('recharts').then((m) => m.LineChart),
{ ssr: false, loading: () => <Skeleton className="h-64 w-full" /> }
)
Detection
-
ID:
dynamic-imports-heavy-ui -
Severity:
medium -
What to look for: Count all heavy UI library imports (charting, code editors, rich text editors, data tables over 50KB). Enumerate which use dynamic imports vs. static imports. Identify heavy UI libraries in the project (charting libraries like Recharts, data tables, modals, code editors). Check whether they use dynamic imports or are bundled eagerly. Look for
React.lazy,import(), or framework-specific dynamic loading. -
Pass criteria: Heavy UI components (charts, modals, code editors) are loaded on-demand via dynamic imports. They are not included in the initial bundle. At least 90% of heavy UI components (over 50KB each) should use dynamic imports.
-
Fail criteria: Heavy components like Recharts, Monaco Editor, or large modals are imported statically and included in the initial bundle, even if used only on certain pages or after user interaction.
-
Skip (N/A) when: The project does not contain heavy UI components, or all heavy components are rendered only after user interaction (e.g., a chart rendered on click).
-
Cross-reference: For bundle size impact of these heavy components, see the
bundle-size-criticalcheck. -
Detail on fail:
"Recharts library (125KB gzipped) imported statically and included in initial bundle. Chart rendered only on dashboard page, not on landing page"or"Monaco Editor bundled eagerly despite being used only in settings page" -
Remediation: Use dynamic imports for heavy components that are not immediately visible.
// components/chart.tsx — dynamic import for heavy component import dynamic from 'next/dynamic' const Chart = dynamic(() => import('recharts').then(m => m.LineChart), { ssr: false })
External references
- iso-25010:2011 · time-behaviour — Time Behaviour (performance efficiency)
Taxons
History
- 2026-04-18·v1.0.0·Initial import from performance-deep-dive·automated