Next.js統合#

@snapkit-studio/nextjsパッケージはNext.jsとの深い統合を提供し、Next.js ImageコンポーネントのAPIと完全な互換性を提供しながら、Snapkitの強力な変換機能を追加します。

インストール#

Next.jsプロジェクトにSnapkitをインストール:

npm install @snapkit-studio/nextjs
# または
yarn add @snapkit-studio/nextjs
# または
pnpm add @snapkit-studio/nextjs

クイックスタート#

環境設定#

まず、.env.localで環境変数を設定してください:

NEXT_PUBLIC_SNAPKIT_ORGANIZATION_NAME=your-organization-name
NEXT_PUBLIC_SNAPKIT_DEFAULT_QUALITY=85
NEXT_PUBLIC_SNAPKIT_DEFAULT_OPTIMIZE_FORMAT=auto

App Routerセットアップ#

ルートレイアウトでSnapkitを設定:

// app/layout.tsx
import { SnapkitProvider } from '@snapkit-studio/nextjs';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <SnapkitProvider
          baseUrl="https://snapkit-cdn.snapkit.studio"
          organizationName="your-org"
          defaultQuality={85}
          defaultFormat="auto"
        >
          {children}
        </SnapkitProvider>
      </body>
    </html>
  );
}

Pages Routerセットアップ#

Pages Routerの場合、_app.tsxにproviderを追加:

// pages/_app.tsx
import { SnapkitProvider } from '@snapkit-studio/nextjs';
import type { AppProps } from 'next/app';
 
export default function App({ Component, pageProps }: AppProps) {
  return (
    <SnapkitProvider
      baseUrl="https://snapkit-cdn.snapkit.studio"
      organizationName="your-org"
      defaultQuality={85}
      defaultFormat="auto"
    >
      <Component {...pageProps} />
    </SnapkitProvider>
  );
}

主な機能#

ドロップイン置換#

設定変更なしでNext.js Imageコンポーネントを置換:

// 前
import Image from 'next/image';
 
// 後
import { Image } from '@snapkit-studio/nextjs';
 
// 使用法は同じまま
<Image
  src="/hero.jpg"
  alt="ヒーロー画像"
  width={800}
  height={600}
  priority
/>

拡張された変換#

Next.js機能を超える強力な変換を追加:

import { Image } from '@snapkit-studio/nextjs';
 
<Image
  src="/product.jpg"
  alt="製品画像"
  width={400}
  height={300}
  transforms={{
    format: 'auto',
    quality: 90,
    sharpen: true,
    blur: 0,
    grayscale: false
  }}
  className="rounded-lg shadow-md"
/>

自動最適化#

フォーマット選択#

ブラウザサポートに基づいて自動的にモダンフォーマットを提供:

<Image
  src="/photo.jpg"
  width={600}
  height={400}
  transforms={{
    format: 'auto' // WebP、AVIF、または元のフォーマットを提供
  }}
/>

品質調整#

ネットワーク対応品質最適化:

<Image
  src="/high-res.jpg"
  width={1200}
  height={800}
  transforms={{
    quality: 'auto' // 接続速度に基づいて調整
  }}
/>

Next.js固有機能#

画像最適化#

静的インポート#

ビルド時最適化を伴う静的画像インポートの完全サポート:

import heroImage from '@/public/hero.jpg';
 
<Image
  src={heroImage}
  alt="ヒーロー"
  placeholder="blur"
  priority
  transforms={{ format: 'auto' }}
/>

動的インポート#

動的に読み込まれる画像の場合:

<Image
  src={`/products/${productId}.jpg`}
  width={500}
  height={500}
  transforms={{
    format: 'auto',
    fit: 'cover'
  }}
/>

レスポンシブ画像#

コンテナフィル#

レスポンシブコンテナベースレイアウトの場合:

<div className="relative aspect-video">
  <Image
    src="/banner.jpg"
    alt="バナー"
    fill
    sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
    className="object-cover"
    transforms={{ format: 'auto' }}
  />
</div>

アートディレクション#

異なるブレークポイント用の異なる画像:

<picture>
  <source
    media="(max-width: 768px)"
    srcSet="/mobile-hero.jpg"
  />
  <Image
    src="/desktop-hero.jpg"
    width={1920}
    height={1080}
    alt="レスポンシブヒーロー"
    transforms={{ format: 'auto' }}
  />
</picture>

パフォーマンス機能#

優先読み込み#

LCP最適化のため:

<Image
  src="/above-fold.jpg"
  width={1200}
  height={600}
  priority
  transforms={{
    format: 'auto',
    quality: 90
  }}
/>

プレースホルダー付き遅延読み込み#

スムーズな読み込み体験:

<Image
  src="/gallery-image.jpg"
  width={400}
  height={300}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,..."
  loading="lazy"
/>

設定#

next.config.js設定#

Snapkitを画像最適化ソリューションとして設定:

