Optimize performance
Skill VelimirMueller/claude_development_skills/skills/frontend/optimize-performance
Use when tuning frontend performance — enables the React Compiler, splits code by route and lazy-loads heavy chunks, adds bundle analysis with a size budget, measures Core Web Vitals (LCP/INP/CLS) with web-vitals, and applies image/CLS best practices. Measure first, then optimize.From its SKILL.md
npx -y skills add VelimirMueller/claude_development_skills --skill optimize-performanceAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.6 KB, as published. Nobody here has run it
Optimize Performance
1. Audit current state
grep -E '"(babel-plugin-react-compiler|rollup-plugin-visualizer|web-vitals)"' package.json 2>/dev/null
grep -rn "React.lazy\|defineAsyncComponent\|loading=\"lazy\"" src/ 2>/dev/null | head
Prerequisites: scaffold-frontend-project (Vite) and ideally set-up-routing (route-level splitting). Rule zero: measure before optimizing — wire the analyzer + vitals (steps 6–7) before hand-tuning anything.
2. Decide what to do
- Greenfield → enable Compiler + splitting + measurement (steps 4–8).
- Slow app → measure first (6–7), then attack the biggest chunk / worst vital.
3. Detect framework
React → React Compiler + React.lazy. Vue → the SFC compiler is already optimal; lazy via defineAsyncComponent, and v-memo/v-once for proven hotspots only.
4. Enable the React Compiler (React)
The compiler auto-memoizes — it removes the need for most useMemo/useCallback/memo. It's GA in React 19.
pnpm add -D babel-plugin-react-compiler
// vite.config.ts
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
// if set-up-routing ran, tanstackRouter() goes FIRST (before react)
react({ babel: { plugins: [['babel-plugin-react-compiler', {}]] } }), // compiler = build-time transform
// then tailwindcss()
],
});
The compiler relies on the Rules of React; add eslint-plugin-react-hooks (v5+, which ships the compiler rules) alongside Biome for React rule-checking only if you want lint-time guarantees — Biome doesn't cover those yet. After enabling, delete redundant useMemo/useCallback (keep Zustand selectors — different axis; see set-up-state-management).
5. Split code by route, lazy-load the heavy stuff
- Routes: already split if
set-up-routingran (TanStackautoCodeSplitting/ Vue dynamicimport()). - Heavy non-route components (charts, editors, modals below the fold):
const Chart = lazy(() => import('@/components/organisms/Chart')); // React
// Vue: const Chart = defineAsyncComponent(() => import('@/components/organisms/Chart.vue'))
Wrap in <Suspense>. Let Vite handle vendor splitting; only add build.rollupOptions.output.manualChunks for a measured win.
6. Bundle analysis + a budget
pnpm add -D rollup-plugin-visualizer
// vite.config.ts (dev-only-ish; gate behind an env flag)
import { visualizer } from 'rollup-plugin-visualizer';
// plugins: [..., visualizer({ filename: 'dist/stats.html', gzipSize: true })]
pnpm build then open dist/stats.html. Set a budget (e.g. initial JS < 200 KB gzipped) and enforce it with size-limit (pnpm add -D size-limit @size-limit/preset-app, add a size-limit array to package.json, run pnpm size-limit in CI) so regressions fail the build, not just the eyeball.
7. Measure Core Web Vitals
pnpm add web-vitals
// src/libs/reportWebVitals.ts
import { onCLS, onINP, onLCP } from 'web-vitals';
export function reportWebVitals(report: (m: { name: string; value: number }) => void) {
onCLS(report);
onINP(report); // INP replaced FID in 2024
onLCP(report);
}
Call it once from the app entry; send to analytics (or the captureError-style seam) in prod, console.log in dev.
8. Images & layout stability
- Always set
width/height(oraspect-ratio) so images don't shift layout (CLS). loading="lazy"+decoding="async"for below-the-fold images.- Serve AVIF/WebP;
vite-imagetoolsgenerates responsivesrcsetat build time. - Preload the LCP image/font;
font-display: swap.
9. Verify
pnpm build # inspect dist/stats.html against the budget
pnpm preview # run Lighthouse / read web-vitals in console
Targets: LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1 (mobile, mid-tier device).
References
- ./performance-rules.md — measure-first, the Compiler's effect, splitting strategy, CWV targets, image/CLS rules, when manual memo still matters.
- ../_shared/conventions.md —
@/alias,libs/seam. - ../_shared/stack-versions.md — tooling versions.
- ../../landing/build-landing-page/SKILL.md — the hero LCP/CLS budget on public pages, where CWV are ranking + revenue (the priority inversion:
../../landing/_shared/page-types.md).