Przejdź do treści
Biblioteka skilli
Programowanie · Analiza

performance-optimizer

/performance-optimizer

Optymalizuje wydajność aplikacji Vercel: Core Web Vitals, renderowanie, buforowanie, obrazy, fonty i rozmiar paczek.

Repozytorium
artemis ↗
Licencja
MIT
Ostatnia zmiana repozytorium
25.10.2026

Ocena i bezpieczeństwo

86/ 100Klasa: dobry
Format20 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść26 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
2
Skrypty
0
Komentarze HTML
8
Adresy URL w SKILL.md
9
Przestarzałość

Brak sygnałów. Repozytorium zmienione 25.10.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co sprawdzić przed instalacją
  • SKILL.md zawiera komentarze HTML (8). Nie widać ich w podglądzie Markdown, a model je czyta.

Co robi i kiedy

Optymalizuje wydajność aplikacji Vercel: Core Web Vitals, renderowanie, buforowanie, obrazy, fonty i rozmiar paczek.

Oryginalny opis (EN)

Specializes in optimizing Vercel application performance — Core Web Vitals, rendering strategies, caching, image optimization, font loading, edge computing, and bundle size. Use when investigating slow pages, improving Lighthouse scores, or optimizing loading performance.

Jak działa

  1. Core Web Vitals Reference
  2. Core Web Vitals Diagnostic Trees
  3. Rendering Strategy Decision Tree
  4. Detection Rules
  5. Quick Reference
  6. Bundle Size Analysis
  7. Caching Strategy Matrix
  8. Performance Audit Checklist
  9. Specific Fix Patterns
  10. Always Use next/image
Sekcje z nagłówków SKILL.md, w oryginale · 932 linii, 3 374 słów
Podgląd SKILL.md
---
name: performance-optimizer
description: Specializes in optimizing Vercel application performance — Core Web Vitals, rendering strategies, caching, image optimization, font loading, edge computing, and bundle size. Use when investigating slow pages, improving Lighthouse scores, or optimizing loading performance.
---

You are a Vercel performance optimization specialist. Use the diagnostic trees below to systematically identify and fix performance issues.

---

## Core Web Vitals Reference

| Metric | What It Measures | Good Threshold |
|--------|-----------------|----------------|
| LCP | Largest Contentful Paint | < 2.5s |
| INP | Interaction to Next Paint | < 200ms |
| CLS | Cumulative Layout Shift | < 0.1 |
| FCP | First Contentful Paint | < 1.8s |
| TTFB | Time to First Byte | < 800ms |

## Core Web Vitals Diagnostic Trees

### LCP (Largest Contentful Paint) — Target: < 2.5s

```
LCP > 2.5s?
├─ What is the LCP element?
│  ├─ Hero image
│  │  ├─ Using `next/image`? → Yes: check `priority` prop on above-fold images
│  │  ├─ Image format? → Ensure WebP/AVIF (automatic with next/image)
│  │  ├─ Image size > 200KB? → Resize to actual display dimensions
│  │  ├─ Lazy loaded? → Remove `loading="lazy"` for above-fold images
│  │  └─ CDN serving? → Vercel Image Optimization auto-serves from edge
│  │
│  ├─ Text block (heading, paragraph)
│  │  ├─ Font loading blocking render? → Use `next/font` with `display: swap`
│  │  ├─ Web font file > 100KB? → Subset to needed characters
│  │  └─ Font loaded from third-party? → Self-host via `next/font/google`
│  │
│  └─ Video / background image
│     ├─ Use `poster` attribute for video elements
│     ├─ Preload critical background images with `<link rel="preload">`
│     └─ Consider replacing video hero with static image + lazy video
│
├─ Server response time (TTFB) > 800ms?
│  ├─ Using SSR for static content? → Switch to SSG or ISR
│  ├─ Can use Cache Components? → Add `'use cache'` to slow Server Components
│  ├─ Database queries slow? → Add connection pooling, check query plans
│  ├─ Edge Config available? → Use for configuration data (< 5ms reads)
│  └─ Region mismatch? → Deploy function in same region as database
│
└─ Render-blocking resources?
   ├─ Large CSS file? → Use CSS Modules or Tailwind for tree-shaking
   ├─ Synchronous scripts in `<head>`? → Move to `next/script` with `afterInteractive`
   └─ Third-party scripts? → Defer with `next/script strategy="lazyOnload"`
```

### INP (Interaction to Next Paint) — Target: < 200ms

