はじめに

先日、React の勉強会で、Next.js App Router の設定やファイル規約について取り上げました 🫐

App Router では、エラー・ローディング状態や、
SEO 設定の方法を簡略化してくれています!

今回は、Next.js App Router における特別ファイルの種類と使い方を調査したので、基礎的な内容をまとめました!

時間の節約になれば、嬉しいです 🙌

Next.js App Router の特別ファイルとは?

Next.js App Router の特別ファイルとは、特定の名前を持つファイルで、その名前に応じた特別な役割を果たします

https://nextjs.org/docs/app/getting-started/project-structure

https://nextjs.org/docs/app/api-reference/file-conventions

上記の公式を見るとわかりますが、
たくさんありますね、、🧐

これらのファイルでは、:

  • ルーティング
  • レイアウト
  • メタデータ
  • エラーハンドリングなど、、

Web アプリケーション開発に必要な、様々な機能を提供します!

Next.js App Router の特別ファイル・設定まとめ

それでは、主要な特別ファイル・設定について、
テンポよく紹介していきます 😎

layout.tsx(共通レイアウト)

https://nextjs.org/docs/app/api-reference/file-conventions/layout

layout ファイルは、複数のページで共有される UI コンポーネントを定義します。


export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    html lang="ja">
      body>
        header>共通ヘッダーheader>
        {children}
        footer>共通フッターfooter>
      body>
    html>
  );
}

レイアウトは入れ子にすることができ、
親レイアウトの children として子レイアウトや子ページが表示されます。
Nested Layout

ルートレイアウト(app/layout.js)は必須で、html タグと body タグを含める必要があります!

page.tsx(ページファイル)

https://nextjs.org/docs/app/getting-started/layouts-and-pages

page ファイルは、特定のルートの主要な UI コンポーネント(ページ)を定義します。

このファイルが存在するディレクトリは、公開されたルートとなります。


export default function AboutPage() {
  return (
    div>
      h1>About Ush1>
      p>会社についての情報です。p>
    div>
  );
}

この例では、/about にアクセスすると、AboutPage コンポーネントが表示されます。

route.ts(API エンドポイントの構築)

https://nextjs.org/docs/app/api-reference/file-conventions/route

route ファイルは、API エンドポイントを定義します。


import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  return NextResponse.json({ message: "Hello, world!" });
}

この例では、/api/hello にアクセスすると、{ message: "Hello, world!" } を JSON 形式で返します。

静的なページの metadata

https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-object

page ファイル、もしくは layout ファイルに、
metadata オブジェクトをエクスポートすることで、静的なメタデータを定義できます。


import { Metadata } from "next";

export const metadata: Metadata = {
  title: "商品一覧",
  description: "当店で取り扱っている商品の一覧です",
};

export default function ProductsPage() {
  return div>商品一覧ページdiv>;
}

動的なページの metadata

https://nextjs.org/docs/app/api-reference/functions/generate-metadata

動的なページの場合、
ページの内容ごとにメタデータも変化することが想定されます!

その場合、generateMetadata 関数をエクスポートすることで、動的なメタデータを生成できます。


import { Metadata } from "next";

type Props = {
  params: { id: string };
};

export async function generateMetadata({ params }: Props): PromiseMetadata> {
  
  const product = await getProduct(params.id);

  return {
    title: product.name,
    description: product.description,
  };
}

export default async function ProductPage({ params }: Props) {
  const product = await getProduct(params.id);
  return div>{product.name}の詳細ページdiv>;
}

サイトマップ

https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generating-a-sitemap-using-code-js-ts

sitemap.ts ファイルを作成することで、サイトマップを生成できます。


import { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://example.com",
      lastModified: new Date(),
      changeFrequency: "yearly",
      priority: 1,
    },
    {
      url: "https://example.com/about",
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 0.8,
    },
    {
      url: "https://example.com/blog",
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 0.5,
    },
  ];
}

もし、サイトマップ自体について知りたい場合は、下記もチェックしてみてください:

https://zenn.dev/kazzyfrog/articles/about-sitemap-with-nextjs

このファイルにより、/sitemap.xml エンドポイントが自動的に生成されます!

robots txt

https://nextjs.org/docs/app/api-reference/file-conventions/metadata/robots#generate-a-robots-file

robots.ts ファイルで、検索エンジンのクローラー向けの指示を設定できます。


import { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "https://zenn.dev/",
      disallow: "/private/",
    },
    sitemap: "https://example.com/sitemap.xml",
  };
}

このファイルにより、/robots.txt エンドポイントが自動的に生成されます。

JSON-LD (構造化データ)

https://nextjs.org/docs/app/building-your-application/optimizing/metadata#json-ld

JSON-LD は、検索エンジンがウェブページの内容を理解するのに役立つ構造化データです。

特別ファイルではありませんが、メタデータやコンポーネント内で定義することができます。


import { product } from "./data";

export default function Page({ params }) {
  const productData = product(params.id);

  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "Product",
    name: productData.name,
    description: productData.description,
    image: productData.image,
    offers: {
      "@type": "Offer",
      price: productData.price,
      priceCurrency: "JPY",
    },
  };

  return (
    >
      script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      h1>{productData.name}h1>
      {}
    >
  );
}

もし、JSON-LD 自体について知りたい場合は、下記もチェックしてみてください:

https://zenn.dev/kazzyfrog/articles/about-json-ld

ローディング(読み込み中)のページ

loading ファイルには、ページやレイアウトがロード中に表示される UI を定義します。


export default function Loading() {
  return (
    div className="loading-spinner">
      p>データを読み込み中...p>
    div>
  );
}

このファイルは React の Suspense と組み合わせて使用され、
ページがデータをロードしている間にのみ、自動で表示されます。

エラーページ

error ファイルは、ページやレイアウトでエラーが発生した場合に表示される UI を定義します。


"use client";

import { useEffect } from "react";

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  useEffect(() => {
    
    console.error(error);
  }, [error]);

  return (
    div>
      h2>エラーが発生しましたh2>
      button onClick={() => reset()}>再試行button>
    div>
  );
}

このファイルは 'use client' ディレクティブが必須で、クライアントコンポーネントとして機能します。

存在しないページ(404 Not Found)

not-found ファイルは、ページが見つからない場合(404 エラー)に表示される UI を定義します。


export default function NotFound() {
  return (
    div>
      h2>ページが見つかりませんh2>
      p>お探しのページは存在しないか、移動した可能性があります。p>
    div>
  );
}

静的な OGP 画像ファイル

TOP ページ用の OG 画像のように、静的に用意した画像の場合は、
opengraph-image.png などの画像ファイルを、app 直下に配置するだけで、自動で設定されます!

動的な OGP 画像の自動生成

ブログ記事のページなどの動的なページでは、
opengraph-image.tsx または twitter-image.tsx ファイルを使って、動的な OGP 画像を生成できます!


import { ImageResponse } from "next/server";

export const runtime = "edge";
export const contentType = "image/png";
export const size = {
  width: 1200,
  height: 630,
};

export default async function Image({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);

  return new ImageResponse(
    (
      div
        style={{
          display: "flex",
          color: "white",
          background: "linear-gradient(to right, #0099F7, #F11712)",
          width: "100%",
          height: "100%",
          padding: "50px",
          textAlign: "center",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        div style={{ fontSize: 60, fontWeight: "bold" }}>{post.title}div>
      div>
    ),
    {
      ...size,
    }
  );
}

opengraph-image.tsxtwitter-image.tsx を分ける必要がない場合は、
opengraph-image.tsx のみを配置しれば、両方に適用されますよ 👍

そして、もし、画像生成機能の ImageResponse 自体について知りたい場合は、
下記もチェックしてみてください:

https://zenn.dev/kazzyfrog/articles/next-image-response-guide

アイコン系(favicon, apple-icon など)

サイトのロゴとなるアイコン系の画像も、
app 直下に配置することで設定可能です:

  • apple-icon.png
  • favicon.ico
  • icon.svg
  • manifest.json

もし、それそれのアイコンの必要性について確認したい場合は、下記もチェックしてみてください:

https://zenn.dev/kazzyfrog/articles/about-favicon-with-nextjs

おわりに

最後まで読んでいただき、ありがとうございます 🥳

下記の、React ハンズオン勉強会での、振り返りのような記事ですが、
少しでも参考になれば、嬉しいです!

https://b13o.com/services/handson-workshop

そして、もし、間違いや補足情報などがありましたら、
ぜひコメントを追加してください!

Happy Hacking 🙂

フラッグシティパートナーズ海外不動産投資セミナー 【DMM FX】入金

Source link