Agent skill
performance-auditing
Audit web applications for performance issues and optimize for speed, especially on Cloudflare Workers edge runtime. Use when diagnosing slow pages, optimizing load times, reducing bundle size, improving Core Web Vitals, or optimizing for edge deployment. Triggers on requests like "audit performance", "optimize speed", "improve load time", "reduce bundle size", "Core Web Vitals", or "edge optimization".
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/performance-auditing-paulirv-peabod-web
SKILL.md
Performance Auditing
Audit and optimize performance for Cloudflare Workers edge deployment.
Process
- Measure baseline - Current metrics and bottlenecks
- Analyze bundle - JavaScript size and splitting
- Optimize loading - Critical path, lazy loading
- Database queries - D1 optimization
- Caching strategy - Edge and browser caching
Core Web Vitals
| Metric | Good | Needs Work | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | ≤2.5s | ≤4.0s | >4.0s |
| FID (First Input Delay) | ≤100ms | ≤300ms | >300ms |
| CLS (Cumulative Layout Shift) | ≤0.1 | ≤0.25 | >0.25 |
| INP (Interaction to Next Paint) | ≤200ms | ≤500ms | >500ms |
JavaScript Optimization
Bundle Analysis
# Analyze bundle size
npx @next/bundle-analyzer
# Or use built-in Next.js analysis
ANALYZE=true npm run build
Code Splitting
// Dynamic imports for heavy components
import dynamic from 'next/dynamic';
const HeavyEditor = dynamic(() => import('@/components/Editor'), {
loading: () => <EditorSkeleton />,
ssr: false, // Client-only if needed
});
// Route-based splitting (automatic with App Router)
// Each route segment is a separate chunk
Tree Shaking
// Bad: imports entire library
import _ from 'lodash';
_.debounce(fn, 300);
// Good: imports only what's needed
import debounce from 'lodash/debounce';
debounce(fn, 300);
Image Optimization
Next.js Image Component
import Image from 'next/image';
// Optimized with automatic sizing
<Image
src={`/api/media/${path}`}
alt={alt}
width={800}
height={600}
sizes="(max-width: 768px) 100vw, 800px"
priority={isAboveFold} // Preload LCP images
/>
Cloudflare Image Transformations
// Use existing image.ts helper for transformations
import { getImageUrl } from '@/lib/image';
// Resize on the fly via Cloudflare
const optimizedUrl = getImageUrl(path, { width: 400, quality: 80 });
Lazy Loading
// Below-fold images
<Image loading="lazy" ... />
// Native lazy loading for img
<img loading="lazy" decoding="async" ... />
React Optimization
Memoization
// Expensive computations
const sortedArticles = useMemo(
() => articles.sort((a, b) => new Date(b.date) - new Date(a.date)),
[articles]
);
// Callback stability
const handleClick = useCallback((id) => {
setSelected(id);
}, []);
// Component memoization (use sparingly)
const ArticleCard = memo(({ article }) => { ... });
Avoiding Re-renders
// Bad: creates new object every render
<Component style={{ color: 'red' }} />
// Good: stable reference
const style = { color: 'red' };
<Component style={style} />
// Bad: inline function
<Button onClick={() => handleClick(id)} />
// Good: stable callback
const handleButtonClick = useCallback(() => handleClick(id), [id]);
<Button onClick={handleButtonClick} />
D1 Database Optimization
Indexing
-- Ensure indexes exist for common queries
CREATE INDEX IF NOT EXISTS idx_articles_published ON articles(published);
CREATE INDEX IF NOT EXISTS idx_articles_authored_on ON articles(authored_on);
CREATE INDEX IF NOT EXISTS idx_articles_slug ON articles(slug);
-- Composite indexes for common filters
CREATE INDEX IF NOT EXISTS idx_articles_pub_date
ON articles(published, authored_on DESC);
Query Optimization
// Bad: fetching all then filtering
const all = await db.prepare('SELECT * FROM articles').all();
const published = all.results.filter(a => a.published);
// Good: filter in query
const published = await db.prepare(
'SELECT * FROM articles WHERE published = 1 ORDER BY authored_on DESC LIMIT ?'
).bind(limit).all();
// Bad: N+1 queries
for (const article of articles) {
const tags = await db.prepare('SELECT * FROM tags WHERE article_id = ?').bind(article.id).all();
}
// Good: JOIN or batch query
const articlesWithTags = await db.prepare(`
SELECT a.*, GROUP_CONCAT(t.name) as tags
FROM articles a
LEFT JOIN article_tags at ON a.id = at.article_id
LEFT JOIN tags t ON at.tag_id = t.id
WHERE a.published = 1
GROUP BY a.id
`).all();
Pagination
// Offset pagination (simple but slower for large offsets)
const page = parseInt(searchParams.get('page') || '1');
const limit = 10;
const offset = (page - 1) * limit;
// Cursor pagination (better for large datasets)
const cursor = searchParams.get('cursor');
const query = cursor
? 'SELECT * FROM articles WHERE id < ? ORDER BY id DESC LIMIT ?'
: 'SELECT * FROM articles ORDER BY id DESC LIMIT ?';
Caching Strategy
Static Generation
// Force static for public pages
export const dynamic = 'force-static';
export const revalidate = 3600; // Revalidate every hour
// Or use ISR
export const revalidate = 60; // Revalidate every minute
Data Caching
// Cache database results
const cached = await caches.default.match(cacheKey);
if (cached) return cached;
const data = await fetchData();
const response = new Response(JSON.stringify(data));
await caches.default.put(cacheKey, response.clone());
return response;
Browser Caching Headers
// For static assets
return new Response(body, {
headers: {
'Cache-Control': 'public, max-age=31536000, immutable',
},
});
// For dynamic content
return new Response(body, {
headers: {
'Cache-Control': 'public, max-age=60, s-maxage=300',
},
});
Workers-Specific Optimization
CPU Time Limits
// Workers have CPU time limits (10-50ms typically)
// Avoid synchronous heavy computation
// Bad: blocking computation
const result = heavyComputation(data);
// Good: break into smaller chunks or use Durable Objects
Memory Limits
// Workers have memory limits (128MB typical)
// Stream large responses instead of buffering
// Bad: buffer entire file
const file = await bucket.get(key);
const body = await file.arrayBuffer();
// Good: stream the response
const file = await bucket.get(key);
return new Response(file.body, { headers });
Output
Provide performance audit results:
- Core Web Vitals measurements
- Bundle size analysis
- Database query analysis
- Caching recommendations
- Priority fixes with implementation code
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?