```
INP > 200ms?
├─ Which interaction is slow?
│  ├─ Button click / form submit
│  │  ├─ Heavy computation on main thread? → Move to Web Worker
│  │  ├─ State update triggers large re-render? → Memoize with `useMemo`/`React.memo`
│  │  ├─ Fetch request blocking UI? → Use `useTransition` for non-urgent updates
│  │  └─ Server Action slow? → Show optimistic UI with `useOptimistic`
│  │
│  ├─ Scroll / resize handlers
│  │  ├─ No debounce/throttle? → Add `requestAnimationFrame` or debounce
│  │  ├─ Layout thrashing? → Batch DOM reads, then writes
│  │  └─ Intersection Observer available? → Replace scroll listeners
│  │
│  └─ Keyboard input in forms
│     ├─ Controlled input re-rendering entire form? → Use `useRef` for form state
│     ├─ Expensive validation on every keystroke? → Debounce validation
│     └─ Large component tree updating? → Push `'use client'` boundary down
│
├─ Hydration time > 500ms?
│  ├─ Too many client components? → Audit `'use client'` boundaries
│  ├─ Large component tree hydrating at once? → Use Suspense for progressive hydration
│  ├─ Third-party scripts competing? → Defer with `next/script`
│  └─ Bundle size > 200KB (gzipped)? → See bundle analysis below
│
└─ Long tasks (> 50ms) on main thread?
   ├─ Profile with Chrome DevTools → Performance tab → identify long tasks
   ├─ Break up long tasks with `scheduler.yield()` or `setTimeout`
   └─ Move to Server Components where possible (zero client JS)
```

### CLS (Cumulative Layout Shift) — Target: < 0.1

```
CLS > 0.1?
├─ Images causing layout shift?
│  ├─ Missing `width`/`height`? → Always set dimensions (next/image does this)
│  ├─ Not using `next/image`? → Migrate to `next/image` for automatic sizing
│  └─ Aspect ratio changes on load? → Set explicit `aspect-ratio` in CSS
│
├─ Fonts causing layout shift?
│  ├─ Not using `next/font`? → Migrate to `next/font` (zero-CLS font loading)
│  ├─ FOUT (flash of unstyled text)? → `next/font` with `adjustFontFallback: true`
│  └─ Custom font metrics off? → Use `size-adjust` CSS property
│
├─ Dynamic content injected above viewport?
│  ├─ Ad banners / cookie banners? → Reserve space with `min-height`
│  ├─ Async-loaded components? → Use skeleton placeholders with fixed dimensions
│  └─ Toast notifications? → Position as overlay (fixed/absolute), not in flow
│
├─ CSS animations triggering layout?
│  ├─ Animating `width`, `height`, `top`, `left`? → Use `transform` instead
│  └─ Use `will-change: transform` for GPU-accelerated animations
│
└─ Responsive design shifts?
   ├─ Different layouts per breakpoint causing jump? → Use consistent aspect ratios
   └─ Client-side media query check? → Use CSS media queries, not JS `matchMedia`
```

---

## Rendering Strategy Decision Tree

<!-- Sourced from nextjs skill: references/rsc-boundaries.md -->
# RSC Boundaries

Detect and prevent invalid patterns when crossing Server/Client component boundaries.

## Detection Rules

### 1. Async Client Components Are Invalid

Client components **cannot** be async functions. Only Server Components can be async.

**Detect:** File has `'use client'` AND component is `async function` or returns `Promise`

```tsx
// Bad: async client component
'use client'
export default async function UserProfile() {
  const user = await getUser() // Cannot await in client component
  return <div>{user.name}</div>
}

// Good: Remove async, fetch data in parent server component
// page.tsx (server component - no 'use client')
export default async function Page() {
  const user = await getUser()
  return <UserProfile user={user} />
}

// UserProfile.tsx (client component)
'use client'
export function UserProfile({ user }: { user: User }) {
  return <div>{user.name}</div>
}
```

```tsx
// Bad: async arrow function client component
'use client'
const Dashboard = async () => {
  const data = await fetchDashboard()
  return <div>{data}</div>
}

// Good: Fetch in server component, pass data down
```

### 2. Non-Serializable Props to Client Components

Props passed from Server → Client must be JSON-serializable.

**Detect:** Server component passes these to a client component:
- Functions (except Server Actions with `'use server'`)
- `Date` objects
- `Map`, `Set`, `WeakMap`, `WeakSet`
- Class instances
- `Symbol` (unless globally registered)
- Circular references

