Next.js에서 SEO 향상 전략

August 19, 2023

    Nextjs

SEO(Search Engine Optimization)은 사용자가 검색어를 입력했을 때, 해당 검색 결과에 검색엔진에 의해 높은 순위를 차지할 수 있도록 웹사이트를 설계하는 전략 및 기술을 이야기한다. SEO는 단순히 검색엔진에 많은 정보를 준다고 해서 만족되는 것은 아니다. 사이트 성능, 이탈 시간등 컨텐츠도 SEO에 중요한 요소들이다. 하지만 이 글에서는 성능이나 컨텐츠적인 요소들은 다루지 않고 SEO를 위해 기본적인 설정만을 다룬다.

Metadata

메타데이터는 웹 페이지의 내용을 설명하거나 검색엔진에 정보를 제공하는 데이터이다. 메타데이터는 웹페이지의 <head>섹션에 위치하며 검색엔진이 페이지를 해석하는데 도움을 준다.

Next.js에서는 정적, 동적으로 메타데이터를 생성하게 도와준다.

import { Metadata } from 'next' // either Static metadata export const metadata: Metadata = { title: '...', } // or Dynamic metadata export async function generateMetadata({ params }) { return { title: '...', } }

정적인 방법은 메타데이터 객체를 직접 정의하는 방법이고 아래의 동적인 방법은 함수 generateMetadata로 메타데이터를 생성하는 방법이다. 이 객체를 applayout에 정의하면 하위 페이지들은 모두 해당 메타데이터 객체의 정보를 따른다.

페이지별로 다른 메타데이터가 필요하다면, 해당 페이지의 layout파일에 메타데이터 객체를 다시 정의하면, 상위 디렉토리에 정의된 메타데이터 객체와 중복되는 속성들은 해당 페이지에 가까운 속성이 우선적으로 메타데이터에 들어가게 된다.

아래는 메타데이터 객체의 예시이다.

export const metadata = { generator: 'Next.js', //제작 프레임워크 applicationName: 'Next.js', //웹 어플리케이션의 이름 referrer: 'origin-when-cross-origin', //페이지 이동시 정보 전송 방법 결정 keywords: ['Next.js', 'React', 'JavaScript'], //주요 키워드나 주제 authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.org' }], //저자들에 대한 정보 colorScheme: 'dark', //기본 색상 스킴 creator: 'Jiachi Liu', //웹 제작자 이름 publisher: 'Sebastian Markbåge', //웹 페이지를 게시한 사람이나 조직 이름 formatDetection: { email: false, address: false, telephone: false, }, //특정 유형 데이터의 자동 감지, 포맷 시도 여부 결정 }

위와 같이 메타데이터 객체를 정의하면 아래와 같이 <head>에 메타데이터가 추가된다.

<meta name="application-name" content="Next.js" /> <meta name="author" content="Seb" /> <link rel="author" href="https://nextjs.org" /> <meta name="author" content="Josh" /> <meta name="generator" content="Next.js" /> <meta name="keywords" content="Next.js,React,JavaScript" /> <meta name="referrer" content="origin-when-cross-origin" /> <meta name="color-scheme" content="dark" /> <meta name="creator" content="Jiachi Liu" /> <meta name="publisher" content="Sebastian Markbåge" /> <meta name="format-detection" content="telephone=no, address=no, email=no" />

openGraph

openGraph는 소셜 미디어 플랫폼에서 링크를 걸 때, 어떻게 표시되는지를 정의하기 위한 정보들이다. 카카오톡에 링크를 전송하면 썸네일과 간단한 정보들이 뜨는것이 바로 openGraph에 정의된 메타데이터를 기반으로 만들어지는 것이다. opoenGraph의 속성들은 아래와 같다.

export const metadata = { openGraph: { title: 'Next.js', description: 'The React Framework for the Web', url: 'https://nextjs.org', siteName: 'Next.js', images: [ { url: 'https://nextjs.org/og.png', width: 800, height: 600, }, { url: 'https://nextjs.org/og-alt.png', width: 1800, height: 1600, alt: 'My custom alt', }, ], locale: 'en_US', type: 'website', }, }

이제 위의 요소들을 근거로 개인 블로그에 들어갈 메타데이터 객체를 아래와 같이 작성해 보았다.

export const metadata = { generator: 'Next.js', title: 'Latemarch', description: 'Latemarch blog', referrer: 'origin-when-cross-origin', applicationName: 'Latemarch - blog', keywords: ['Next.js', 'blog', '기술 블로그', '자바스크립트'], authors: { name: 'Latemarch', url: 'jjh@catholic.ac.kr' }, colorScheme: 'dark', creator: 'Latemarch', publisher: 'Latemarch', formatDetection: { email: false, address: false, telephone: false, }, openGraph: { title: 'Latemarch - blog', siteName: 'Latemarch', description: 'Latemarch - blog', image: { url: '/images/frontend.png', alt: 'My blog image' }, locale: 'kr_KR', type: 'website', }, }

이 메타데이터 객체는 기본 메타데이터 이고 각 페이지마다 title, description과 같은 정보가 조금씩 달라진다.

sitemap.xml

사이트맵은 웹 사이트의 페이지들을 목록화한 파일로, 검색엔진 크롤러에게 접근 가능한 url을 제공해 주므로 SEO에 있어 중요한 역할을 한다. app/sitemap.xml파일을 직접 만들어 넣을 수 있지만, app/sitemap.ts로 사이트맵을 만들 수도 있다.

import { MetadataRoute } from 'next' export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://acme.com', lastModified: new Date(), }, { url: 'https://acme.com/about', lastModified: new Date(), }, { url: 'https://acme.com/blog', lastModified: new Date(), }, ] }

robots.txt

SEO를 위해 검색엔진 크롤러가 어떤 URL에 접근 할 수 있는지 알려줘야 한다. 이를 app/robots.txt를 추가하여 검색엔진 크롤러에게 사이트맵을 제공할 수 있다. 이 때에도 마찬가지로 app/robots.ts로 생성 가능하다.

import { MetadataRoute } from 'next' export default function robots(): MetadataRoute.Robots { return { rules: { userAgent: '*', allow: '/', disallow: '/private/', //크롤링 금지 대상 지정 }, sitemap: 'https://acme.com/sitemap.xml', } }