1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2025年人気No.1のNext.jsで、最新ツールとウェブを作る! | エピソード8 パフォーマンスとSEOの最適化

Posted at

目標

  • Next.jsでパフォーマンスを向上させる方法を学ぶ。
  • next/imageで画像を最適化する。
  • SEOを強化するためにメタデータを追加する。
  • Incremental Static Regeneration (ISR)で効率的な更新を実現する。

1. 画像の最適化

ウェブサイトの読み込み速度を向上させるため、next/imageを使って画像を最適化します。

手順:

  1. public/にサンプル画像(例:sample.jpg)を追加。
  2. app/page.tsxを編集して画像を表示:
    import { supabase } from '../lib/supabase';
    import Image from 'next/image';
    
    export default async function Home() {
      const { data: posts } = await supabase
        .from('posts')
        .select('*')
        .order('created_at', { ascending: false });
    
      return (
        <div className="min-h-screen flex flex-col items-center bg-gray-100 py-8">
          <h1 className="text-4xl font-bold text-blue-600 mb-8">データベースからの投稿</h1>
          <Image
            src="/sample.jpg"
            alt="サンプル画像"
            width={600}
            height={400}
            className="mb-8 rounded"
          />
          <ul className="space-y-4 max-w-2xl w-full">
            {posts?.map((post) => (
              <li key={post.id} className="bg-white p-4 rounded shadow">
                <a href={`/posts/${post.id}`} className="text-xl font-semibold text-blue-500 hover:underline">
                  {post.title}
                </a>
                <p className="text-gray-600">{post.content}</p>
              </li>
            ))}
          </ul>
        </div>
      );
    }
    

ポイント

  • next/imageは自動で画像を圧縮し、遅延読み込み(lazy loading)を適用。
  • widthheightを指定してレイアウトシフトを防ぐ。

2. メタデータでSEOを強化

検索エンジンに最適化されたメタデータを追加します。

app/layout.tsxの更新:

import './globals.css';
import Link from 'next/link';
import { auth } from 'next-auth';
import { signIn, signOut } from 'next-auth/react';

export const metadata = {
  title: 'Next.js 2025ブログ',
  description: '2025年の最新技術で作られたブログサイト',
  openGraph: {
    title: 'Next.js 2025ブログ',
    description: 'Next.jsとSupabaseで構築されたモダンなブログ',
    url: 'https://your-site.com',
    images: ['/sample.jpg'],
  },
};

export default async function RootLayout({ children }) {
  const session = await auth();

  return (
    <html lang="ja">
      <body className="font-sans antialiased">
        <header className="bg-blue-800 text-white p-4">
          <nav className="max-w-4xl mx-auto flex justify-between items-center">
            <Link href="/" className="text-xl font-bold">ホーム</Link>
            <div className="space-x-4">
              <Link href="/about" className="hover:underline">About</Link>
              <Link href="/add-post" className="hover:underline">投稿追加</Link>
              {session ? (
                <>
                  <span>{session.user?.name}</span>
                  <button onClick={() => signOut()} className="hover:underline">ログアウト</button>
                </>
              ) : (
                <button onClick={() => signIn('google')} className="hover:underline">Googleでログイン</button>
              )}
            </div>
          </nav>
        </header>
        <main>{children}</main>
        <footer className="bg-gray-200 p-4 text-center text-gray-600">
          © 2025 Next.js学習シリーズ
        </footer>
      </body>
    </html>
  );
}

ポイント

  • openGraphでSNS共有時の表示を最適化。
  • 個別ページではgenerateMetadataを使って動的にメタデータを設定可能。

3. ISR(Incremental Static Regeneration)の利用

ISRを使えば、静的ページを定期的に更新できます。

app/page.tsxの更新:

import { supabase } from '../lib/supabase';
import Image from 'next/image';

export const revalidate = 60; // 60秒ごとに再生成

export default async function Home() {
  const { data: posts } = await supabase
    .from('posts')
    .select('*')
    .order('created_at', { ascending: false });

  return (
    <div className="min-h-screen flex flex-col items-center bg-gray-100 py-8">
      <h1 className="text-4xl font-bold text-blue-600 mb-8">データベースからの投稿</h1>
      <Image
        src="/sample.jpg"
        alt="サンプル画像"
        width={600}
        height={400}
        className="mb-8 rounded"
      />
      <ul className="space-y-4 max-w-2xl w-full">
        {posts?.map((post) => (
          <li key={post.id} className="bg-white p-4 rounded shadow">
            <a href={`/posts/${post.id}`} className="text-xl font-semibold text-blue-500 hover:underline">
              {post.title}
            </a>
            <p className="text-gray-600">{post.content}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

ポイント

  • revalidateで指定した秒数ごとにページが再生成。
  • 静的生成の速度と動的更新の柔軟性を両立。

4. パフォーマンスの確認

GoogleのLighthouseを使ってパフォーマンスを測定します。

手順:

  1. Chrome DevToolsを開き、「Lighthouse」タブを選択。
  2. http://localhost:3000でテストを実行。
  3. スコアを確認し、改善点を検討(例:画像サイズの削減、CSSの最適化)。

実践:最適化されたブログ

  • 画像: next/imageで最適化されたサンプル画像を追加。
  • SEO: メタデータで検索エンジンとSNSに対応。
  • ISR: 投稿リストを60秒ごとに更新。

確認

  • Lighthouseスコアが80以上になるように調整。

エピソード8の終了

  • パフォーマンスとSEOを最適化しました。
  • ウェブサイトがより高速で検索エンジンに優しくなりました。

次回のエピソード:Vercelにデプロイし、実際に公開します。


この記事が役に立ったと思ったら、ぜひ「いいね」を押して、ストックしていただければ嬉しいです!次回のエピソードもお楽しみに!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?