【Next.js / App Router】自分がいつも行っているSEO対策TODOリスト

【Next.js / App Router】自分がいつも行っているSEO対策TODOリスト

こんにちは!@Ryo54388667です!☺️

普段は都内でエンジニアとして業務をしてます!

主にTypeScriptやNext.jsといった技術を触っています。

今回はApp Routerを利用した時、自分がいつも行っているSEO対策を紹介していきます!


宣伝

新米エンジニアの転職先を探しています!


TDH(title, description, h1)の設定

#

概要

#

Titleは、HTMLのtitleタグを指します。ブラウザのタブ名に反映されるだけではなく、クローラーに適切に伝えるためにも重要な要素となっています。ベストプラクティスについては下記のリンクに記載されています。

https://developers.google.com/search/docs/appearance/title-link?hl=ja


続いて、descriotionは、<meta name="description" content=”{ここの内容}”> を指します。主にページの要約を書きます。

ターゲットとなるキーワードをこちらに盛り込むと良いと言われています。ベストプラクティスについては、下記のリンクを見てください。

https://developers.google.com/search/docs/appearance/snippet?hl=ja


h1についてはページのタイトルにあたるものを設定してください。


実装

#

ルートレイアウトでテンプレートを設定します。%s を利用するとネストしたレイアウトで設定したtitleが差し替えられます。

layout.tsx
Copied!
export const metadata: Metadata = {
  title: {
    template: `%s | ${SITE_TITLE}`,
    default: "Home",
  },
  description: SITE_DESCRIPTION,
  metadataBase: new URL(baseURL)
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    ...
  );
}

動的にメタ情報を設定する場合はgenerateMetadataを利用します。

page.tsx
Copied!
export async function generateMetadata(
  { params }: { params: { blogId: string } },
): Promise<Metadata> {
  const blogId = params.blogId
  const data = await getBlogById(blogId)

  return {
    title: data.title,
    description: data.description
  }
}

詳しくはZennで書きましたので、こちらもご覧ください!

h1については通常どおり、bodyタグ内で記述すればOKです!


Sitemapの作成

#

概要

#

クローラーに効率的にサイトをクローリングしてもらうために利用します。ベストプラクティスについては下記のリンクを見てください。

https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview?hl=ja


実装

#

Next.jsのApp Routerでの実装方法について紹介します。

※ v13.3.0以上


sitemap.ts
Copied!
import { MetadataRoute } from "next";
import { baseURL } from "@/config";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const staticPaths = [
    {
      url: `${baseURL}/blogs`,
      lastModified: new Date()
    },
    {
      url: `${baseURL}/about`,
      lastModified: new Date()
    }
  ]


  const blogList = await getAllBlogList()

  const dynamicPaths = blogList.map((content) => {
    return {
      url: `${baseURL}/blogs/${content.id}`,
      lastModified: content.publishedAt || content.updatedAt
    }
  })

  return [...staticPaths, ...dynamicPaths]
}

構造化データJSON-LDの設定

#

概要

#

特定のスニペットを記述すると、Googleの検索結果の見え方を工夫できる機能です。例えば、某飲食店評価サイトの検索結果は店名と同時に評価などがGoogleの検索結果に表示されます。特定のスニペットを利用すると、検索結果を工夫することができ、CTRの改善につながることもあります。ベストプラクティスについては下記のリンクを見てください。

https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data?hl=ja

下記のページも一覧になっていてわかりやすいです!

https://www.kabanoki.net/2151/#google_vignette


実装

#
Copied!
import type { BreadcrumbList, BlogPosting ,WithContext } from "schema-dts"
import { baseURL } from "@/config"


type JsonLDProps = {
  data: any
}

const JsonLD = ({ data }: JsonLDProps) => {
  const breadcrumbJsonLD: WithContext<BreadcrumbList> = {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    itemListElement: [
      {
        "@type": "ListItem",
        position: 1,
        name: "Home",
        item: `${baseURL}/blogs`
      },
      {
        "@type": "ListItem",
        position: 2,
        name: data.title,
        item: `${baseURL}/blogs/${data.id}`
      }
    ]
  }

  const blogPostingJsonLD: WithContext<BlogPosting> = {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    mainEntityOfPage: {
      "@type": "WebPage",
      "@id": `${baseURL}/blogs/${data.id}`
    },
    headline: data.title,
    datePublished: data.publishedAt || data.updatedAt,
    dateModified: data.updatedAt,
    keywords: [...data.category.map(({ name }) => name), data.title].join(","),
    description: data.description,
    image: data.thumbnail?.url,
    author: {
      "@type": "Person",
      name: "xxxxxx",
      jobTitle: "Software Engineer",
      url: `${baseURL}/about`
    },
  }
  
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify([blogPostingJsonLD,{ ...breadcrumbJsonLD }]) }}
    />
  )
}
export default JsonLD

Google Analytics

#

実装

#

Next.jsからサードパーティ用のライブラリが用意されています。こちらを活用するのが良いです!


layout.tsx
Copied!
import { GoogleAnalytics } from "@next/third-parties/google";
import { baseURL, gaId } from "@/config";


export default function Layout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
      <html lang="ja">
          <body>
            {children}
          </body>
        <GoogleAnalytics gaId={gaId} />
      </html>
  );
}

最後に

#

最後にTODOリストを掲載しておきます!

  • TDH(title, description, h1)の設定
  • Sitemapの作成
  • 構造化データJSON-LDの設定
  • Google Analytics

より良い方法があれば教えてください〜

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

気ままにつぶやいているので、気軽にフォローをお願いします!🥺



新米エンジニアの転職先を探しています!



GitHub
修正をリクエストする
Post to X