بنقرة واحدة
bundle-optimization
Guide for optimizing bundle size and images. Server Components by default, use image quality caps.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Guide for optimizing bundle size and images. Server Components by default, use image quality caps.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Guide for adding environment variables. Use when adding new env vars to ensure all 5 locations are updated (code, env files, Coolify, workflow, GitHub secrets).
Enforce the internal API proxy layer pattern. Use when adding API endpoints, fetching data from backend, implementing HMAC signing, or working with lib/api/* or app/api/*.
Best practices for React 19 and Next.js 16 App Router. Use when creating components, hooks, or pages. Enforces server-first rendering, proper client boundaries, and modern React patterns.
MANDATORY checklist before writing ANY new code. Use this skill FIRST before implementing any feature, component, utility, type, or hook. Enforces DRY principle and existing pattern reuse.
Evaluate external PR suggestions (Gemini, CodeRabbit) against project conventions. Use when asked to review or agree with external code review comments.
Guide for CSP, security headers, and external scripts. Use fetchWithHmac for APIs, safeFetch for external services.
| name | bundle-optimization |
| description | Guide for optimizing bundle size and images. Server Components by default, use image quality caps. |
Guide for optimizing bundle size and image performance. Ensure fast page loads and good Core Web Vitals.
yarn analyze # Full bundle analysis (client + server)
yarn analyze:browser # Browser bundles only
yarn analyze:server # Server bundles only
yarn analyze:experimental # Next.js 16.1 interactive analyzer (Turbopack-compatible)
External images use quality caps to reduce bandwidth:
| Context | Quality | Use Case |
|---|---|---|
| Default | 50 | Standard images |
| Priority/LCP | 50 | Above-the-fold images |
Note: LCP quality was reduced from 60 to 50 based on Lighthouse analysis showing 159 KiB potential savings. See
utils/image-quality.tsfor details.
import {
getOptimalImageQuality,
getOptimalImageSizes,
} from "@utils/image-quality";
// Get quality based on context (uses options object)
const heroQuality = getOptimalImageQuality({ isPriority: true }); // 50 (LCP external)
const cardQuality = getOptimalImageQuality({ isPriority: false }); // 50 (standard external)
// Get responsive sizes
const sizes = getOptimalImageSizes("card");
// "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
import Image from "next/image";
import { getOptimalImageQuality, getOptimalImageSizes } from "@utils/image-quality";
// ✅ CORRECT - Using helpers with options object
<Image
src={event.imageUrl}
alt={event.title}
width={400}
height={300}
quality={getOptimalImageQuality({ isPriority: false })}
sizes={getOptimalImageSizes("card")}
loading="lazy"
/>
// ✅ CORRECT - Priority for LCP images
<Image
src={event.imageUrl}
alt={event.title}
fill
priority
quality={getOptimalImageQuality({ isPriority: true })}
sizes={getOptimalImageSizes("hero")}
/>
For unreliable image sources:
import { useImageRetry } from "@hooks/useImageRetry";
function EventImage({ src, alt }) {
// useImageRetry takes optional maxRetries (default: 2)
const {
retryCount,
hasError,
imageLoaded,
showSkeleton,
handleError,
getImageKey,
} = useImageRetry();
return (
<Image
key={getImageKey(src)} // Forces re-render on retry
src={src}
alt={alt}
onError={handleError}
// Exponential backoff on retry (1s, 2s, 4s...)
/>
);
}
import { preloadImage } from "@utils/image-preload";
// Preload LCP image
preloadImage(heroImageUrl);
Caution: preloadImage has coupling to internal Next.js _next/image URL format. Use sparingly.
For static assets that need cache busting, add a version query parameter:
// Pattern: Add version param for cache busting
// BUILD_VERSION is available via scripts/generate-sw.mjs
const buildVersion = process.env.BUILD_VERSION || Date.now().toString();
function getVersionedUrl(path: string): string {
return `${path}?v=${buildVersion}`;
}
// Usage
const url = getVersionedUrl("/static/data.json");
// "/static/data.json?v=1234567890"
BUILD_VERSION resolves to:
import dynamic from "next/dynamic";
// ✅ CORRECT - Lazy load heavy components
const HeavyChart = dynamic(() => import("@components/ui/HeavyChart"), {
loading: () => <ChartSkeleton />,
});
// ❌ WRONG - ssr: false in Server Components
// Don't use ssr: false inside Server Components
// Instead, create a client component wrapper
Most components should be Server Components (no JS shipped):
// ✅ Server Component - Zero JS
export function EventList({ events }) {
return (
<ul>
{events.map((event) => (
<li key={event.id}>{event.title}</li>
))}
</ul>
);
}
"use client";
// Only add "use client" for:
// - useState, useEffect
// - Event handlers (onClick, etc.)
// - Browser APIs
// - Third-party client-only libraries
Monitor these in bundle analysis:
| Metric | Target | Action if Exceeded |
|---|---|---|
| First Load JS | < 100kB | Split or lazy load |
| Shared chunks | < 50kB | Check for large deps |
| Page-specific | < 30kB | Review page imports |
yarn analyzeindex.ts re-exports) → NEVER create barrel files that re-export "use client" components from different route contexts. In Next.js RSC, every "use client" module re-exported from a barrel gets registered in the client-reference-manifest of every route that imports from that barrel — even if the component is never used. optimizePackageImports only applies to npm packages, not local barrels. Always use direct file imports.components/ui/sponsor/index.ts re-exported 7 components. Routes like /[place] only needed SponsorBannerSlot, but importing from the barrel also pulled CheckoutButton, PlaceSelector, and PricingSectionClient (all "use client") into the manifest — adding 24 KB of bloat.
// ❌ WRONG: Barrel import pulls ALL exports into manifest
import { SponsorBannerSlot } from "@components/ui/sponsor";
// → Also registers CheckoutButton, PlaceSelector, PricingSectionClient
// ✅ CORRECT: Direct import only registers what's needed
import SponsorBannerSlot from "@components/ui/sponsor/SponsorBannerSlot";
Fix: Always use direct file imports for local components. Reserve barrels only for npm-published packages.
getOptimalImageQuality?getOptimalImageSizes?yarn analyze for new dependencies?index.ts) re-exporting "use client" components from different routes?getVersionedUrl for static assets?