# 간단한 SEO 적용(NEXT.JS)
B2C 서비스에서, 특히 웹서비스를 기반으로 한다면 SEO는 가장 중요한 지표 중 하나이다. SEO(search engine optimization)의 증진은 검색 엔진이 웹 페이지를 잘 찾아낼 수 있게끔 하는 과정입니다.
## 기본적인 내용
### 검색엔진
검색엔진은 미리 웹상의 정보를 수집하여 색인 목록을 만들어두고 사용자가 검색엔진을 사용했을 때 관련 키워드를 색인목록에서 찾아 노출시킵니다. 검색엔진이 정보를 수집하여 색인목록을 만드는 과정은 봇(또는 크롤러)의 크롤링을 통해 이루어집니다. 따라서 SEO의 증진은 봇이 웹페이지를 색인을 더 잘 할수 있게끔 만드는 과정입니다.
### SEO 가이드
전 세계 웹 사용자의 92%가 구글을 이용한다고 하는 만큼 구글에 서비스가 노출 되는 것은 중요합니다. 구글은 이를 위한 SEO 가이드 및 개발 도구(search console)등을 제공합니다.
가이드를 살펴보면 url의 설정 기준, meta 태그의 설정, 사이트 맵, robots.txt등 다양한 기준이 정의되어 있습니다.
### 기본적인 SEO 측정
Chrome의 경우 개발자 도구에 Lighthouse를 통해 SEO지표를 측정할 수 있습니다. Lighthouse를 통해 분석하면 5가지 지표가 나오는데 SEO 지표는 해당 웹 사이트가 몇몇 기준에 부합하는 정도를 점수화 해서 보여줍니다. 또한 어떤 부분이 설정되었는지 되어있지 않은지를 알려주어 작업할 수 있도록 돕습니다.
아래는 "모두의 개발"의 Lighthouse 점수표와 SEO에 대한 세부 내용입니다. 현재 해당 페이지에 robots.txt 파일이 없음을 알려주고 있습니다.


