Nextjs App Directory SEO

Next 13 버전 이후에 도입된 App directory에서 SSR과 SSG를 구성하는 방식이 변경되면서 웹 사이트의 SEO을 동적으로 구성하는 방식들도 변경되었다.

최신 Nextjs 버전에서 SEO를 구성하는 방법들은 다음과 같다.

meta tag

메타 태그는 웹 페이지의 정보를 정의하는 태그로, 웹 페이지의 제목, 설명, 키워드, 작성자, 최종 수정일 등의 정보를 정의할 수 있다.

이러한 정보들로 검색엔진이 웹 페이지의 정보를 분석하고, 사용자에게 보여줄 때에도 웹 페이지의 정보를 표시할 수 있다.

Nextjs에서 meta tag를 설정하려면 layout.tsx 파일에 다음과 같이 정의 할 수 있다.

/app/layout.tsx
import { Metadata } from "next";
export const metadata:Metadata = {
    title: 'title',
  	description: 'description',
  	keywords: ['meta','tag'],
    openGraph: {
        title: 'Next.js',
        description: 'Description',
        type: 'article',
        publishedTime: '2024-01-01T00:00:00.000Z',
        authors: ['byeonmgin']
    },
}

아래와 같이 title template을 사용하면 페이지별로 동적으로 title을 지정할 수 있다.

/app/layout.tsx
export const metadata: Metadata = {
  title: {
      default: 'byeongmin.dev',
      template: '%s | byeongmin.dev',
    },
}
/app/post/page.tsx
export const metadata: Metadata = {
  title: 'Nextjs'
}

이렇게 지정하면 해당 post 페이지의 title은 Nextjs | byeongmin.dev로 설정된다.

이러한 기능을 활용해서 Nextjs 동적 라우팅으로 생성하는 SSG같은 페이지에서 generateMetadata 함수를 사용하여 동적으로 페이지별로 해당 페이지에 대한 메타 태그를 생성할 수 있다.

/app/post/page.tsx
export async function generateMetadata({
  params,
}: {
  params: { slug: string | string[] };
}) {
  const allPosts = await getAllFrontmatter("posts");

  // 생략 : 해당 페이지에대한 post 정보를 가져온다.

  const metadata: Metadata = {
    title: post?.title,
    description: post?.description,
    // 생략
  };
  return metadata;
}

적용된 메타 태그를 보면 아래와 같이 모든 페이지 별로 동적으로 메타 태그를 생성 된것을 볼 수 있다.

robot.txt
robot.txt

robots.txt

웹 사이트 내의 컨텐츠에 대해 크롤러의 접근 제어에 대한 내용을 정의하고sitemap을 크롤러에게 알려주는 역할을 한다.

기본적으로 모든 사이트의 루트 경로 + /robots.txt 경로에 위치한다. 이 사이트의 https://www.byeongmin.dev/robots.txt 에 접속해도 다음과 같은 내용을 확인할 수 있다.

robot.txt
robot.txt

Nextjs에서 /app/robots.ts 경로로 아래와 같이 robots.txt 파일을 생성할 수 있다.

/app/robots.ts
export default function robots() {
  return {
    rules: [
      {
        userAgent: "*",
        allow: ["/"],
      },
    ],
    sitemap: "https://www.byeongmin.dev/sitemap.xml",
    host: "https://www.byeongmin.dev",
  };
}

sitemap.xml

sitemap.xml는 해당 사이트의 모든 URL을 XML 형식으로 나열하여, 컨텐츠들의 업데이트 시점이나 빈도등을 담아서 웹 사이트의 페이지 구조를 크롤러에게 알려준다.

sitemap.xml 파일 역시 기본적으로 사이트의 루트 경로 + /sitemap.xml 경로에 위치한다.

이 사아트의 https://www.byeongmin.dev/sitemap.xml 에 접속해도 다음과 같은 내용을 확인할 수 있다.

sitemap.xml
sitemap.xml

Nextjs에서 /app/sitemap.ts 경로로 아래와 같이 sitemap.xml 파일을 생성할 수 있다.

/app/sitemap.ts
import { MetadataRoute } from 'next'

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

이 블로그와 같이 SSG페이지를 생성하는 경우에는 다음과 같이 sitemap.xml 파일을 생성할 수 있다.

/app/sitemap.ts
import { getAllFrontmatter } from "@/lib";
import { SITE_URL } from "@/utils";
import { MetadataRoute } from "next";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const sitemap = [
    {
      url: SITE_URL,
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 1,
    },
  ];

  const posts = await getAllFrontmatter("posts");

  posts.map((post) => {
    sitemap.push({
      url: `${SITE_URL}/post/${post.slug}`,
      lastModified: new Date(post.date),
      changeFrequency: "yearly" as const,
      priority: 0.8,
    });
  });

  return sitemap as MetadataRoute.Sitemap;
}

기본적으로 사이트 정보를 sitemap에 담고 getAllFrontmatter함수를 사용하여 SSG로 생성하는 페에지의 정보를 가져와서 동적으로 sitemap을 생성할 수 있다.

이렇게 하면 build시에 sitemap을 생성한다.

sitemap build
sitemap build

이렇게 생성된 sitemap.xml을 검색엔진에 제출하면 검색엔진이 크롤링과 색인 생성을 하여 변경 사항을 자동으로 반영할 수 있다.

menifest.json

PWA를 구성할 때 사용하는 파일로, 웹 앱의 정보를 담고 있는 파일이다. 웹 앱을 다운 받았을때 아이콘, 이름, 시작 URL, 테마 색상 등을 설정할 수 있다.

nextjs에서 /app/manifest.ts 경로로 아래와 같이 menifest.json 파일을 생성할 수 있다.

/app/manifest.ts
import { MetadataRoute } from 'next'

export default function manifest(): MetadataRoute.Manifest {
  return {
    name: 'Next.js App',
    short_name: 'Next.js App',
    description: 'Next.js App',
    start_url: '/',
    display: 'standalone',
    background_color: '#ffffff',
    theme_color: '#ffffff',
    icons: [
      {
        src: '/favicon.ico',
        sizes: 'any',
        type: 'image/x-icon',
      },
    ],
  }
}

SEO 검사하기

크롬 개발자 도구에서 Lighthouse를 사용하여 SEO를 검사할 수 있다.

위에 해당 하는 내용들을 모두 적용했다면, SEO부분에서 쉽게 통과할 수 있다.

lighthouse
lighthouse