
React Performance Optimization
Shrink initial JavaScript bundles and defer heavy UI with React.lazy, Suspense, and route-level code splitting before you ship a React app.
Overview
react-performance-optimization is an agent skill for the Ship phase that teaches React.lazy and Suspense code-splitting patterns to reduce initial bundle size.
Install
npx skills add https://github.com/nickcrew/claude-ctx-plugin --skill react-performance-optimizationWhat is this skill?
- React.lazy + Suspense patterns for route-based and component-level splitting
- Examples with react-router-dom Routes for Dashboard, Reports, and Settings pages
- Guidance to split heavy widgets (charts, editors, modals) behind Suspense fallbacks
- Calls out First Contentful Paint and caching benefits of on-demand chunk loading
- Best practices: route splits first, meaningful loading UI, preload critical paths
Adoption & trust: 1.4k installs on skills.sh; 15 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your React app ships one large bundle so first paint is slow even when users only need a single route or lightweight shell.
Who is it for?
Solo builders finishing a React SPA or dashboard who already use react-router and want agent-guided splitting without guessing chunk boundaries.
Skip if: Non-React stacks, server-only APIs, or apps where SSR/streaming architecture (e.g. Next.js RSC) replaces client-side lazy loading as the primary strategy.
When should I use this skill?
User is optimizing React load performance, bundle size, or asking for lazy loading / code splitting with Suspense and react-router.
What do I get? / Deliverables
You get route- and component-level lazy boundaries with Suspense fallbacks so chunks load on demand and critical UI appears faster.
- Refactored lazy route and component imports with Suspense boundaries
- Loading fallback components aligned to UX expectations
- Documented split order (routes before heavy optional widgets)
Recommended Skills
Journey fit
Performance tuning and bundle strategy belong on the Ship shelf because they directly affect load time and UX before users hit production traffic. The skill documents perf patterns (lazy routes, component splits, fallbacks)—exactly the perf subphase for frontend React products.
How it compares
Pattern library for bundle splitting—not a Lighthouse runner or automated bundle analyzer integration.
Common Questions / FAQ
Who is react-performance-optimization for?
Indie developers and small teams shipping React frontends who want their coding agent to apply consistent lazy-loading and Suspense patterns during perf passes.
When should I use react-performance-optimization?
In the Ship perf phase when you are tightening load time before launch—especially for route-heavy SaaS dashboards, marketing sites with hidden heavy widgets, or browser extensions built with React.
Is react-performance-optimization safe to install?
It is documentation-only procedural guidance with no network or shell requirements; still review the Security Audits panel on this Prism page before adding any third-party skill pack.
SKILL.md
READMESKILL.md - React Performance Optimization
# Code Splitting Patterns ## React.lazy and Suspense **Load components on demand for smaller initial bundles:** ```jsx import { lazy, Suspense } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; // Lazy-loaded route components const Dashboard = lazy(() => import('./pages/Dashboard')); const Reports = lazy(() => import('./pages/Reports')); const Settings = lazy(() => import('./pages/Settings')); // Component-level code splitting const HeavyChart = lazy(() => import('./components/HeavyChart')); function App() { return ( <BrowserRouter> <Suspense fallback={<LoadingSpinner />}> <Routes> <Route path="/" element={<Dashboard />} /> <Route path="/reports" element={<Reports />} /> <Route path="/settings" element={<Settings />} /> </Routes> </Suspense> </BrowserRouter> ); } function DataVisualization({ data, showChart }) { return ( <div> <h2>Data Overview</h2> {showChart && ( <Suspense fallback={<div>Loading chart...</div>}> <HeavyChart data={data} /> </Suspense> )} </div> ); } ``` **Benefits:** - Reduces initial bundle size (faster First Contentful Paint) - Loads code only when needed (better caching) - Route-based splitting: Users only download visited pages **Best practices:** - Split by routes first (biggest impact) - Split heavy components (charts, editors, modals) - Provide meaningful loading fallbacks - Preload critical routes with `<link rel="preload">` ## Bundle Optimization **Reduce bundle size with smart imports and tree shaking:** ```jsx // BAD: Imports entire library import _ from 'lodash'; import { Button, Modal, Table, Form } from 'antd'; // GOOD: Import only needed functions import debounce from 'lodash/debounce'; import groupBy from 'lodash/groupBy'; // GOOD: Tree-shakeable imports (if library supports it) import { Button } from 'antd/es/button'; import { Modal } from 'antd/es/modal'; // Dynamic imports for heavy libraries const PDFViewer = lazy(() => import('react-pdf-viewer')); const CodeEditor = lazy(() => import('@monaco-editor/react')); // Conditional polyfill loading async function loadPolyfills() { if (!window.IntersectionObserver) { await import('intersection-observer'); } } ``` ## Bundle Analysis Tools ```bash # Webpack Bundle Analyzer npm install --save-dev webpack-bundle-analyzer # Vite Bundle Visualizer npm install --save-dev rollup-plugin-visualizer # Analyze bundle composition npm run build -- --stats npx webpack-bundle-analyzer dist/stats.json ``` **Analysis workflow:** 1. Generate production build with stats 2. Open bundle visualizer 3. Identify large dependencies 4. Check for duplicate code 5. Find optimization opportunities (lazy loading, tree shaking) 6. Measure improvement after changes # Common Performance Pitfalls ## 1. Inline Object/Array Props ### The Problem ```jsx // BAD: New object every render defeats memo function Parent() { return <Component config={{ theme: 'dark' }} />; } const Component = memo(({ config }) => { // Re-renders every time because config is a new object return <div>{config.theme}</div>; }); ``` ### Solutions ```jsx // GOOD: Stable reference with useMemo function Parent() { const config = useMemo(() => ({ theme: 'dark' }), []); return <Component config={config} />; } // BEST: Extract to constant if truly static const CONFIG = { theme: 'dark' }; function Parent() { return <Component config={CONFIG} />; } // ALSO GOOD: Pass primitives directly function Parent() { return <Component theme="dark" />; } ``` ## 2. Anonymous Functions in JSX ### The Problem ```jsx // BAD: New function every render function List({ items }) { return items.map(item => ( <Item key={item.id} onClick={() => handleClick(item.id)} /> )); } ``` ### Solutions ```jsx // GOOD: useCallback with stable reference function List({ items }) { const handleItemClick = useCallback((id) => {