## 기초적인 SEO 작업
### head의 설정
head는 웹 페이지를 표현하는 문서(html)의 정보를 담은 meta data 세트로 검색 엔진이 분석하는 주요 요소 입니다.
구글 SEO 가이드에 따르면 메타 데이터에 유효한 요소인 `title`, `meta`, `link`등의 요소만 넣을 것을 권장합니다. 또한 읽을 수 있는 meta 태그만 넣을것을 권장하는 만큼 적절한 tag를 입력하여 처리하도록 합시다. 자세한 내용은 가이드를 참고할 수 있도록 합시다.
[구글 SEO 가이드](https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata?hl=ko)
React나 NEXT.JS에서 head의 작성은 이전 글인 "**React \<head\>**" 를 참고합니다.
[React \<head\>](https://blog-seolim.vercel.app/article/1)
### sitemap.xml / robots.txt
sitemap.xml과 robots.txt는 모두 봇(크롤러)가 페이지를 색인하기 위해 참고하는 파일입니다. robots.txt는 크롤러가 페이지에 접근할 때 어떤 페이지를 접근할지에 대한 설정을 가지고 있고 sitemap.xml은 해당 서비스가 어떻게 구성되어있는지를 봇에게 알려주어 크롤링 효율을 높입니다.
robots.txt는 아래와 같이 작성됩니다.
```
User-agent: *
Allow: /
Sitemap: http://localhost:4000/sitemap.xml
Sitemap: http://localhost:4000/server-sitemap-index.xml
```
User-agent는 봇의 이름을 설정하고 Allow/Disallow를 통해 접근을 하게 할지 말지를 결정합니다. 또한 Sitemap의 위치를 알려줍니다.
sitemap은 여러 포맷으로 작성될 수 있습니다. 구글의 경우 rss, xml, text 여러 포맷을 지원합니다. 아래처럼 작성합니다.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="https://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="https://www.w3.org/1999/xhtml" xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="https://www.google.com/schemas/sitemap-image/1.1" xmlns:video="https://www.google.com/schemas/sitemap-video/1.1">
<url><loc>http://localhost:4000</loc><lastmod>2022-10-30T10:22:43.162Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
<url><loc>http://localhost:4000/login</loc><lastmod>2022-10-30T10:22:43.162Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
<url><loc>http://localhost:4000/post</loc><lastmod>2022-10-30T10:22:43.162Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>
</urlset>
```
위 두 파일을 root path에서 정적파일로 제공하면 봇은 두 파일을 참고합니다.
## next-sitemap
NEXT로 SSR을 만들어 둔다면 동적으로 페이지를 생성하는 경우가 많습니다. 그 때마다 sitemap을 재설정하는 것은 비효율 적이므로 stiemap.xml또한 동적으로 생성하여 봇에게 제공하는 것이 좋습니다.
이를 생성하는 스크립트를 직접 만들 수 도 있겠지만 `next-sitemap`을 사용하면 쉽게 sitemap을 간단히 개발할 수 있습니다.
[next-sitemap](https://www.npmjs.com/package/next-sitemap)
`next-sitemap` 은 작성된 configuration에 따라 기본적인 사이트맵(sitemap)을 build 과정에서 생성하고 동적페이지에 대해서 server-sitemap.index.xml를 동적으로 생성하고 기본 사이트맵에서 가르키도록 생성됩니다. 아래와 같이 configuration파일을 작성합니다.
```typescript
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'your url',
generateRobotsTxt: true, /** robots.txt를 생성할지 여부 */
sitemapSize: 7000,
/** 이 하단은 동적페이지를 생성할 경우 필요한 옵션 */
exclude: ['/server-sitemap-index.xml'], // <= exclude here
robotsTxtOptions: {
additionalSitemaps: [
`yout url/server-sitemap-index.xml`, // <==== Add here
],
},
}
```
위 설정인 동적 페이지 생성을 통한 xml을 제공하려면 추가적으로 pages에 server-sitemp.index.xml 폴더를 생성하고 index.tsx를 아래와 같이 작성합니다. 스크립트는 요구되는 url정보를 list로 받아 xml를 동적으로 생성합니다. 아래 예시는 서버로 부터 게시글을 받아와 모든 게시글 페이지를 sitemap에 등록하여 보여주는 과정입니다.
```typescript
// pages/server-sitemap-index.xml/index.tsx
import { getServerSideSitemapIndex } from 'next-sitemap';
import { GetServerSideProps } from 'next';
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const { articles } = await fetch(`${process.env.BASEURL}/api/articles`).then((res) => res.json());
return getServerSideSitemapIndex(
ctx,
articles.map(({ id }: { id: number }) => `${process.env.SITE_URL}/article/${id}`),
);
};
// Default export to prevent next.js errors
export default function SitemapIndex() {}
```
마지막으로 기본 빌드시 sitemap을 생성할 수 있도록 아래 스크립트를 package.json에 추가한다.
```json
"script": {
"postbuild": "next-sitemap --config {your config file}",
}
```
혹은 `next-sitemap.config.js`를 루트에 작성하면 `next-sitemap`만으로 동작시킬 수 있습니다.
build후 public 디렉토리에 sitemap.xml이 생성된 것을 확인할 수 있습니다.
## CSR vs SSR
"CSR은 SEO가 나쁘다" 라는 것은 반은 맞고 반을 틀린말입니다. CSR의 SEO가 나쁜 까닭은 처음으로 보내는 index.html이 비어있고 이후 스크립트(js)를 통해 화면을 그리기에 봇은 사이트를 빈 페이지로 인식하기 때문입니다.
다만 최신 구글 봇은 js 코드를 해석하고 sitemap등을 통해 SPA의 라우팅에 대한 정보도 넘겨줄 수 있습니다. 또한 meta데이터는 index.html을 통해 제공할 수 있으므로 어느정도 SEO를 보장할 수 있습니다.
그러나 구글 에드센스 신청등에서 SSR은 높은 점수를 받는 편으로 확인되고 html바디를 직접적으로 그리는 만큼 SEO에 대한 관점으로 볼 때는 SSR을 권장하는 편입니다.
## 마무리
SEO 향상을 위한 기초적인 방법을 제시하였습니다. 이 외에도 적절한 키워드나 edge function(lambda edge)등 SEO를 향상시키는 다양한 방법론과 기술이 존재합니다. SEO는 개발 연습에 있어 간과하기 쉽지만 꼭 한번씩은 이해하고 실습해보기 바랍니다.