agentsclimarketplace

Performance vitals

Skill ComeOnOliver/skillshub/skills/aiskillstore/marketplace/doyajin174/performance-vitals

๐Ÿง  The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.

Install
npx -y skills add ComeOnOliver/skillshub --skill performance-vitals

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Enforce Core Web Vitals optimization. Use when building user-facing features, reviewing performance, or when Lighthouse scores drop. Covers LCP, FID/INP, CLS, and optimization techniques.

The file declares its own license as MIT. That is the authorโ€™s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.2 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it

Performance & Core Web Vitals

Core Web Vitals ์ตœ์ ํ™”๋ฅผ ๊ฐ•์ œํ•˜๋Š” ์Šคํ‚ฌ์ž…๋‹ˆ๋‹ค.

2025 Context

2024๋…„ 3์›”: INP(Interaction to Next Paint)๊ฐ€ FID๋ฅผ ๋Œ€์ฒด Google Search ๋žญํ‚น์— Core Web Vitals ์˜ํ–ฅ

Core Web Vitals ๋ชฉํ‘œ

์ง€ํ‘œGoodNeeds ImprovementPoor
LCP (Largest Contentful Paint)โ‰ค 2.5s2.5s - 4s> 4s
INP (Interaction to Next Paint)โ‰ค 200ms200ms - 500ms> 500ms
CLS (Cumulative Layout Shift)โ‰ค 0.10.1 - 0.25> 0.25

LCP ์ตœ์ ํ™” (Largest Contentful Paint)

๋ฌธ์ œ ์›์ธ

  • ๋А๋ฆฐ ์„œ๋ฒ„ ์‘๋‹ต
  • ๋ Œ๋” ์ฐจ๋‹จ ๋ฆฌ์†Œ์Šค (CSS, JS)
  • ๋А๋ฆฐ ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ
  • ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. ์ด๋ฏธ์ง€ ์ตœ์ ํ™”

// โŒ BAD: ์ตœ์ ํ™” ์—†๋Š” ์ด๋ฏธ์ง€
<img src="/hero.jpg" alt="Hero" />

// โœ… GOOD: Next.js Image ์ปดํฌ๋„ŒํŠธ
import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // LCP ์ด๋ฏธ์ง€๋Š” priority ์ถ”๊ฐ€
  placeholder="blur"
  blurDataURL={blurDataUrl}
/>

2. ํฐํŠธ ์ตœ์ ํ™”

// โœ… GOOD: Next.js ํฐํŠธ ์ตœ์ ํ™”
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',  // FOIT ๋ฐฉ์ง€
  preload: true,
});

// CSS
@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap;
}

3. Critical CSS ์ธ๋ผ์ธ

// next.config.js
module.exports = {
  experimental: {
    optimizeCss: true,
  },
};

4. ํ”„๋ฆฌ๋กœ๋“œ

<!-- ์ค‘์š” ๋ฆฌ์†Œ์Šค ํ”„๋ฆฌ๋กœ๋“œ -->
<link rel="preload" href="/hero.jpg" as="image" />
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin />
<link rel="preconnect" href="https://api.example.com" />

INP ์ตœ์ ํ™” (Interaction to Next Paint)

๋ฌธ์ œ ์›์ธ

  • ๊ธด JavaScript ํƒœ์Šคํฌ
  • ๊ณผ๋„ํ•œ DOM ํฌ๊ธฐ
  • ๋น„ํšจ์œจ์ ์ธ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. ๊ธด ํƒœ์Šคํฌ ๋ถ„ํ• 

// โŒ BAD: ๊ธด ๋™๊ธฐ ์ž‘์—…
function processLargeData(items: Item[]) {
  items.forEach(item => {
    heavyComputation(item);  // ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ๋ธ”๋กœํ‚น
  });
}

