Next 22장 - SEO
포스트
취소

Next 22장 - SEO

Next

SEO

  • 검색 엔진 최적화인 SEO, Next에서는 SSR로 동작하기 때문에 빈 태그가 아닌 실제 요소들이 들어가 있고, 그렇기에 SEO에 대한 강점을 가진다.
  • 이 외에도 여러 가지의 평가 항목 중 meta data를 활용하여 검색 엔진에 우위를 가질 수 있다.
  • Next 14 버전에서는 <Head> 태그를 사용하는 것이 아닌, next에 내장된 MetaData를 활용하는 것으로 바뀌었다.

Meta data

  • Next Metadata
  • 페이지 별로 메타 데이터를 작성할 수 있으며, 동적 메타 데이터 작성도 가능하다.
  • 공식 문서에 나와있는대로 generateMetadata를 이용해서 data를 가져온다.
1
2
3
4
5
6
import {Metadata} from "next";

export const meatadata : Metadata = {
  title: ...,
  description: ...,
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// dynamic metadata
import type { Metadata, ResolvingMetadata } from 'next'

type Props = {
  params: { id: string }
  searchParams: { [key: string]: string | string[] | undefined }
}

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // read route params
  const id = params.id
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  const previousImages = (await parent).openGraph?.images || []

  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }: Props) {}

meta data custom

  • 위와 같이 동적으로 메타 데이터를 받아와서 사용하는 것 외에도, 페이지별 동일한 메타 데이터가 반복되어 사용된다면 아래와 같이 상수를 이용하여 사용할 수 있다.
  • 이후 페이지별로 metadata를 넘겨주기만 하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { Metadata } from "next";

interface MetadataProps {
  [key: string]: string;
}

export const META = {
  title: "...",
  siteName: "...",
  description: "...",
  keyword: ["...", "...", "...", "..."],
  url: "https://...",
  googleVerification: process.env.GOOGLE || "",
  naverVerification: process.env.NAVER || "",
  ogImage: "/main.png",
} as const;

export const getMetadata = (metadataProps?: MetadataProps) => {
  const { title, description, asPath } = metadataProps || {};

  const TITLE = title ? `${title} | ...` : META.title;
  const DESCRIPTION = description || META.description;
  const PAGE_URL = asPath ? META.url + asPath : META.url;
  const OG_IMAGE = META.ogImage;

  const metadata: Metadata = {
    metadataBase: new URL(META.url),
    alternates: {
      canonical: PAGE_URL,
    },
    title: TITLE,
    description: DESCRIPTION,
    keywords: [...META.keyword],
    openGraph: {
      title: TITLE,
      description: DESCRIPTION,
      siteName: TITLE,
      locale: "ko_KR",
      type: "website",
      url: PAGE_URL,
      images: {
        url: OG_IMAGE,
      },
    },
    verification: {
      google: META.googleVerification,
      other: {
        "naver-site-verification": META.naverVerification,
      },
    },
    twitter: {
      title: TITLE,
      description: DESCRIPTION,
      images: {
        url: OG_IMAGE,
      },
    },
  };

  return metadata;
};
1
2
3
4
5
6
7
8
9
10
11
12
// home/page.tsx
import { Metadata } from "next";
import { getMetadata } from "@/constant/metaData";

export const generateMetadata = async (): Promise<Metadata> => {
  return getMetadata();
};

// example/page.tsx
export const generateMetadata = async (): Promise<Metadata> => {
  return getMetadata({ title: "여기는 example", description: "예시 페이지" });
};

web master

  • next metadata vertification
  • 네이버 서치 어드바이저
  • 네이버, 구글 등의 검색 엔진에 노출되고 싶다면 각 사이트의 웹마스터 도구를 사용할 수 있다.
  • 각 사이트마다 웹 마스터 도구에 들어가면 본인의 사이트인지에 대한 확인 작업을 거친다.
  • 이러한 확인 작업은 사이트에서 부여하는 고유의 문자열을 meta태그에 넣어 확인하거나, 다운로드 되는 html 파일을 public 파일에 넣어 배포하고, 검색 엔진에서 부여한 코드 혹은 파일을 확인하는 작업을 거친다.

next-sitemap

  • site map이란, 구글이나 네이버와 같은 검색 사이트들의 크롤링 봇에게 본인의 서비스에서 사용할 수 있는 사이트 주소를 알려주는 것이다.
  • 이러한 작업은 운영하는 서비스가 사용자들의 검색어에 더 많이 노출될 수 있도록 도와주는 이점을 갖는다.
  • 상황에 따라서 노출되면 안 되는 특정 주소는 robotos.txt를 이용하여 크롤링해도 되는 주소와 하지 말아야 할 주소를 구분하여 명시해줄 수 있다.
1
npm i next-sitemap
1
2
3
4
5
6
// pacakge.json
{
  "scripts": {
    "postbuild": "next-sitemap",
  },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// /app/next-sitemap.config.js 파일 생성
/** @type {import('next-sitemap').IConfig} */

module.exports = {
  siteUrl: "http://localhost:8088", // .게시하는 site의 url
  generateRobotsTxt: true, // robots.txt generate 여부 (자동생성 여부)
  sitemapSize: 7000, // sitemap별 최대 크기 (최대 크기가 넘어갈 경우 복수개의 sitemap으로 분리됨)
  changefreq: "daily", // 페이지 주소 변경 빈도 (검색엔진에 제공됨) - always, daily, hourly, monthly, never, weekly, yearly 중 택 1
  priority: 1, // 페이지 주소 우선순위 (검색엔진에 제공됨, 우선순위가 높은 순서대로 크롤링함)
  exclude: [
    "/exclude/review", // 페이지 주소 하나만 제외시키는 경우
    "/exclude/**", // 하위 주소 전체를 제외시키는 경우
  ], // sitemap 등록 제외 페이지 주소
  robotsTxtOptions: {
    // 정책 설정
    policies: [
      {
        userAgent: "*", // 모든 agent 허용
        allow: "/", // 모든 페이지 주소 크롤링 허용
        disallow: [
          "/exclude", // exclude로 시작하는 페이지 주소 크롤링 금지
        ],
      },
      // 추가 정책이 필요할 경우 배열 요소로 추가 작성
    ],
  }, // robots.txt 옵션 설정
};
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.