Claude Code से इमेज ऑप्टिमाइजेशन पाइपलाइन बनाएं
Claude Code से WebP/AVIF रूपांतरण, responsive images और CI budget checks ऑटोमेट करें।
इमेज ऑप्टिमाइजेशन का मतलब सिर्फ publish करने से पहले एक folder compress करना नहीं है। जैसे ही किसी site में hero image, article screenshots, product thumbnails, diagrams और social preview images बढ़ती हैं, manual process भरोसेमंद नहीं रहता। एक बड़ी PNG image Largest Contentful Paint, यानी page पर दिखने वाला सबसे बड़ा मुख्य element, बन सकती है और पूरी page speed को कमजोर कर सकती है।
इस guide में हम Claude Code को implementation partner की तरह इस्तेमाल करेंगे। sharp से AVIF, WebP और JPEG variants बनाएंगे, responsive picture component से उन्हें browser को देंगे, और CI में image budget check जोड़ेंगे। लक्ष्य सबसे छोटा file बनाना नहीं है। लक्ष्य है readable quality, fallback compatibility, predictable naming और ऐसा workflow जिसे review करना आसान हो।
Masa ने एक छोटे technical blog में पहले सिर्फ “AVIF बना दो” वाला तरीका आजमाया। Transfer size कम हुआ, लेकिन कुछ crawlers को JPEG चाहिए था, code screenshots में text soft दिखने लगा, और hero image गलती से lazy load हो गई। Stable result तब आया जब conversion, rendering और verification को अलग steps बनाया गया।
अगर आप Claude Code में नए हैं, तो पहले Claude Code getting started guide देखें। Images के बाहर performance सुधारने के लिए Claude Code performance optimization भी साथ पढ़ें।
Pipeline का overview
Claude Code को सिर्फ “images fast करो” न कहें। उसे clear pipeline दें ताकि हर file की जिम्मेदारी साफ रहे।
flowchart LR
A["original images"] --> B["sharp conversion"]
B --> C["AVIF / WebP / JPEG variants"]
C --> D["OptimizedImage component"]
D --> E["browser chooses best source"]
C --> F["manifest.json"]
F --> G["CI size budget check"]
Conversion script original images से deterministic variants बनाता है। Component browser को बताता है कि कौन-कौन से candidates उपलब्ध हैं। Budget check deploy से पहले heavy images रोकता है। इससे Claude Code के diffs छोटे रहते हैं और review में problem जल्दी दिखती है।
Coding से पहले quality rules तय करें
सभी images पर एक ही quality value लगाना आसान है, पर सही नहीं है। Photo, UI screenshot, diagram और OGP image अलग तरह से खराब होते हैं। Claude Code को code लिखवाने से पहले ऐसी table दें।
| Use case | Target | Review point |
|---|---|---|
| Hero image | 1280px या ज्यादा, AVIF/WebP first, JPEG fallback | LCP candidate, इसलिए priority load |
| Article screenshot | 640px/960px variants | छोटा UI text readable रहे |
| Gallery/list | 320px/640px variants | नीचे की images lazy load |
| Social preview | JPEG या PNG fallback | Crawlers compatibility |
June 2026 update के लिए formats की primary reference sharp official documentation है। HTML side पर MDN responsive images guide follow करें: srcset तभी उपयोगी है जब sizes actual rendered width बताता हो।
Implementation 1: sharp से variants बनाना
यह script public/images/original से jpg, jpeg, png पढ़ता है, output public/images/optimized में लिखता है और CI के लिए manifest.json बनाता है।
npm install -D sharp glob tsx
// scripts/optimize-images.ts
import path from "node:path";
import { mkdir, writeFile } from "node:fs/promises";
import { glob } from "glob";
import sharp from "sharp";
const inputDir = process.argv[2] ?? "public/images/original";
const outputDir = process.argv[3] ?? "public/images/optimized";
const widths = [320, 640, 960, 1280, 1920] as const;
const formats = ["avif", "webp", "jpeg"] as const;
const quality = { avif: 52, webp: 76, jpeg: 82 } as const;
type ImageFormat = (typeof formats)[number];
type ManifestEntry = {
src: string;
width: number;
format: string;
bytes: number;
};
const manifest: Record<string, ManifestEntry[]> = {};
function slugFromPath(filePath: string) {
const relative = path.relative(inputDir, filePath);
return relative
.replace(path.extname(relative), "")
.split(path.sep)
.join("-")
.replace(/[^a-zA-Z0-9_-]/g, "-")
.toLowerCase();
}
function extension(format: ImageFormat) {
return format === "jpeg" ? "jpg" : format;
}
async function buildVariant(filePath: string, slug: string, width: number, format: ImageFormat) {
let image = sharp(filePath).rotate().resize({ width, withoutEnlargement: true });
if (format === "avif") image = image.avif({ quality: quality.avif, effort: 4 });
if (format === "webp") image = image.webp({ quality: quality.webp, effort: 4 });
if (format === "jpeg") image = image.jpeg({ quality: quality.jpeg, mozjpeg: true });
const fileName = `${slug}-${width}w.${extension(format)}`;
const target = path.join(outputDir, fileName);
const info = await image.toFile(target);
return {
src: `/images/optimized/${fileName}`,
width: info.width,
format: extension(format),
bytes: info.size,
};
}
async function optimizeOne(filePath: string) {
const metadata = await sharp(filePath).metadata();
const sourceWidth = metadata.width ?? widths[widths.length - 1];
const targetWidths: number[] = widths.filter((width) => width <= sourceWidth);
if (!targetWidths.includes(sourceWidth)) targetWidths.push(sourceWidth);
targetWidths.sort((a, b) => a - b);
const slug = slugFromPath(filePath);
manifest[slug] = [];
for (const width of targetWidths) {
for (const format of formats) {
manifest[slug].push(await buildVariant(filePath, slug, width, format));
}
}
console.log(`optimized ${slug}: ${manifest[slug].length} files`);
}
async function main() {
await mkdir(outputDir, { recursive: true });
const pattern = `${inputDir.replace(/\\/g, "/")}/**/*.{jpg,jpeg,png}`;
const files = await glob(pattern, { nodir: true });
for (const filePath of files) {
await optimizeOne(filePath);
}
await writeFile(
path.join(outputDir, "manifest.json"),
JSON.stringify(manifest, null, 2),
);
console.log(`done: ${files.length} source images`);
}
void main().catch((error) => {
console.error(error);
process.exit(1);
});
इस script में important बात है कि original से बड़ी image न बनाई जाए। अगर 900px screenshot का नाम 1280w रख दिया गया, तो बाद में debugging मुश्किल होगी। Manifest actual width और bytes store करता है, इसलिए review data-driven हो जाता है।
Implementation 2: responsive image component
अब generated files को browser तक पहुँचाने वाला component चाहिए। यह React example है; Astro में भी वही picture, source, img structure इस्तेमाल किया जा सकता है।
// src/components/OptimizedImage.tsx
import type { ImgHTMLAttributes } from "react";
type OptimizedImageProps = Omit<
ImgHTMLAttributes<HTMLImageElement>,
"src" | "srcSet" | "sizes" | "width" | "height" | "loading"
> & {
slug: string;
alt: string;
width: number;
height: number;
widths?: number[];
sizes?: string;
priority?: boolean;
};
function srcSet(slug: string, widths: number[], extension: "avif" | "webp" | "jpg") {
return widths
.map((width) => `/images/optimized/${slug}-${width}w.${extension} ${width}w`)
.join(", ");
}
export function OptimizedImage({
slug,
alt,
width,
height,
widths = [320, 640, 960, 1280],
sizes = "(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 960px",
priority = false,
className,
...imgProps
}: OptimizedImageProps) {
const fallbackWidth = widths.includes(960) ? 960 : widths[Math.floor(widths.length / 2)];
const priorityProps = priority
? ({ fetchPriority: "high" } as ImgHTMLAttributes<HTMLImageElement>)
: {};
return (
<picture className={className}>
<source type="image/avif" srcSet={srcSet(slug, widths, "avif")} sizes={sizes} />
<source type="image/webp" srcSet={srcSet(slug, widths, "webp")} sizes={sizes} />
<img
src={`/images/optimized/${slug}-${fallbackWidth}w.jpg`}
srcSet={srcSet(slug, widths, "jpg")}
sizes={sizes}
width={width}
height={height}
alt={alt}
loading={priority ? "eager" : "lazy"}
decoding={priority ? "sync" : "async"}
{...priorityProps}
{...imgProps}
/>
</picture>
);
}
priority सिर्फ main hero या first viewport की बड़ी image पर लगाएं। सभी images eager करने से CSS, JavaScript, fonts और real LCP image network के लिए compete करते हैं। Decision के लिए web.dev LCP guide useful reference है।
Implementation 3: CI में image budget
Pipeline तब पूरी होती है जब वह अपने आप fail हो सके। Reviewer layout देखता है, पर हर generated file का size नहीं देखता। यह script manifest पढ़ता है और limit से बड़ी variants पर build रोकता है।
// scripts/check-image-budget.mjs
import { readFile } from "node:fs/promises";
const manifestUrl = new URL("../public/images/optimized/manifest.json", import.meta.url);
const manifest = JSON.parse(await readFile(manifestUrl, "utf8"));
const maxBytes = Number(process.env.IMAGE_BUDGET_BYTES ?? 240_000);
const failures = [];
for (const [slug, entries] of Object.entries(manifest)) {
for (const entry of entries) {
const isLargeCandidate = entry.width >= 1280 && ["avif", "webp", "jpg"].includes(entry.format);
if (isLargeCandidate && entry.bytes > maxBytes) {
failures.push(`${slug} ${entry.width}w.${entry.format}: ${entry.bytes} bytes`);
}
}
}
if (failures.length > 0) {
console.error(`Image budget exceeded. Limit: ${maxBytes} bytes`);
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}
console.log("Image budget check passed.");
{
"scripts": {
"images:build": "tsx scripts/optimize-images.ts",
"images:check": "node scripts/check-image-budget.mjs"
}
}
शुरुआत में 240KB जैसी simple limit रखें। Real output देखने के बाद hero, screenshot और thumbnail के लिए अलग budget बना सकते हैं।
तीन practical use cases
पहला use case technical blog है। Screenshots अक्सर high-resolution PNG होते हैं। Claude Code को content width, mobile layout और small text readability बताने से sizes और quality settings बेहतर बनती हैं।
दूसरा use case SaaS landing page है। Product screenshot या hero image अक्सर LCP होता है। उसे width, height, priority loading और fallback चाहिए; बाकी images lazy load रह सकती हैं।
तीसरा use case ecommerce या portfolio gallery है। एक ही original card, detail page, carousel और OGP में इस्तेमाल होता है। Manifest tests और admin tools को बताता है कि कौन से variants मौजूद हैं।
Common pitfalls
AVIF quality बहुत कम न करें। Photo ठीक दिख सकती है, लेकिन UI screenshot का छोटा text पढ़ना मुश्किल हो सकता है।
sizes न छोड़ें। इसके बिना browser मान सकता है कि image पूरा viewport ले रही है और जरूरत से बड़ी file download कर सकता है।
Hero image को lazy load न करें। Lazy loading नीचे की content के लिए सही है, visible LCP candidate के लिए नहीं।
Claude Code को एक ही prompt में CDN upload, admin UI, framework migration और image conversion न दें। पहले script, फिर component, फिर CI check करें।
Claude Code prompt
Create an image optimization script for jpg/png files in public/images/original.
Output files to public/images/optimized.
Generate 320, 640, 960, 1280, and 1920px widths in avif, webp, and jpg.
Do not generate a width larger than the original image.
Write manifest.json with src, width, format, and bytes.
Add package scripts named images:build and images:check.
Keep the diff minimal and do not touch unrelated files.
यह prompt paths, formats, constraints, metadata और scope साफ करता है। Boundary clear होने पर Claude Code का output review करना आसान होता है।
Verified result
Masa की test में raw 1920px PNG screenshots को इस pipeline से बदलने के बाद article image transfer आधे से भी कम हो गया। Failed experiment था code screenshots पर AVIF quality 45: bytes कम हुए, पर text soft दिखा। Stable setup में photos के लिए low-50 AVIF, UI screenshots के लिए WebP/JPEG visual check, और priority सिर्फ hero image पर रखा गया।
Next step है किसी एक image category पर npm run images:build और npm run images:check चलाना। Flow stable होने के बाद इसे Claude Code workflow automation से जोड़ें ताकि Pull Request में image regressions पकड़ी जा सकें।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Permission Receipt Pattern: scope, proof और rollback लिखना
Claude Code के लिए permission receipt: allowed actions, approval boundary, verification commands, rollback note और revenue CTA checks।
Claude Code और Codex के लिए सुरक्षित Agent Harness: permissions, verification और rollback
Claude Code और Codex agents के लिए सुरक्षित harness: permissions, plan, verification और rollback.
Claude Code Subagents गाइड: article और code work को सुरक्षित तरीके से delegate करें
Claude Code subagents से article और code work बांटें: delegation rules, prompts, pitfalls, checklist और examples.