개발일기/Web

[React] react-helmet으로 페이지 별로 html head 채우기

DongKeun2 2024. 11. 23. 00:23

CSR 방식의 React, 한 장의 html

 리액트는 CSR(client-side-rendering) 방식의 웹 렌더링이 이루어진다.

SPA(single-page-application)는 UX에 도움이 되지만 SEO 관점에서는 단점 투성이다.

말 그대로 단일 페이지이기 때문에 HTML 한 장만 존재하기 때문에 메인을 제외하고 갈아끼우는 페이지들은 검색 엔진에 적용시키기 어렵다.

 

SPA === CSR 이라고는 할 수 없지만 결이 비슷하기 때문에 특수한 작업을 하지 않는다면 거의 맞는 말이 된다. react는 SPA이자 CSR이다.

CSR이면 SEO 관리가 힘들다.

 

 아무튼 cra로 생성한 react 프로젝트는 SPA + CSR이기 때문에 가장 상위의 index.html에서 head를 관리하게 된다.

저번에 og를 다루면서 이 곳에 태그를 채워 넣어 확인을 했던 경험이 있었다.

한 페이지로 이루어진 프로젝트라면 하나의 html에 이런 작업을 해줘도 큰 문제가 없다.

 

 하지만 여러 페이지를 다루게 된다면 어떻게 해야할까?

 

당장 티스토리 블로그만 봐도 페이지마다 title이 다른 것을 볼 수 있다.

 

react-helmet-async

react에서는 react-helmet 라이브러리를 사용하면 페이지마다 head를 갈아줄 수 있다.

react side effect에 의존하기 때문에 비동기 처리에 문제가 있어 만약 서버에서 받아온 데이터를 넣어야 한다면 대안으로 나온 react-helmet-async를 쓰면 된다.

 

yarn add react-helmet-async
pnpm install react-helmet-async

 

 

둘 다 사용방법은 널려있어서 그리 어렵지 않게 적용할 수 있다.

 

일단 가장 상위에 provider를 감싼다.

import { HelmetProvider } from 'react-helmet-async';

function App() {
    return (
        <HelmetProvider>
        	<Main />
        </HelmetProvider>
    )
}

 

컴포넌트 내부에서 Helmet에 head에 담을 정보를 담아준다.

import { Helmet } from 'react-helmet-async';

const Page1 = () => {
    return (
        ...
        <Helmet>
            <title>{title}</title>
            <meta name="description" content={description} />
            <meta property="og:type" content="website" />
            <meta property="og:title" content={title} />
            <meta property="og:description" content={description} />
            <meta property="og:image" content={image} />
        </Helmet>
        ...
    )
}

 

라이프 사이클을 확인해서 중복되지 않게 페이지마다 잘 넣어주면 된다.

CustomHead 이런 걸로 따로 빼주고 가져다 쓰는 게 편할 것 같다.

 

확인해보면 페이지마다 head에 내가 지정한 데이터가 잘 들어가는 것을 볼 수 있다.

 

helmet으로 넣어준 데이터는 "data-rh"="true" 로 표시된다.

 

이제 페이지마다 메타데이터를 따로 구성할 수 있게 되었다.

하지만 아직 갈 길은 멀다. 사실 CSR 방식의 제일 큰 문제점인 SEO는 해결하지 못했기 때문이다.

react-snap으로 뭐가 된다던데 react 18버전에서는 잘 안 되는 것 같고 업데이트도 몇 년 전부터 멈춰있어서 기대하지 않는 게 좋을 것 같다.

 

Prerender 적용 경험, SSR로 이관

 react로 구현했을 때 장점이 있는 페이지에서 메타 정보를 다루기 위해 react-helmet-async를 쓰는 건 좋지만 SEO가 필요한 페이지를 react로 구현하는 건 좋지 않아 보인다.


 정적인 데이터를 prerender하여 html을 한 장이 아닌 여러장을 뽑아둘 수 있는데 react-snap과 prerender 관련 라이브러리를 적용하면 쉽게 해결할 수 있을 것이다.

 

 이렇게 페이지별로 미리 메타 태그가 포함된 html을 생성한다. 해봤는데 결국 동적인 데이터는 관리하기 힘들고, SEO에도 큰 기여를 할 수 없어 CSR의 한계는 아직 넘을 수 없어보인다.

 

SEO를 위해 Next.js로 이관 

 지금 하는 쇼핑몰 프로젝트는 SEO가 절대적으로 중요하기 때문에 react만으로는 한계가 있을 것 같고, 결국 SSG 또는 SSR 방식으로 돌려야 할 것 같아 next로 마이그레이션을 진행중이다.