// next.config.js
module.exports = {
  images: {
    domains: ['snapkit-cdn.snapkit.studio'],
    loader: 'custom',
    loaderFile: './snapkit-loader.js',
  },
};

カスタムローダー#

高度な使用例のためのカスタムローダーを作成:

// snapkit-loader.js
export default function snapkitLoader({ src, width, quality }) {
  const url = new URL(`https://your-org-cdn.snapkit.studio/${src}`);
 
  const params = {
    w: width,
    q: quality || 75,
    auto: 'format',
  };
 
  Object.keys(params).forEach(key =>
    url.searchParams.set(key, params[key])
  );
 
  return url.href;
}

App Router機能#

サーバーコンポーネント#

React Server Componentsの完全サポート:

// app/gallery/page.tsx
import { Image } from '@snapkit-studio/nextjs';
 
export default async function Gallery() {
  const images = await fetchImages();
 
  return (
    <div className="grid grid-cols-3 gap-4">
      {images.map((img) => (
        <Image
          key={img.id}
          src={img.url}
          width={400}
          height={300}
          alt={img.alt}
          transforms={{ format: 'auto' }}
        />
      ))}
    </div>
  );
}

クライアントコンポーネント#

クライアントサイド機能とのシームレスな統合:

'use client';
 
import { useState } from 'react';
import { Image } from '@snapkit-studio/nextjs';
 
export default function InteractiveGallery() {
  const [selectedImage, setSelectedImage] = useState(0);
 
  return (
    <Image
      src={images[selectedImage]}
      width={800}
      height={600}
      transforms={{
        format: 'auto',
        quality: 90
      }}
    />
  );
}

高度な使用法#

メタデータ生成#

SEOとソーシャル共有のため:

// app/products/[id]/page.tsx
import { Metadata } from 'next';
 
export async function generateMetadata({ params }): Promise<Metadata> {
  const product = await getProduct(params.id);
 
  return {
    openGraph: {
      images: [{
        url: `https://your-cdn.snapkit.studio/${product.image}?w=1200&h=630&fit=cover`,
        width: 1200,
        height: 630,
      }],
    },
  };
}

ISRとSSG#

Incremental Static Regenerationの完全サポート:

// app/blog/[slug]/page.tsx
export const revalidate = 3600; // 毎時間再検証
 
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
 
  return (
    <Image
      src={post.featuredImage}
      width={1200}
      height={600}
      alt={post.title}
      priority
      transforms={{ format: 'auto' }}
    />
  );
}

Edge Runtime#

Edge runtimeに最適化:

export const runtime = 'edge';
 
export default function EdgeOptimizedPage() {
  return (
    <Image
      src="/edge-optimized.jpg"
      width={600}
      height={400}
      transforms={{
        format: 'auto',
        quality: 85
      }}
    />
  );
}

移行ガイド#

next/imageから#

最小限の変更が必要:

// ステップ1: インポートを更新
- import Image from 'next/image';
+ import { Image } from '@snapkit-studio/nextjs';
 
// ステップ2: transformsを追加(オプション)
<Image
  src="/photo.jpg"
  width={500}
  height={300}
+ transforms={{ format: 'auto' }}
/>

レガシーNext.jsから#

Next.js 12以前の場合:

// 前(Next.js 12)
<Image
  src="/photo.jpg"
  width={500}
  height={300}
  layout="responsive"
/>
 
// 後(Snapkit使用)
<Image
  src="/photo.jpg"
  width={500}
  height={300}
  sizes="100vw"
  style={{
    width: '100%',
    height: 'auto',
  }}
  transforms={{ format: 'auto' }}
/>

パフォーマンス最適化#

ビルド時最適化#

ビルド中に最適化された画像を生成:

// next.config.js
module.exports = {
  experimental: {
    optimizeImages: true,
  },
};

ランタイム最適化#

ユーザーコンテキストに基づく動的最適化:

<Image
  src="/dynamic.jpg"
  width={800}
  height={600}
  transforms={{
    format: 'auto',
    quality: typeof window !== 'undefined'
      ? navigator.connection?.saveData ? 60 : 85
      : 85,
  }}
/>

ベストプラクティス#

  1. App Routerを使用: より良いパフォーマンスのためReact Server Componentsを活用してください。

  2. キャッシングを有効化: 最適化された画像のため適切なキャッシュヘッダーを設定してください。

  3. Above-the-fold最適化: 重要な画像にはpriorityプロパティを使用してください。

  4. レスポンシブ画像: レスポンシブレイアウトには常にsizesプロパティを提供してください。

  5. フォーマット自動: Snapkitが自動的に最適なフォーマットを選択するようにしてください。

トラブルシューティング#

よくある問題#

  1. Hydrationの不一致: サーバーとクライアント間で一貫したレンダリングを確認してください。

  2. CORS問題: next.config.jsでdomainsを設定してください。

  3. ビルドエラー: すべての静的インポートが有効であることを確認してください。

  4. パフォーマンス問題: キャッシュ設定を確認してください。

リソース#