```tsx
// Bad: Function prop
// page.tsx (server)
export default function Page() {
  const handleClick = () => console.log('clicked')
  return <ClientButton onClick={handleClick} />
}

// Good: Define function inside client component
// ClientButton.tsx
'use client'
export function ClientButton() {
  const handleClick = () => console.log('clicked')
  return <button onClick={handleClick}>Click</button>
}
```

```tsx
// Bad: Date object (silently becomes string, then crashes)
// page.tsx (server)
export default async function Page() {
  const post = await getPost()
  return <PostCard createdAt={post.createdAt} /> // Date object
}

// PostCard.tsx (client) - will crash on .getFullYear()
'use client'
export function PostCard({ createdAt }: { createdAt: Date }) {
  return <span>{createdAt.getFullYear()}</span> // Runtime error!
}

// Good: Serialize to string on server
// page.tsx (server)
export default async function Page() {
  const post = await getPost()
  return <PostCard createdAt={post.createdAt.toISOString()} />
}

// PostCard.tsx (client)
'use client'
export function PostCard({ createdAt }: { createdAt: string }) {
  const date = new Date(createdAt)
  return <span>{date.getFullYear()}</span>
}
```

```tsx
// Bad: Class instance
const user = new UserModel(data)
<ClientProfile user={user} /> // Methods will be stripped

// Good: Pass plain object
const user = await getUser()
<ClientProfile user={{ id: user.id, name: user.name }} />
```

```tsx
// Bad: Map/Set
<ClientComponent items={new Map([['a', 1]])} />

// Good: Convert to array/object
<ClientComponent items={Object.fromEntries(map)} />
<ClientComponent items={Array.from(set)} />
```

### 3. Server Actions Are the Exception

Functions marked with `'use server'` CAN be passed to client components.

```tsx
// Valid: Server Action can be passed
// actions.ts
'use server'
export async function submitForm(formData: FormData) {
  // server-side logic
}

// page.tsx (server)
import { submitForm } from './actions'
export default function Page() {
  return <ClientForm onSubmit={submitForm} /> // OK!
}

// ClientForm.tsx (client)
'use client'
export function ClientForm({ onSubmit }: { onSubmit: (data: FormData) => Promise<void> }) {
  return <form action={onSubmit}>...</form>
}
```

## Quick Reference

| Pattern | Valid? | Fix |
|---------|--------|-----|
| `'use client'` + `async function` | No | Fetch in server parent, pass data |
| Pass `() => {}` to client | No | Define in client or use server action |
| Pass `new Date()` to client | No | Use `.toISOString()` |
| Pass `new Map()` to client | No | Convert to object/array |
| Pass class instance to client | No | Pass plain object |
| Pass server action to client | Yes | - |
| Pass `string/number/boolean` | Yes | - |
| Pass plain object/array | Yes | - |

---

## Bundle Size Analysis

<!-- Sourced from nextjs skill: references/bundling.md > Bundle Analysis -->
Analyze bundle size with the built-in analyzer (Next.js 16.1+):

```bash
next experimental-analyze
```

This opens an interactive UI to:
- Filter by route, environment (client/server), and type
- Inspect module sizes and import chains
- View treemap visualization

Save output for comparison:

```bash
next experimental-analyze --output
# Output saved to .next/diagnostics/analyze
```

Reference: https://nextjs.org/docs/app/guides/package-bundling

---

## Caching Strategy Matrix

<!-- Sourced from nextjs skill: references/data-patterns.md > Decision Tree -->
```
Need to fetch data?
├── From a Server Component?
│   └── Use: Fetch directly (no API needed)
│
├── From a Client Component?
│   ├── Is it a mutation (POST/PUT/DELETE)?
│   │   └── Use: Server Action
│   └── Is it a read (GET)?
│       └── Use: Route Handler OR pass from Server Component
│
├── Need external API access (webhooks, third parties)?
│   └── Use: Route Handler
│
└── Need REST API for mobile app / external clients?
    └── Use: Route Handler
```

### Cache Invalidation Patterns

<!-- Sourced from next-cache-components skill: Cache Invalidation -->
### `cacheTag()` - Tag Cached Content

```tsx
import { cacheTag } from 'next/cache'

async function getProducts() {
  'use cache'
  cacheTag('products')
  return db.products.findMany()
}

async function getProduct(id: string) {
  'use cache'
  cacheTag('products', `product-${id}`)
  return db.products.findUnique({ where: { id } })
}
```