// โœ… GOOD: ์ฒญํฌ ๋ถ„ํ•  + yield
async function processLargeData(items: Item[]) {
  const CHUNK_SIZE = 100;

  for (let i = 0; i < items.length; i += CHUNK_SIZE) {
    const chunk = items.slice(i, i + CHUNK_SIZE);
    chunk.forEach(item => heavyComputation(item));

    // ๋ธŒ๋ผ์šฐ์ €์— ์ œ์–ด๊ถŒ ๋ฐ˜ํ™˜
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

2. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ตœ์ ํ™”

// โŒ BAD: ๋ฌด๊ฑฐ์šด ํ•ธ๋“ค๋Ÿฌ
<input onChange={(e) => {
  const value = e.target.value;
  validateAllFields();  // ๋ฌด๊ฑฐ์šด ์—ฐ์‚ฐ
  updateUI();
  sendAnalytics();
}} />

// โœ… GOOD: ๋””๋ฐ”์šด์Šค + ๋ถ„๋ฆฌ
import { useDeferredValue, useTransition } from 'react';

function SearchInput() {
  const [input, setInput] = useState('');
  const deferredInput = useDeferredValue(input);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setInput(e.target.value);  // ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ

    startTransition(() => {
      // ๋œ ๊ธ‰ํ•œ ์—…๋ฐ์ดํŠธ๋Š” transition์œผ๋กœ
      performSearch(e.target.value);
    });
  };

  return <input value={input} onChange={handleChange} />;
}

3. Web Worker ํ™œ์šฉ

// worker.ts
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

// main.ts
const worker = new Worker(new URL('./worker.ts', import.meta.url));

worker.postMessage(data);
worker.onmessage = (e) => {
  setResult(e.data);
};

CLS ์ตœ์ ํ™” (Cumulative Layout Shift)

๋ฌธ์ œ ์›์ธ

  • ํฌ๊ธฐ ๋ฏธ์ง€์ • ์ด๋ฏธ์ง€/๋น„๋””์˜ค
  • ๋™์  ์ฝ˜ํ…์ธ  ์‚ฝ์ž…
  • ์›นํฐํŠธ FOIT/FOUT
  • ์• ๋‹ˆ๋ฉ”์ด์…˜

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. ์ด๋ฏธ์ง€/๋น„๋””์˜ค ํฌ๊ธฐ ์ง€์ •

// โŒ BAD: ํฌ๊ธฐ ๋ฏธ์ง€์ •
<img src="/photo.jpg" alt="Photo" />

// โœ… GOOD: ํฌ๊ธฐ ๋ช…์‹œ
<img
  src="/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
/>

// โœ… GOOD: aspect-ratio ์‚ฌ์šฉ
<div style={{ aspectRatio: '16/9' }}>
  <img src="/video-thumb.jpg" alt="Video" style={{ width: '100%' }} />
</div>

2. ๋™์  ์ฝ˜ํ…์ธ  ๊ณต๊ฐ„ ํ™•๋ณด

// โŒ BAD: ๊ณต๊ฐ„ ์—†์ด ๋™์  ์‚ฝ์ž…
{isLoaded && <Banner />}

// โœ… GOOD: ์Šค์ผˆ๋ ˆํ†ค์œผ๋กœ ๊ณต๊ฐ„ ํ™•๋ณด
{isLoaded ? <Banner /> : <BannerSkeleton />}

// โœ… GOOD: min-height๋กœ ๊ณต๊ฐ„ ํ™•๋ณด
<div style={{ minHeight: '200px' }}>
  {isLoaded && <DynamicContent />}
</div>

3. ํฐํŠธ ๋กœ๋”ฉ

/* โœ… GOOD: font-display: swap */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
}

/* โœ… GOOD: ํด๋ฐฑ ํฐํŠธ ํฌ๊ธฐ ์กฐ์ • */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
  size-adjust: 105%;  /* ํด๋ฐฑ ํฐํŠธ์™€ ํฌ๊ธฐ ๋งž์ถค */
}

4. ์• ๋‹ˆ๋ฉ”์ด์…˜

/* โŒ BAD: ๋ ˆ์ด์•„์›ƒ ์†์„ฑ ์• ๋‹ˆ๋ฉ”์ด์…˜ */
.animate {
  transition: width 0.3s, height 0.3s, margin 0.3s;
}

/* โœ… GOOD: transform, opacity๋งŒ ์‚ฌ์šฉ */
.animate {
  transition: transform 0.3s, opacity 0.3s;
}

