performance-optimization
Optimizes application performance across frontend, backend, queries, and databases. Use when performance requirements exist, when you suspect performance regressions, when Core Web Vitals or load times need improvement, when N+1 query patterns need fixing, or when profiling reveals bottlenecks.
DeepseekModel
キュレーション済みスキル
品質 優秀 · 90
v1.0.0
取得
https://deepseekmodel.com/api/download.php?id=addyosmani-agent-skills-skills-performance-optimization-skill-md&format=skill
ダウンロード .skill
標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name performance-optimization description Optimizes application performance across frontend, backend, queries, and databases. Use when performance requirements exist, when you suspect performance regressions, when Core Web Vitals or load times need improvement, when N+1 query patterns need fixing, or when profiling reveals bottlenecks. Performance Optimization Overview Measure before optimizing. Performance work without measurement is guessing — and guessing leads to premature optimization that adds complexity without improving what matters. Profile first, identify the actual bottleneck, fix it, measure again. Optimize only what measurements prove matters. When to Use Performance requirements exist in the spec (load time budgets, response time SLAs) Users or monitoring report slow behavior Core Web Vitals scores are below thresholds You suspect a change introduced a regression Building features that handle large datasets or high traffic When NOT to use: Don't optimize before you have evidence of a problem. Premature optimization adds complexity that costs more than the performance it gains. Core Web Vitals Targets Metric Good Needs Improvement Poor LCP (Largest Contentful Paint) ≤ 2.5s ≤ 4.0s > 4.0s INP (Interaction to Next Paint) ≤ 200ms ≤ 500ms > 500ms CLS (Cumulative Layout Shift) ≤ 0.1 ≤ 0.25 > 0.25 The Optimization Workflow 1. MEASURE → Establish baseline with real data 2. IDENTIFY → Find the actual bottleneck (not assumed) 3. FIX → Address the specific bottleneck 4. VERIFY → Measure again; keep or revert 5. GUARD → Add monitoring or tests to prevent regression Step 1: Measure Two complementary approaches — use both: Synthetic (Lighthouse, DevTools Performance tab): Controlled conditions, reproducible. Best for CI regression detection and isolating specific issues. RUM (web-vitals library, CrUX): Real user data in real conditions. Required to validate that a fix actually improved user experience. Frontend: # Synthetic: Lighthouse in Chrome DevTools (or CI) # Chrome DevTools → Performance tab → Record # Chrome DevTools MCP → Performance trace # RUM: Web Vitals library in code import { onLCP, onINP, onCLS } from 'web-vitals' ; onLCP(console.log); onINP(console.log); onCLS(console.log); Backend: # Response time logging # Application Performance Monitoring (APM) # Database query logging with timing # Simple timing console.time( 'db-query' ); const result = await db.query(...); console.timeEnd( 'db-query' ); Where to Start Measuring Use the symptom to decide what to measure first: What is slow? ├── First page load │ ├── Large bundle? --> Measure bundle size, check code splitting │ ├── Slow server response? --> Measure TTFB in DevTools Network waterfall │ │ ├── DNS long? --> Add dns-prefetch / preconnect for known origins │ │ ├── TCP/TLS long? --> Enable HTTP/2, check edge deployment, keep-alive │ │ └── Waiting (server) long? --> Profile backend, check queries and caching │ └── Render-blocking resources? --> Check network waterfall for CSS/JS blocking ├── Interaction feels sluggish │ ├── UI freezes on click? --> Profile main thread, look for long tasks (>50ms) │ ├── Form input lag? --> Check re-renders, controlled component overhead │ └── Animation jank? --> Check layout thrashing, forced reflows ├── Page after navigation │ ├── Data loading? --> Measure API response times, check for waterfalls │ └── Client rendering? --> Profile component render time, check for N+1 fetches └── Backend / API ├── Single endpoint slow? --> Profile database queries, check indexes ├── All endpoints slow? --> Check connection pool, memory, CPU └── Intermittent slowness? --> Check for lock contention, GC pauses, external deps Step 2: Identify the Bottleneck Common bottlenecks by category: Frontend: Symptom Likely Cause Investigation Slow LCP Large images, render-blocking resources, slow server Check network waterfall, image sizes High CLS Images without dimensions, late-loading content, font shifts Check layout shift attribution Poor INP Heavy JavaScript on main thread, large DOM updates Check long tasks in Performance trace Slow initial load Large bundle, many network requests Check bundle size, code splitting Backend: Symptom Likely Cause Investigation Slow API responses N+1 queries, missing indexes, unoptimized queries Check database query log Memory growth Leaked references, unbounded caches, large payloads Heap snapshot analysis CPU spikes Synchronous heavy computation, regex backtracking CPU profiling High latency Missing caching, redundant computation, network hops Trace requests through the stack Step 3: Fix Common Anti-Patterns N+1 Queries (Backend) // BAD: N+1 — one query per task for the owner const tasks = await db. tasks . findMany (); for ( const task of tasks) { task. owner = await db. users . findUnique ({ where : { id : task. ownerId } }); } // GOOD: Single query with join/include const tasks = await db. tasks . findMany ({ include : { owner : true }, }); Unbounded Data Fetching // BAD: Fetching all records const allTasks = await db. tasks . findMany (); // GOOD: Paginated with limits const tasks = await db. tasks . findMany ({ take : 20 , skip : (page - 1 ) * 20 , orderBy : { createdAt : 'desc' }, }); Queries That Ignore Their Index "Add an index" is the guess. The query plan is the measurement: EXPLAIN ANALYZE SELECT id, title FROM tasks WHERE owner_id = 42 ORDER BY created_at DESC LIMIT 20 ; Three things in the output decide the fix: What you see What it means Seq Scan on a large table where you expected an index No usable index for this predicate Estimated rows= off from actual by an order of magnitude Stale statistics; the planner is choosing on bad information A Sort node above the scan The index covers the filter but not the ORDER BY Index for the shape of the query , not the column in isolation. In a composite index, equality columns come first, then the range or sort column: CREATE INDEX idx_tasks_owner_created ON tasks (owner_id, created_at DESC ); When an index will not help: Situation Why Low selectivity, querying the dominant value (a status column that is 95% active , filtered on active ) A sequential scan is genuinely cheaper; the planner will ignore the index. Filtering on the rare value is the opposite case, and a partial index serves it well Leading wildcard ( LIKE '%term' ) A B-tree cannot seek without a prefix; needs trigram or full-text Function on the column ( WHERE lower(email) = ? ) The plain column index is unusable; index the expression instead Write-heavy table Every index is a tax on every INSERT / UPDATE ; measure the write cost, not just the read gain Re-run EXPLAIN ANALYZE after. An index that did not change the plan is a revert (Step 4), and it is not free: it still costs on every write. Connection Pool Exhaustion The signature is distinctive: every endpoint slows at once, the slow time is spent waiting for a connection rather than executing, and the database reports mostly idle sessions. // BAD: a pool per request or per module — under serverless this multiplies // by instance count and exhausts the database's connection limit // GOOD: one pool per process, sized against the database's ceiling const pool = new Pool ({ max : 10 , // instances × max must stay under max_connections idleTimeoutMillis : 30_000 , connectionTimeoutMillis : 5_000 , // fail fast instead of queueing forever }); Bigger is not faster. A pool larger than what the database can execute concurrently just relocates the queue from your app to the database, where it is harder to see. When instance count is unbounded (serverless, autoscaling), a proxy that multiplexes connections (pgbouncer, RDS Proxy) is the fix, not a higher max . Missing Image Optimization (Frontend) <!-- BAD: No dimensions, no format optimization --> < img src = "/hero.jpg" /> <!-- GOOD: Hero / LCP image — art direction + resolution switching, high priority --> <!-- Two techniques combined: - Art direction (media): different crop/composition per breakpoint - Resolution switching (srcset + sizes): right file size per screen density --> < picture > <!-- Mobile: portrait crop (8:10) --> < source media = "(max-width: 767px)" srcset = "/hero-mobile-400.avif 400w, /hero-mobile-800.avif 800w" sizes = "100vw" width = "800" height = "1000" type = "image/avif" /> < source media = "(max-width: 767px)" srcset = "/hero-mobile-400.webp 400w, /hero-mobile-800.webp 800w" sizes = "100vw" width = "800" height = "1000" type = "image/webp" /> <!-- Desktop: landscape crop (2:1) --> < source srcset = "/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1600.avif 1600w" sizes = "(max-width: 1200px) 100vw, 1200px" width = "1200" height = "600" type = "image/avif" /> < source srcset = "/hero-800.webp 800w, /hero-1200.webp 1200w, /hero-1600.webp 1600w" sizes = "(max-width: 1200px) 100vw, 1200px" width = "1200" height = "600" type = "image/webp" /> < img src = "/hero-desktop.jpg" width = "1200" height = "600" fetchpriority = "high" alt = "Hero image description" /> </ picture > <!-- GOOD: Below-the-fold image — lazy loaded + async decoding --> < img src = "/content.webp" width = "800" height = "400" loading = "lazy" decoding = "async" alt = "Content image description" /> Unnecessary Re-renders (React) // BAD: Creates new object on every render, causing children to re-render function TaskList ( ) { return < TaskFilters options = {{ sortBy: ' date ', order: ' desc ' }} /> ; } // GOOD: Stable reference const DEFAULT_OPTIONS = { sortBy : 'date' , order : 'desc' } as const ; function TaskList ( ) { return < TaskFilters options = {DEFAULT_OPTIONS} /> ; } // Use React.memo for expensive components const TaskItem = React . memo ( function TaskItem ( { task }: Props ) { return < div > {/* expensive render */} </ div > ; }); // Use useMemo for expensive computations function TaskStats ( { tasks }: Props ) { const stats = useMemo ( () => calculateStats (tasks), [tasks]); return < div > {stats.completed} / {stats.total} </ div > ; } Large Bundle Size // Modern bundlers (Vite, webpack 5+) handle named imports with tree-shaking automatically, // provided the dependency ships ESM and is marked `sideEffects: false` in package.json. // Profile before changing import styles — the real gains come from splitting and lazy loading. // GOOD: Dynamic import for heavy, rarely-used features const ChartLibrary = lazy ( () => import ( './ChartLibrary' )); // GOOD: Route-level code splitting wrapped in Suspense const SettingsPage = lazy ( () => import ( './pages/Settings' )); function App ( ) { return ( < Suspense fallback = { < Spinner /> }> < SettingsPage /> </ Suspense > ); } Missing Caching (Backend) Cache what is expensive to produce and read far more often than it changes. Caching a query that was already fast adds a network hop, a staleness bug, and an eviction policy to maintain, in exchange for nothing. Pick the layer deliberately: Layer Visible to Use when Cost In-process ( Map , LRU) One instance Small, hot, per-instance staleness is acceptable Each instance drifts independently; invalidation reaches only one Shared (Redis, Memcached) All instances Instances must agree, or the value is expensive to recompute A network hop, and another service to run and monitor CDN / edge Everyone, per URL Responses are public and identical for a given key Invalidation is the hard part; assume you cannot recall a bad response quickly // Cache frequently-read, rarely-changed data const CACHE_TTL = 5 * 60 * 1000 ; // 5 minutes let cachedConfig : AppConfig | null = null ; let cacheExpiry = 0 ; async function getAppConfig ( ): Promise < AppConfig > { if (cachedConfig && Date . now () < cacheExpiry) { return cachedConfig; } cachedConfig = await db. config . findFirst (); cacheExpiry = Date . now () + CACHE_TTL ; return cachedConfig; } // HTTP caching headers for static assets app. use ( '/static' , express. static ( 'public' , { maxAge : '1y' , // Cache for 1 year immutable : true , // Never revalidate (use content hashing in filenames) })); // Cache-Control for API responses res. set ( 'Cache-Control' , 'public, max-age=300' ); // 5 minutes Key design decides correctness. Every input that changes the response belongs in the key: tenant, locale, permissions, feature flags. A key that omits the viewer is how one user's data gets served to another, and that ships as a performance win. Choose one invalidation strategy, not three: Strategy Trade-off TTL Simplest. You accept staleness up to the TTL, so state the acceptable window explicitly Event or tag based Fresh on write, but writers now have to know the cache topology Versioned keys ( user:42:profile:v7 ) Never invalidate, just stop reading old keys. Costs memory until eviction Guard against the stampede. A hot key expires, every concurrent request misses together, and the origin takes the full load at once, which is how a cache turns into an outage instead of preventing one. Serve stale while a single request recomputes ( stale-while-revalidate ), or coalesce concurrent misses behind one in-flight promise so N waiters cause one recompute. Do not cache: anything whose staleness is a correctness bug (balances, permissions, inventory at checkout), or per-user data under a key that does not identify the user. See ../../references/performance-checklist.md for request coalescing, write strategies, negative caching, and the cache checklist. Step 4: Verify (Keep or Revert) A fix is a hypothesis until you re-measure. This step decides whether it survives. Re-measure the way you measured the baseline: same command, same conditions, same fixed budget (wall-clock, sample count, or request count). A baseline taken on a cold cache against a result taken on a warm one measures the cache, not your change. Change one thing at a time. Three optimizations landed together produce one number, and you cannot attribute it. If they must ship together, measure each in isolation first.
このスキルを起動するキーワード。クリックでコピーできます。
このスキルにはトリガーワードがありません。
ダウンロードした .skill に含まれるフィールド。
| フィールド | 説明 |
|---|---|
| format | フォーマット識別子(skill/v1) |
| skill_id | スキル固有 ID |
| name | スキル名 |
| version | バージョン |
| description | 説明 |
| category | カテゴリ(配列) |
| trigger_words | トリガーワード |
| tags | タグ |
| source | ソース |
| source_url | ソース URL(本ページ) |
| exported_at | エクスポート日時(ダウンロード毎) |
| system_prompt | システムプロンプト本文 |
| model_config | モデル設定:provider / model / temperature / max_tokens / top_p |
| examples | サンプル |
| install_guide | 各プラットフォームの導入説明(Coze / Dify / Claude / カスタム) |