### `updateTag()` - Immediate Invalidation

Use when you need the cache refreshed within the same request:

```tsx
'use server'

import { updateTag } from 'next/cache'

export async function updateProduct(id: string, data: FormData) {
  await db.products.update({ where: { id }, data })
  updateTag(`product-${id}`)  // Immediate - same request sees fresh data
}
```

### `revalidateTag()` - Background Revalidation

Use for stale-while-revalidate behavior:

```tsx
'use server'

import { revalidateTag } from 'next/cache'

export async function createPost(data: FormData) {
  await db.posts.create({ data })
  revalidateTag('posts')  // Background - next request sees fresh data
}
```

---

---

## Performance Audit Checklist

Run through this when asked to optimize a Vercel application:

1. **Measure first**: Check Speed Insights dashboard for real-user CWV data
2. **Identify LCP element**: Use Chrome DevTools → Performance → identify the LCP element
3. **Audit `'use client'`**: Every `'use client'` file ships JS to the browser — minimize
4. **Check images**: All above-fold images use `next/image` with `priority`
5. **Check fonts**: All fonts loaded via `next/font` (zero CLS)
6. **Check third-party scripts**: All use `next/script` with correct strategy
7. **Check data fetching**: Server Components fetch in parallel, no waterfalls
8. **Check caching**: Cache Components used for expensive operations
9. **Check bundle**: Run analyzer, look for low-hanging fruit
10. **Check infrastructure**: Functions in correct region, Fluid Compute enabled

---

## Specific Fix Patterns

### Image Optimization

<!-- Sourced from nextjs skill: references/image.md -->
# Image Optimization

Use `next/image` for automatic image optimization.

## Always Use next/image

```tsx
// Bad: Avoid native img
<img src="/hero.png" alt="Hero" />

// Good: Use next/image
import Image from 'next/image'
<Image src="/hero.png" alt="Hero" width={800} height={400} />
```

## Required Props

Images need explicit dimensions to prevent layout shift:

```tsx
// Local images - dimensions inferred automatically
import heroImage from './hero.png'
<Image src={heroImage} alt="Hero" />

// Remote images - must specify width/height
<Image src="https://example.com/image.jpg" alt="Hero" width={800} height={400} />

// Or use fill for parent-relative sizing
<div style={{ position: 'relative', width: '100%', height: 400 }}>
  <Image src="/hero.png" alt="Hero" fill style={{ objectFit: 'cover' }} />
</div>
```

## Remote Images Configuration

Remote domains must be configured in `next.config.js`:

```js
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '*.cdn.com', // Wildcard subdomain
      },
    ],
  },
}
```

## Responsive Images

Use `sizes` to tell the browser which size to download:

```tsx
// Full-width hero
<Image
  src="/hero.png"
  alt="Hero"
  fill
  sizes="100vw"
/>

// Responsive grid (3 columns on desktop, 1 on mobile)
<Image
  src="/card.png"
  alt="Card"
  fill
  sizes="(max-width: 768px) 100vw, 33vw"
/>

// Fixed sidebar image
<Image
  src="/avatar.png"
  alt="Avatar"
  width={200}
  height={200}
  sizes="200px"
/>
```

## Blur Placeholder

Prevent layout shift with placeholders:

```tsx
// Local images - automatic blur hash
import heroImage from './hero.png'
<Image src={heroImage} alt="Hero" placeholder="blur" />

// Remote images - provide blurDataURL
<Image
  src="https://example.com/image.jpg"
  alt="Hero"
  width={800}
  height={400}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>

// Or use color placeholder
<Image
  src="https://example.com/image.jpg"
  alt="Hero"
  width={800}
  height={400}
  placeholder="empty"
  style={{ backgroundColor: '#e0e0e0' }}
/>
```

## Priority Loading

Use `priority` for above-the-fold images (LCP):

```tsx
// Hero image - loads immediately
<Image src="/hero.png" alt="Hero" fill priority />

// Below-fold images - lazy loaded by default (no priority needed)
<Image src="/card.png" alt="Card" width={400} height={300} />
```

## Common Mistakes

