Skip to content
Skills Library
Programming · Analysis

performance-optimization

/performance-optimization

Make a slow web frontend faster — web vitals, bundle size, code splitting, chunking, render behaviour. Use when a page is slow, the bundle grew, or web vitals regressed. API throughput and latency belong to load-testing.

Repository
claude-kit ↗
Licence
MIT
Last repository change
07.09.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
3
Scripts
0
HTML comments
2
URLs in SKILL.md
3
Deprecation

No signals detected. Repository changed on 07.09.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What to check before installing
  • SKILL.md zawiera komentarze HTML (2). Nie widać ich w podglądzie Markdown, a model je czyta.

What it does and when to use it

Make a slow web frontend faster — web vitals, bundle size, code splitting, chunking, render behaviour. Use when a page is slow, the bundle grew, or web vitals regressed. API throughput and latency belong to load-testing.

Original author description

Make a slow web frontend faster — web vitals, bundle size, code splitting, chunking, render behaviour. Use when a page is slow, the bundle grew, or web vitals regressed. API throughput and latency belong to load-testing.

How it works

  1. Steps
  2. References
Original SKILL.md headings · 294 lines, 1,227 words
SKILL.md preview
---
name: performance-optimization
description: Make a slow web frontend faster — web vitals, bundle size, code splitting, chunking, render behaviour. Use when a page is slow, the bundle grew, or web vitals regressed. API throughput and latency belong to load-testing.
---

Optimize performance for: the invocation request.

## Steps

1. **Identify the optimization target**: Determine if this is a bundle optimization, render performance issue, or Core Web Vitals improvement for `the invocation request`.

2. **Gather baseline metrics**: Run the appropriate analysis tools.

   ### Bundle Analysis
   ```bash
   # Use the project's bundle analyzer (examples: vite-bundle-visualizer, webpack-bundle-analyzer, esbuild analyzer)
   # Run the project's build and check output for chunk sizes
   ```

   ### Runtime Performance
   - Use the `auditor` agent or Chrome DevTools to run a Lighthouse trace on the target page
   - Check for framework-specific warnings in the browser console

3. **Apply optimizations based on category**:

---

### A. Bundle Optimization

#### Code Splitting (Route-Level)
Every major route should be lazy-loaded where the framework supports it:

**React/Preact example:**
```typescript
// App entry point
const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
const DataPage = React.lazy(() => import('./pages/DataPage'));

// Wrap in Suspense
<Suspense fallback={<Spinner />}>
  <Route path="/" element={<DashboardPage />} />
</Suspense>
```

**Vue example:**
```javascript
const routes = [
  { path: '/', component: () => import('./pages/DashboardPage.vue') },
  { path: '/data', component: () => import('./pages/DataPage.vue') },
];
```

**Angular example:**
```typescript
// In routing module
const routes: Routes = [
  { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule) },
];
```

#### Tree Shaking
- Import only what you use:
  ```typescript
  // GOOD
  import { IconName, SpecificIcon } from 'icon-library';

  // BAD
  import * as Icons from 'icon-library';
  ```
- Verify chart/visualization library imports are specific (e.g., import only the chart types you need)

#### Chunk Strategy
| Chunk | Contents | Target Size |
|-------|----------|-------------|
| `vendor-core` | Core framework (react/vue/angular) + router | ~40-50KB gz |
| `vendor-ui` | UI component library | ~30KB gz |
| `vendor-charts` | Chart/visualization libraries | ~50KB gz (lazy) |
| `app` | Application code | <100KB gz |
| Route chunks | Per-page code | <30KB gz each |

**Example configuration (adapt to your bundler):**

Vite:
```typescript
build: {
  rollupOptions: {
    output: {
      manualChunks: {
        'vendor-core': ['framework', 'framework-router'],
        'vendor-ui': ['ui-library-pkg'],
        'vendor-charts': ['chart-library'],
      },
    },
  },
},
```

Webpack:
```javascript
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendor' },
      // ... custom groups
    },
  },
},
```

#### Bundle Size Targets
| Metric | Target | Alert |
|--------|--------|-------|
| Initial JS (gzipped) | < 200KB | > 250KB |
| Largest chunk (gzipped) | < 100KB | > 120KB |
| Total CSS (gzipped) | < 30KB | > 50KB |

