npm install react-helmet-async
react-helmet-async
?
→react-helmet-async
는react-helmet
을 개선한 라이브러리로, npm trend 를 참고했을때,
꾸준히 업데이트 되며, 사용자의 수 또한 기존react-helmet
을 넘어섰으므로, 해당 라이브러리를 설치하여 사용합니다.
Provider
로 감싸고, Helmet
컴포넌트를 이용해서 메타데이터를 작성하면 된다.// index.tsx
import React from 'react';
import { HelmetProvider } from 'react-helmet-async';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<HelmetProvider>
<App />
</HelmetProvider>
);
// App.tsx
import React from 'react';
import { Helmet } from 'react-helmet-async';
function App : JSX.Element () {
<>
<Helmet>
<meta property="og:site_name" content="사이트 이름" />
<meta property="og:title" content="페이지 이름" />
<meta property="og:url" content="사이트 주소" />
<meta property="og:description" content="설명" />
...
</Helmet>
{/* JSX 작성 */}
</>
}
index.html
에 메타데이터가 이미 작성되어 있다면, 해당 내용은 삭제한다.// metadatas/metadatas.tsx
import React from 'react';
import { Helmet } from 'react-helmet-async';
export function Page1Metas(): JSX.Element {
return (
<Helmet>
<meta property="og:site_name" content="사이트 이름" />
<meta property="og:title" content="페이지 이름" />
<meta property="og:url" content="사이트 주소" />
<meta property="og:description" content="설명" />
</Helmet>
);
}
export function Page2Metas(): JSX.Element {
return (
<Helmet>
<meta property="og:site_name" content="사이트 이름" />
<meta property="og:title" content="페이지 이름" />
<meta property="og:url" content="사이트 주소" />
<meta property="og:description" content="설명" />
</Helmet>
);
}
export function Page3Metas(): JSX.Element {
return (
<Helmet>
<meta property="og:site_name" content="사이트 이름" />
<meta property="og:title" content="페이지 이름" />
<meta property="og:url" content="사이트 주소" />
<meta property="og:description" content="설명" />
</Helmet>
);
}
→ 각 메타데이터들을 Helmet
컴포넌트로 감싼 컴포넌트로 만들어 export 한다.
// metadatas/metadatas.tsx
import React from 'react';
import { Helmet } from 'react-helmet-async';
interface IProps {
siteName : string;
title : string;
siteUrl : string;
desc : string;
}
export function Page1Metas({siteName, title, siteUrl, desc} : IProps): JSX.Element {
return (
<Helmet>
<meta property="og:site_name" content={siteName} />
<meta property="og:title" content={title} />
<meta property="og:url" content={siteUrl} />
<meta property="og:description" content={desc} />
</Helmet>
);
}
→ 뭐가 더 편한지는 본인 선택!
index.html
하나만 마주치게 되므로, og 가 정확하게 표시되지 않는 문제점이 발생한다.react-helmet-async
만 사용해도 무관 할 듯 하다.react-snap
을 이용하면 위의 문제를 해결 할 수 있다.index.html
파일을 생성하고, 이를 크롤러에 제공 해주는 역할을 하는 라이브러리이다.npm install react-snap -D
"scripts": {
...,
"postbuild" : "react-snap"
},
prebulild
는 빌드 전에 실행하고, postbuild
는 빌드 후에 실행된다."reactSnap": {
"include": [
// 프리렌더링 되기 원하는 path 를 작성한다.
],
"exclued": [
// 프리렌더링에서 제외할 path 를 작성한다.
]
},
root
부터 시작하여 모든 링크를 크롤링해주지만, 위의 설정을 통해 원하거나, 제외하고 싶은 링크를 설정 할 수 있다.// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
// 일부 생략
const container = document.getElementById('root') as HTMLElement;
const root = ReactDOM.createRoot(container);
if (container.hasChildNodes()) {
ReactDOM.hydrateRoot(
container,
<HelmetProvider>
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
</HelmetProvider>
);
} else {
root.render(
<HelmetProvider>
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
</HelmetProvider>
);
}
hydrate
를 이용하기 위해 기존 index.tsx
작성내용에서 일부를 변경했다.render
와 hydrate
가 각각 createRoot
, hydrateRoot
로 변경되었다.postbulid
에 따라 위의 사진처럼 파일 내부의 path를 자동으로 크롤링한다.참고 글
https://velog.io/@miyoni/noSSRyesSEO
https://velog.io/@byseop/SPA에서-서버사이드-렌더링을-구축하지-않고-SEO-최적화하기
https://www.nashu.dev/blogs/react-snap
동작하나요...? 아무리해도 동적으로 된 url들이 안되네요...ㅠ
public에 있는 요소들만 가져오고 helmet으로 변경해준 태그 들은 변경이 안되네용