```tsx
// Bad: Missing sizes with fill - downloads largest image
<Image src="/hero.png" alt="Hero" fill />

// Good: Add sizes for proper responsive behavior
<Image src="/hero.png" alt="Hero" fill sizes="100vw" />

// Bad: Using width/height for aspect ratio only
<Image src="/hero.png" alt="Hero" width={16} height={9} />

// Good: Use actual display dimensions or fill with sizes
<Image src="/hero.png" alt="Hero" fill sizes="100vw" style={{ objectFit: 'cover' }} />

// Bad: Remote image without config
<Image src="https://untrusted.com/image.jpg" alt="Image" width={400} height={300} />
// Error: Invalid src prop, hostname not configured

// Good: Add hostname to next.config.js remotePatterns
```

## Static Export

When using `output: 'export'`, use `unoptimized` or custom loader:

```tsx
// Option 1: Disable optimization
<Image src="/hero.png" alt="Hero" width={800} height={400} unoptimized />

// Option 2: Global config
// next.config.js
module.exports = {
  output: 'export',
  images: { unoptimized: true },
}

// Option 3: Custom loader (Cloudinary, Imgix, etc.)
const cloudinaryLoader = ({ src, width, quality }) => {
  return `https://res.cloudinary.com/demo/image/upload/w_${width},q_${quality || 75}/${src}`
}

<Image loader={cloudinaryLoader} src="sample.jpg" alt="Sample" width={800} height={400} />
```

### Font Loading

<!-- Sourced from nextjs skill: references/font.md -->
# Font Optimization

Use `next/font` for automatic font optimization with zero layout shift.

## Google Fonts

```tsx
// app/layout.tsx
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}
```

## Multiple Fonts

```tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
})

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  variable: '--font-roboto-mono',
})

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  )
}
```

Use in CSS:
```css
body {
  font-family: var(--font-inter);
}

code {
  font-family: var(--font-roboto-mono);
}
```

## Font Weights and Styles

```tsx
// Single weight
const inter = Inter({
  subsets: ['latin'],
  weight: '400',
})

// Multiple weights
const inter = Inter({
  subsets: ['latin'],
  weight: ['400', '500', '700'],
})

// Variable font (recommended) - includes all weights
const inter = Inter({
  subsets: ['latin'],
  // No weight needed - variable fonts support all weights
})

// With italic
const inter = Inter({
  subsets: ['latin'],
  style: ['normal', 'italic'],
})
```

## Local Fonts

```tsx
import localFont from 'next/font/local'

const myFont = localFont({
  src: './fonts/MyFont.woff2',
})

// Multiple files for different weights
const myFont = localFont({
  src: [
    {
      path: './fonts/MyFont-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: './fonts/MyFont-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
  ],
})

// Variable font
const myFont = localFont({
  src: './fonts/MyFont-Variable.woff2',
  variable: '--font-my-font',
})
```

## Tailwind CSS Integration

```tsx
// app/layout.tsx
import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
})

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={inter.variable}>
      <body>{children}</body>
    </html>
  )
}
```

```js
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['var(--font-inter)'],
      },
    },
  },
}
```

## Preloading Subsets

Only load needed character subsets:

```tsx
// Latin only (most common)
const inter = Inter({ subsets: ['latin'] })

// Multiple subsets
const inter = Inter({ subsets: ['latin', 'latin-ext', 'cyrillic'] })
```

## Display Strategy

Control font loading behavior:

```tsx
const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // Default - shows fallback, swaps when loaded
})

// Options:
// 'auto' - browser decides
// 'block' - short block period, then swap
// 'swap' - immediate fallback, swap when ready (recommended)
// 'fallback' - short block, short swap, then fallback
// 'optional' - short block, no swap (use if font is optional)
```

## Don't Use Manual Font Links

Always use `next/font` instead of `<link>` tags for Google Fonts.

```tsx
// Bad: Manual link tag (blocks rendering, no optimization)
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet" />

// Bad: Missing display and preconnect
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet" />

// Good: Use next/font (self-hosted, zero layout shift)
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })
```

## Common Mistakes

```tsx
// Bad: Importing font in every component
// components/Button.tsx
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] }) // Creates new instance each time!

// Good: Import once in layout, use CSS variable
// app/layout.tsx
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })

// Bad: Using @import in CSS (blocks rendering)
/* globals.css */
@import url('https://fonts.googleapis.com/css2?family=Inter');

// Good: Use next/font (self-hosted, no network request)
import { Inter } from 'next/font/google'

// Bad: Loading all weights when only using a few
const inter = Inter({ subsets: ['latin'] }) // Loads all weights

// Good: Specify only needed weights (for non-variable fonts)
const inter = Inter({ subsets: ['latin'], weight: ['400', '700'] })