---

### B. UI Rendering Performance

#### Avoid Unnecessary Re-renders
**React/Preact:**
```typescript
// Use memoization for pure display components
const MetricCard = React.memo(function MetricCard({ title, value }: Props) {
  return <div>...</div>;
});

// Use memoization for expensive derivations
const sortedItems = useMemo(() =>
  items.sort((a, b) => b.priority - a.priority),
  [items]
);

// Use callbacks for handlers passed as props
const handleFilter = useCallback((value: string) => {
  setFilter(value);
}, []);
```

**Vue:**
```vue
<script setup>
// Use computed properties for derived state
const sortedItems = computed(() =>
  items.value.sort((a, b) => b.priority - a.priority)
);
</script>
```

**Angular:**
```typescript
// Use OnPush change detection for pure components
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})
```

#### Client State Store Anti-patterns
**Zustand (React) example:**
```typescript
// BAD - subscribes to entire store, re-renders on ANY change
const store = useStore();

// GOOD - subscribe to specific values
const items = useStore((s) => s.items);
const setFilter = useStore((s) => s.setFilter);

// BAD - creates new reference every render
const filtered = useStore((s) => s.items.filter(i => i.active));

// GOOD - store derived data as state, recompute in actions
const filteredItems = useStore((s) => s.filteredItems);
```

**Pinia (Vue) / Vuex:**
```javascript
// Use getters for derived state, not computed in components
const store = useMyStore();
const filteredItems = store.filteredItems; // getter defined in store
```

**NgRx (Angular):**
```typescript
// Use selectors for derived state
const filteredItems$ = store.select(selectFilteredItems);
```

#### Virtualization
Use virtualization for lists with > 50 items. Examples by framework:

**React:**
```typescript
import { useVirtualizer } from '@tanstack/react-virtual';

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null);
  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 64,
  });

  return (
    <div ref={parentRef} className="h-[600px] overflow-auto">
      <div style={{ height: virtualizer.getTotalSize() }} className="relative w-full">
        {virtualizer.getVirtualItems().map((virtualItem) => (
          <div
            key={virtualItem.key}
            className="absolute top-0 left-0 w-full"
            style={{ height: virtualItem.size, transform: `translateY(${virtualItem.start}px)` }}
          >
            <ItemRow item={items[virtualItem.index]} />
          </div>
        ))}
      </div>
    </div>
  );
}
```

**Vue:** Use `vue-virtual-scroller` or `@tanstack/vue-virtual`

**Angular:** Use `@angular/cdk/scrolling` with `cdk-virtual-scroll-viewport`

---

### C. Core Web Vitals

| Metric | Target | Common Fixes |
|--------|--------|-------------|
| LCP < 2.5s | Optimize critical rendering path | Lazy-load below-fold content, preload fonts |
| FID < 100ms | Minimize main thread work | Code-split heavy components, defer non-critical JS |
| CLS < 0.1 | Prevent layout shifts | Set explicit dimensions on images/containers, use min-height |
| INP < 200ms | Fast interactions | Debounce handlers, use framework-specific non-blocking APIs (e.g., React `startTransition`) |

#### Font Loading
```html
<!-- Preconnect to font CDN (if using web fonts) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Or use font-display: swap in CSS -->
@font-face {
  font-family: 'CustomFont';
  font-display: swap;
  src: url('/fonts/custom.woff2') format('woff2');
}
```

#### Image Optimization
- Use the project's optimized image component if available
- Specify `width` and `height` attributes to prevent CLS
- Use `loading="lazy"` for below-fold images
- Consider using modern formats (WebP, AVIF) with fallbacks

### D. Trustworthy measurement (statistical benchmarking)

Frontend timings are *noisy* — GC pauses, JIT warmup, thermal throttling, and background load make any
single run unreliable. A one-shot "before 210 ms → after 195 ms" comparison can easily be measuring
noise, not your change. Before you claim a regression or an improvement, measure it like an experiment:

- **Repeat and sample, don't run once.** Take many samples per variant, and **interleave** the
  variants (A, B, A, B, … round-robin) rather than all-A-then-all-B, so a thermal/background drift
  hits both equally instead of biasing one.
- **Report a confidence interval, not a point.** Summarize each variant as a mean **with a 95 %
  interval**, and decide based on whether the intervals **overlap**: overlapping → the difference is
  not significant (don't claim it); cleanly separated → a real effect.
- **Auto-sample until significant.** Keep sampling until the interval is tight enough to decide (or a
  cap is hit), rather than trusting a fixed small N.
- **Control the environment.** Same device/CPU throttle/network profile for both variants; close
  background work; pin the comparison to one machine. Compare A vs B *under identical conditions*, not
  across two casual runs. This is what makes the before/after table below honest.

> Stack-agnostic adaptation of statistically rigorous browser benchmarking (interleaved repeated
> sampling, 95 % confidence intervals, auto-sample-until-significance) from the BSD-3-Clause
> [`google/tachometer`](https://github.com/google/tachometer). Re-derived in prose; not vendored.

---

4. **Verify improvements**: Re-run analysis tools and compare against baseline.

5. **Report**: Output a before/after comparison table:

   | Metric | Before | After | Change |
   |--------|--------|-------|--------|
   | Initial bundle | Xkb | Ykb | -Z% |
   | LCP | Xs | Ys | -Zms |
   | ... | ... | ... | ... |

6. **Run build**: Execute the project's build command to confirm the build still passes.

## References

- Check the project's bundler config (e.g., `vite.config.ts`, `webpack.config.js`, `angular.json`)
- Consult the project's design system documentation for image/icon sizing guidelines
- Use the project's virtualization library (e.g., `@tanstack/react-virtual`, `vue-virtual-scroller`, `@angular/cdk/scrolling`)
Files in this package (3)
  • SKILL.md 9 KB
  • agents/openai.yaml 1 KB
  • references/htn-how-javascript-executes-the-code-behind-the-scenes.md 8 KB

Versions

RepositoryScoreLicence
This page · ajyadav013/claude-kit100MIT
zeative/satgas100AGPL-3.0
TheAstroByte/astrobyte-agent-skills100MIT
FrancoStino/opencode-skills-collection100MIT
sanity-io/sanity100MIT
magnus919/agent-skills100MIT
drvoss/everything-copilot-cli100MIT
atc-net/atc-agentic-toolkit100MIT
DnsQueen/orcinus-skills100MIT

Database snapshot: 13.11.2026 · package version 2c56b5f8f275 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 95frontend-performance
    Use this skill when the user says 'performance', 'slow page', 'bundle size', 'lazy loading', 'code splitting', 'LCP', 'CLS', 'INP', 'web vitals', 'image optimization', 'caching strategy', or when optimizing frontend performance. This skill enforces: measure-first optimization,…
  • 100performance
    Performance optimization for Next.js — bundle analysis, Core Web Vitals (LCP/CLS/INP), SSR streaming, code splitting, memory leaks, caching strategies, Lighthouse CI. Use when optimizing page speed, debugging slow renders, reducing bundle size, or setting up performance budgets.
  • 100fec-performance-optimization
    Use when diagnosing or improving frontend performance, Core Web Vitals, bundle size, runtime rendering cost, network waterfalls, memory leaks, long tasks, Lighthouse findings, or performance budgets; Chinese triggers include performance optimization, page freeze, slow first…
  • 100frontend-performance
    Use when a ticket is about a slow or heavy frontend — page load, bundle size, Core Web Vitals (LCP, INP, CLS), a janky list, re-render storms, large images or fonts — and the fix must be measured in the browser before and after with the same tooling, not guessed. Invoke for "the…
  • 100performance-audit
    Profiling, benchmarking, Web Vitals audit, N+1 detection, and performance optimization. Use when: performance, profiling, Web Vitals, N+1, slow, optimize, benchmark, latency, throughput.
  • 100frontend-performance-engineering
    Reference for measuring, diagnosing and improving frontend performance - establishing baselines; Core Web Vitals (LCP, INP, CLS); the critical rendering path and layout, paint and compositing; network waterfalls; bundle analysis, tree shaking, code splitting and lazy loading;…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.