performance-budget — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited performance-budget (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Performance violations are called out before the code is written, not after.
Hard limit: 150kb gzipped per route.
Before writing any code that adds a significant dependency or duplicates logic:
📦 BUNDLE BUDGET CHECK — [route or component]
Current action: [what's being added]
Bundle impact: [estimated size or "unknown — check bundlephobia"]
If this route already has significant JS:
→ Flag for code splitting before adding more
→ Verify dynamic import() is used for non-critical components
→ Confirm tree-shaking is effective on any new importsWhen code splitting is needed:
// ❌ Static import of heavy component loaded on initial render
import { HeavyChart } from '@/components/HeavyChart'
// ✓ Dynamic import — loads only when needed
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {
loading: () => <ChartSkeleton />,
ssr: false // only if component requires browser APIs
})Flag any single import that adds > 20kb gzipped without justification.
<img> Tags🔴 PERFORMANCE STOP — Raw <img> tag detected
Replace with Next.js <Image> component:
- Automatic WebP/AVIF conversion
- Responsive srcset generation
- Lazy loading by default
- Explicit width/height prevents CLSRequired pattern:
import Image from 'next/image'
// Local image
<Image
src="/path/to/image.jpg"
alt="Descriptive alt text"
width={800} // required — prevents CLS
height={600} // required — prevents CLS
priority={true} // only for LCP / above-the-fold images
/>
// Dynamic/fill usage
<div className="relative h-64 w-full">
<Image
src={imageUrl}
alt="Description"
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw" // required with fill
/>
</div>Rules:
priority on above-the-fold images (hero, profile header) — never on below-fold imagessizes required when image width varies by viewportunoptimized={true} without flagging itnext/font Only🔴 PERFORMANCE STOP — External font CDN link detected
Google Fonts CDN links cause render-blocking requests and privacy implications.
Replace with next/font:// ❌ Never
// In <head>: <link href="https://fonts.googleapis.com/css2?family=..." />
// ✓ Required
import { Inter, Playfair_Display } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
})
const playfair = Playfair_Display({
subsets: ['latin'],
display: 'swap',
variable: '--font-playfair',
weight: ['400', '700'],
})Rules:
weight: ['100', '200', ..., '900']display: 'swap' is the default and requirednext/font/localnext/script Required🟡 PERFORMANCE FLAG — Third-party script without next/script
Script: [url or description]Required pattern:
import Script from 'next/script'
// Analytics, chat widgets, non-critical tools
<Script
src="https://example.com/script.js"
strategy="lazyOnload"
onLoad={() => console.log('loaded')}
/>
// Tools needed after page interaction
<Script
src="https://example.com/script.js"
strategy="afterInteractive"
/>
// ⚠️ Only with explicit justification
<Script
src="https://example.com/critical.js"
strategy="beforeInteractive"
// Justification: [required]
/>Flag any script using strategy="beforeInteractive" — it blocks page render and must be explicitly justified.
localStorage / sessionStorage — No Sync Access on Render🟡 PERFORMANCE FLAG — Synchronous storage access during render
localStorage/sessionStorage access during SSR causes hydration mismatch.Required pattern:
// ❌ Causes SSR mismatch
const [value, setValue] = useState(localStorage.getItem('key'))
// ✓ Safe pattern — deferred to client
const [value, setValue] = useState<string | null>(null)
useEffect(() => {
setValue(localStorage.getItem('key'))
}, [])
// ✓ Or use a hook that handles SSR safely
import { useLocalStorage } from '@/hooks/useLocalStorage'
const [value, setValue] = useLocalStorage('key', defaultValue)useEffect🟡 PERFORMANCE FLAG — Raw useEffect fetch pattern detected
useEffect for data fetching causes:
- No caching (every mount re-fetches)
- No request deduplication
- Race conditions on fast navigation
- No background revalidationRequired pattern:
// ❌ Raw useEffect fetch
useEffect(() => {
fetch('/api/trucks').then(r => r.json()).then(setTrucks)
}, [])
// ✓ SWR
import useSWR from 'swr'
const { data, error, isLoading } = useSWR('/api/trucks', fetcher, {
revalidateOnFocus: false,
dedupingInterval: 5000,
})
// ✓ React Query
import { useQuery } from '@tanstack/react-query'
const { data, isLoading, error } = useQuery({
queryKey: ['trucks'],
queryFn: fetchTrucks,
staleTime: 5 * 60 * 1000, // 5 minutes
})Server Components that fetch data directly do not need SWR/React Query — this rule applies to Client Components only.
Before any page is considered complete:
⚡ LCP CHECK REQUIRED
Every page must have an identified LCP element before shipping.
Confirm:
[ ] What is the LCP element? (image, heading, or text block)
[ ] If image: uses <Image> with priority={true}
[ ] If text: no render-blocking fonts or scripts delay its paint
[ ] No Suspense boundary wraps the LCP element
[ ] LCP element is server-rendered, not deferred to client// ❌ Barrel import — pulls in entire library
import _ from 'lodash'
import * as Icons from 'lucide-react'
// ✓ Named import — tree-shakeable
import debounce from 'lodash/debounce'
import { ChevronRight, Search } from 'lucide-react'
// ❌ shadcn barrel (if applicable)
import { Button, Card, Input } from '@/components/ui'
// ✓ Direct import
import { Button } from '@/components/ui/button'Before writing any new page or component that has performance implications:
<Image> used with explicit dimensions?strategy?If any item is "unknown," flag it before writing code.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.