// Bad: Missing subset - loads all characters
const inter = Inter({})

// Good: Always specify subset
const inter = Inter({ subsets: ['latin'] })
```

## Font in Specific Components

```tsx
// For component-specific fonts, export from a shared file
// lib/fonts.ts
import { Inter, Playfair_Display } from 'next/font/google'

export const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })
export const playfair = Playfair_Display({ subsets: ['latin'], variable: '--font-playfair' })

// components/Heading.tsx
import { playfair } from '@/lib/fonts'

export function Heading({ children }) {
  return <h1 className={playfair.className}>{children}</h1>
}
```

### Cache Components (Next.js 16)

<!-- Sourced from next-cache-components skill: use cache Directive -->
### File Level

```tsx
'use cache'

export default async function Page() {
  // Entire page is cached
  const data = await fetchData()
  return <div>{data}</div>
}
```

### Component Level

```tsx
export async function CachedComponent() {
  'use cache'
  const data = await fetchData()
  return <div>{data}</div>
}
```

### Function Level

```tsx
export async function getData() {
  'use cache'
  return db.query('SELECT * FROM posts')
}
```

---

### Optimistic UI for Server Actions

<!-- Sourced from nextjs skill: references/data-patterns.md > Client Component Data Fetching -->
When Client Components need data:

### Option 1: Pass from Server Component (Preferred)

```tsx
// Server Component
async function Page() {
  const data = await fetchData();
  return <ClientComponent initialData={data} />;
}

// Client Component
'use client';
function ClientComponent({ initialData }) {
  const [data, setData] = useState(initialData);
  // ...
}
```

### Option 2: Fetch on Mount (When Necessary)

```tsx
'use client';
import { useEffect, useState } from 'react';

function ClientComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('/api/data')
      .then(r => r.json())
      .then(setData);
  }, []);

  if (!data) return <Loading />;
  return <div>{data.value}</div>;
}
```

### Option 3: Server Action for Reads (Works But Not Ideal)

Server Actions can be called from Client Components for reads, but this is not their intended purpose:

```tsx
'use client';
import { getData } from './actions';
import { useEffect, useState } from 'react';

function ClientComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    getData().then(setData);
  }, []);

  return <div>{data?.value}</div>;
}
```

**Note**: Server Actions always use POST, so no HTTP caching. Prefer Route Handlers for cacheable reads.

---

Report findings as: **Issue** → **Impact** (which CWV affected, by how much) → **Recommendation** (specific code change) → **Expected Improvement** (target metric).

Always reference the **Next.js skill** (`⤳ skill: nextjs`) for framework patterns. For monitoring setup, configure drains via Dashboard or REST API.
Pliki w paczce (2)
  • SKILL.json 1 KB
  • SKILL.md 24 KB

Wersje

RepozytoriumWynikLicencja
Ta strona · 420company/artemis86MIT
smicolon/ai-kit100MIT
armanzeroeight/fastagent-plugins100MIT
armanzeroeight/fastagent-plugins100MIT
Domenico-Tenace-Open-Labs/web-dev-agent90MIT
JochenYang/Jochen-ai-rules90MIT

Migawka bazy z 13.11.2026 · wersja paczki d9851b3268ec (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100performance
    Mierzy i poprawia szybkość stron: Core Web Vitals, rozmiar paczek, kompresję obrazów, cache i czcionki.
  • 100perf-web-optimization
    Optymalizuje wydajność stron WWW: rozmiar bundle'a, obrazy, cache, lazy loading, przesunięcia układu i czas do interaktywności pod wynik Lighthouse.
  • 100performance
    Optymalizuje wydajność aplikacji Next.js: analiza bundle'a, Core Web Vitals, strumieniowanie SSR, dzielenie kodu, wycieki pamięci, cache i Lighthouse CI.
  • 100web-performance-optimization
    Optymalizuje wydajność aplikacji Angular 21: Core Web Vitals, rozmiar paczek, lazy loading i SSR, zawsze po pomiarze.
  • 100next-on-vercel-perf
    Diagnozuje i poprawia Core Web Vitals oraz wydajność strony aplikacji Next.js na Vercel, zaczynając od pomiaru: LCP, INP, CLS, rozmiar JS, obrazy, fonty i cache na edge.
  • 100web-performance-optimization
    Optymalizuje wydajność aplikacji webowej przez code splitting, lazy loading, strategie cache i monitorowanie Core Web Vitals, a także service workery i zmniejszanie bundli.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.