Advanced

Development dengan Claude Code

Pelajari tentang development menggunakan Claude Code. Dilengkapi tips praktis dan contoh kode.

gambaroptimasipipelineでtampilan速度を劇的にpeningkatan

gambar Webhalaman 転送量 大部分 占め.Claude Code 使って、自動的 gambar optimasi pipeline pembangunanすれば、手作業 負担 tidak performa peningkatan bisa dilakukan.

pembangunan gambarkonversiscript

> sharp 使ったgambaroptimasiscript buatkan.
> WebP・AVIFkonversi、リサイズ、metadatapenghapusan otomatisasiして。
// scripts/optimize-images.ts
import sharp from 'sharp';
import { globSync } from 'glob';
import { mkdirSync, existsSync } from 'fs';
import path from 'path';

interface ImageConfig {
  widths: number[];
  formats: ('webp' | 'avif' | 'jpg')[];
  quality: Record<string, number>;
}

const config: ImageConfig = {
  widths: [320, 640, 960, 1280, 1920],
  formats: ['avif', 'webp', 'jpg'],
  quality: { avif: 50, webp: 75, jpg: 80 },
};

async function optimizeImage(inputPath: string, outputDir: string) {
  const name = path.basename(inputPath, path.extname(inputPath));
  
  for (const format of config.formats) {
    for (const width of config.widths) {
      const outputPath = path.join(outputDir, `${name}-${width}w.${format}`);
      
      await sharp(inputPath)
        .resize(width, undefined, { withoutEnlargement: true })
        .toFormat(format, { quality: config.quality[format] })
        .toFile(outputPath);
    }
  }
}

async function main() {
  const images = globSync('src/assets/images/**/*.{jpg,jpeg,png}');
  const outputDir = 'public/images/optimized';
  
  if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });

  for (const img of images) {
    console.log(`optimasi中: ${img}`);
    await optimizeImage(img, outputDir);
  }
  
  console.log(`✅ ${images.length}枚 gambar optimasiしま`);
}

main();

レスポンシブgambarkomponen

// components/OptimizedImage.tsx
interface OptimizedImageProps {
  src: string;
  alt: string;
  widths?: number[];
  sizes?: string;
  className?: string;
  loading?: 'lazy' | 'eager';
  priority?: boolean;
}

export function OptimizedImage({
  src,
  alt,
  widths = [320, 640, 960, 1280],
  sizes = '(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw',
  className,
  loading = 'lazy',
  priority = false,
}: OptimizedImageProps) {
  const baseName = src.replace(/\.(jpg|jpeg|png)$/, '');

  const avifSrcSet = widths
    .map(w => `/images/optimized/${baseName}-${w}w.avif ${w}w`)
    .join(', ');

  const webpSrcSet = widths
    .map(w => `/images/optimized/${baseName}-${w}w.webp ${w}w`)
    .join(', ');

  const jpgSrcSet = widths
    .map(w => `/images/optimized/${baseName}-${w}w.jpg ${w}w`)
    .join(', ');

  return (
    <picture>
      <source type="image/avif" srcSet={avifSrcSet} sizes={sizes} />
      <source type="image/webp" srcSet={webpSrcSet} sizes={sizes} />
      <img
        src={`/images/optimized/${baseName}-960w.jpg`}
        srcSet={jpgSrcSet}
        sizes={sizes}
        alt={alt}
        loading={priority ? 'eager' : loading}
        decoding={priority ? 'sync' : 'async'}
        fetchPriority={priority ? 'high' : undefined}
        className={className}
      />
    </picture>
  );
}

遅延loadingとplaceholder

// ぼかしplaceholder付き遅延loading
function BlurImage({ src, alt, blurDataUrl }: {
  src: string;
  alt: string;
  blurDataUrl: string;
}) {
  const [loaded, setLoaded] = useState(false);

  return (
    <div className="relative overflow-hidden">
      {/* ぼかしプレースホルダー */}
      <img
        src={blurDataUrl}
        alt=""
        aria-hidden="true"
        className={`absolute inset-0 h-full w-full object-cover transition-opacity duration-300
          ${loaded ? 'opacity-0' : 'opacity-100'}`}
        style={{ filter: 'blur(20px)', transform: 'scale(1.1)' }}
      />
      {/* 本画像 */}
      <img
        src={src}
        alt={alt}
        loading="lazy"
        onLoad={() => setLoaded(true)}
        className={`h-full w-full object-cover transition-opacity duration-300
          ${loaded ? 'opacity-100' : 'opacity-0'}`}
      />
    </div>
  );
}

Generate Blur Placeholder

// scripts/generate-blur.ts
import sharp from 'sharp';

async function generateBlurDataUrl(imagePath: string): Promise<string> {
  const buffer = await sharp(imagePath)
    .resize(10, 10, { fit: 'inside' })
    .blur()
    .toBuffer();
  
  return `data:image/jpeg;base64,${buffer.toString('base64')}`;
}

Integrasi ke Build Pipeline

{
  "scripts": {
    "images": "tsx scripts/optimize-images.ts",
    "images:blur": "tsx scripts/generate-blur.ts",
    "prebuild": "npm run images && npm run images:blur",
    "build": "astro build"
  }
}

Summary

Untuk gambaroptimasiはfontoptimasiと並んで、tampilan速度peningkatanに最も効果的な施策です。Claude Codeを使えば、sharp を使ったkonversiscriptからレスポンシブgambarkomponenまで一貫してpembangunanできます。bundle分析と組み合わせて、総合的なperformapeningkatanを進めましょう。gambaroptimasiの詳細, lihat web.dev Images Guide.

#Claude Code #image optimization #WebP #AVIF #performance