์ธก์ • ๋„๊ตฌ

Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v10
        with:
          urls: |
            https://example.com/
            https://example.com/dashboard
          budgetPath: ./lighthouse-budget.json
          uploadArtifacts: true

lighthouse-budget.json

[
  {
    "path": "/*",
    "timings": [
      { "metric": "largest-contentful-paint", "budget": 2500 },
      { "metric": "cumulative-layout-shift", "budget": 0.1 },
      { "metric": "interaction-to-next-paint", "budget": 200 }
    ]
  }
]

web-vitals ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

import { onCLS, onINP, onLCP } from 'web-vitals';

function sendToAnalytics(metric: Metric) {
  console.log(metric.name, metric.value);

  // Analytics ์ „์†ก
  gtag('event', metric.name, {
    value: metric.delta,
    metric_id: metric.id,
    metric_value: metric.value,
    metric_delta: metric.delta,
  });
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);

๋น ๋ฅธ ์ตœ์ ํ™” ์ฒดํฌ๋ฆฌ์ŠคํŠธ

LCP ๊ฐœ์„ 

  • LCP ์ด๋ฏธ์ง€์— priority ๋˜๋Š” preload
  • ์ด๋ฏธ์ง€ ํฌ๋งท ์ตœ์ ํ™” (WebP/AVIF)
  • ์„œ๋ฒ„ ์‘๋‹ต ์‹œ๊ฐ„ < 600ms
  • Critical CSS ์ธ๋ผ์ธ
  • ๋ Œ๋” ์ฐจ๋‹จ ๋ฆฌ์†Œ์Šค ์ œ๊ฑฐ

INP ๊ฐœ์„ 

  • Long Task > 50ms ์ œ๊ฑฐ
  • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ตœ์ ํ™”
  • ๋ฌด๊ฑฐ์šด ์—ฐ์‚ฐ Web Worker๋กœ ์ด๋™
  • useTransition, useDeferredValue ํ™œ์šฉ
  • Third-party ์Šคํฌ๋ฆฝํŠธ ์ง€์—ฐ ๋กœ๋”ฉ

CLS ๊ฐœ์„ 

  • ๋ชจ๋“  ์ด๋ฏธ์ง€/๋น„๋””์˜ค ํฌ๊ธฐ ์ง€์ •
  • ๋™์  ์ฝ˜ํ…์ธ  ๊ณต๊ฐ„ ํ™•๋ณด (์Šค์ผˆ๋ ˆํ†ค)
  • font-display: swap ์„ค์ •
  • transform/opacity๋งŒ ์• ๋‹ˆ๋ฉ”์ด์…˜

Workflow

1. ์„ฑ๋Šฅ ์ธก์ •

# Lighthouse CLI
npx lighthouse https://example.com --output=json --output-path=./lh-report.json

# ๋˜๋Š” Chrome DevTools > Lighthouse ํƒญ

2. ๋ฌธ์ œ ์ง„๋‹จ

LCP > 2.5s?
โ†’ Network ํƒญ์—์„œ LCP ๋ฆฌ์†Œ์Šค ํ™•์ธ
โ†’ ์ด๋ฏธ์ง€ ์ตœ์ ํ™” / ํ”„๋ฆฌ๋กœ๋“œ ์ ์šฉ

INP > 200ms?
โ†’ Performance ํƒญ์—์„œ Long Task ํ™•์ธ
โ†’ ํƒœ์Šคํฌ ๋ถ„ํ•  / Web Worker ์ ์šฉ

CLS > 0.1?
โ†’ Layout Shift ์›์ธ ์š”์†Œ ํ™•์ธ
โ†’ ํฌ๊ธฐ ์ง€์ • / ์Šค์ผˆ๋ ˆํ†ค ์ ์šฉ

3. ๋ชจ๋‹ˆํ„ฐ๋ง

ํ”„๋กœ๋•์…˜:
- Google Search Console Core Web Vitals
- Real User Monitoring (RUM)
- web-vitals ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

CI/CD:
- Lighthouse CI
- Performance Budget ์„ค์ •

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.