Gatsby에서 canonical URL을 만드는 방법?
Source: Dev.to

소개
이전 게시물 중 하나에서 정규 URL이 무엇인지 설명했습니다. 이제 Gatsby에서 이를 구현하는 방법을 보여드리겠습니다.
Gatsby
Gatsby란?
Gatsby는 React‑기반 오픈‑소스 프레임워크로, 웹사이트와 앱을 만들 수 있습니다.
- React 위에 구축된 정적 사이트 생성기(SSG)입니다.
- React 컴포넌트를 HTML 파일로 사전 렌더링합니다.
- 플러그인 생태계와 활발한 커뮤니티를 제공합니다.
Gatsby가 컴포넌트를 HTML 페이지로 렌더링한 후에는 원하는 어떤 호스팅에서도 정적 웹사이트로 제공할 수 있습니다.
React Helmet
React Helmet이란?
React Helmet은 Gatsby 프로젝트에서 <head> 태그 전체를 관리할 수 있게 해주는 재사용 가능한 React 컴포넌트입니다.
import React from "react";
import { Helmet } from "react-helmet";
class Application extends React.Component {
render() {
return (
<Helmet>
<title>My Title</title>
{/* other head tags */}
</Helmet>
);
}
}
Gatsby가 HTML을 렌더링하면 다음과 같이 출력됩니다:
<head>
<title>My Title</title>
<!-- other head tags -->
</head>
설치
npm install gatsby-plugin-react-helmet react-helmet
gatsby-plugin-react-helmet-canonical-urls
React Helmet은 훌륭하지만 gatsby-plugin-canonical-urls와 충돌합니다. 두 플러그인을 모두 사용하면 두 개의 canonical <link> 태그가 생성될 수 있습니다.
gatsby-plugin-react-helmet-canonical-urls 플러그인은 기본 canonical 태그를 제공하고, 이를 React Helmet을 통해 재정의할 수 있게 하여 이 문제를 해결합니다.
설치
npm install --save gatsby-plugin-react-helmet gatsby-plugin-react-helmet-canonical-urls
설정 (gatsby-config.js)
// gatsby-config.js
module.exports = {
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-plugin-react-helmet-canonical-urls`,
options: {
siteUrl: "https://www.example.com",
},
},
],
};
전체 옵션 목록은 여기에서 확인하세요: .
정적 페이지에서 정규 URL 사용하기
예시 컴포넌트 (about.jsx)
import React from "react";
import { Helmet } from "react-helmet";
import Layout from "../components/layout";
export default ({ data, location }) => (
<Layout>
<Helmet>
<title>{`${data.site.siteMetadata.title} - About`}</title>
<link
rel="canonical"
href={`${data.site.siteMetadata.siteUrl}${location.pathname}`}
/>
</Helmet>
<h1>About me</h1>
{/* page content */}
</Layout>
);
사이트 메타데이터 (gatsby-config.js)
module.exports = {
siteMetadata: {
title: "Kode Skills",
siteUrl: "https://kodeskills.com/",
},
};
GraphQL 쿼리
export const query = graphql`
{
site {
siteMetadata {
title
siteUrl
}
}
}
`;
location prop (Gatsby 문서 참고)은 페이지 컴포넌트에 자동으로 전달되며, siteUrl과 location.pathname을 사용해 전체 정규 URL을 만들 수 있습니다.
결론
React Helmet과 gatsby-plugin-react-helmet-canonical-urls를 결합하면 다음을 할 수 있습니다:
- 전체 사이트에 대한 기본 정규화 URL을 정의합니다.
- 필요에 따라 페이지별로 이를 재정의합니다.
<link rel="canonical">태그를 깔끔하고 SEO‑친화적으로 유지합니다.
즐거운 개발 되세요! 🚀
Gatsby에서 정규 URL 만들기
정규 URL이란?
정규 URL은 동일하거나 매우 유사한 콘텐츠를 가진 여러 URL이 존재할 때, 어떤 페이지가 “주된” 버전인지 검색 엔진에 알려주는 역할을 합니다. 이를 통해 중복 콘텐츠에 대한 패널티를 방지하고 링크 가치를 하나로 모을 수 있습니다.
Gatsby에서는 각 페이지의 <head>에 <link rel="canonical"> 태그를 추가할 수 있습니다. 이 태그의 값은 페이지의 전체 URL(프로토콜 및 도메인 포함)이어야 합니다.
정적 페이지
정적 페이지의 경우 사이트 기본 URL(siteUrl)과 페이지 경로명(location.pathname)을 조합하여 정규 URL을 만들 수 있습니다.
// src/pages/about.jsx
import React from "react";
import { graphql } from "gatsby";
import { Helmet } from "react-helmet";
export default ({ data, location }) => (
<>
<Helmet>
<title>{data.site.siteMetadata.title} – About</title>
<link
rel="canonical"
href={`${data.site.siteMetadata.siteUrl}${location.pathname}`}
/>
</Helmet>
{/* page content */}
</>
);
export const query = graphql`
{
site {
siteMetadata {
title
siteUrl
}
}
}
`;
siteUrl은gatsby-config.js에서 가져옵니다.location.pathname은 도메인 뒤에 오는 URL 부분(예:/about)입니다.
동적 템플릿
여러 콘텐츠(블로그 포스트, 태그 페이지 등)에서 재사용되는 템플릿이 있을 경우, Markdown front‑matter에 정의된 slug를 사용해 정규 URL을 동일한 방식으로 구성할 수 있습니다.
1. front‑matter에 slug 추가
---
slug: "how-to-create-canonical-urls-in-gatsby"
title: "How to create canonical URLs in Gatsby?"
---
2. 데이터 쿼리
# src/templates/blog-post.jsx
export const query = graphql`
query BlogPostQuery($slug: String!) {
site {
siteMetadata {
siteUrl
}
}
markdownRemark(frontmatter: { slug: { eq: $slug } }) {
frontmatter {
slug
title
}
}
}
`;
3. 컴포넌트에서 데이터 사용
// src/templates/blog-post.jsx
import React from "react";
import { Helmet } from "react-helmet";
export default ({ data }) => (
<>
<Helmet>
<title>{data.markdownRemark.frontmatter.title}</title>
<link
rel="canonical"
href={`${data.site.siteMetadata.siteUrl}/${data.markdownRemark.frontmatter.slug}`}
/>
</Helmet>
{/* the content of your blog post */}
</>
);
재사용 가능한 SEO 컴포넌트
같은 <Helmet> 로직을 반복하지 않으려면, 페이지나 템플릿 어디에든 삽입할 수 있는 작은 Seo 컴포넌트를 만들어 사용합니다.
// src/components/Seo.jsx
import React from "react";
import { Helmet } from "react-helmet";
export const Seo = ({ canonicalUrl, siteTitle, title }) => (
<Helmet>
<title>{siteTitle} – {title}</title>
{canonicalUrl && <link rel="canonical" href={canonicalUrl} />}
</Helmet>
);
정적 페이지에서 사용
// src/pages/about.jsx
import React from "react";
import { graphql } from "gatsby";
import { Seo } from "../components/Seo";
export default ({ data, location }) => (
<>
<Seo
siteTitle={data.site.siteMetadata.title}
title="About"
canonicalUrl={`${data.site.siteMetadata.siteUrl}${location.pathname}`}
/>
{/* page content */}
</>
);
export const query = graphql`
{
site {
siteMetadata {
title
siteUrl
}
}
}
`;
동적 블로그 포스트 템플릿에서 사용
// src/templates/blog-post.jsx
import React from "react";
import { graphql } from "gatsby";
import { Seo } from "../components/Seo";
export default ({ data }) => (
<>
<Seo
siteTitle={data.site.siteMetadata.title}
title={data.markdownRemark.frontmatter.title}
canonicalUrl={`${data.site.siteMetadata.siteUrl}/${data.markdownRemark.frontmatter.slug}`}
/>
{/* post content */}
</>
);
export const query = graphql`
query BlogPostQuery($slug: String!) {
site {
siteMetadata {
title
siteUrl
}
}
markdownRemark(frontmatter: { slug: { eq: $slug } }) {
frontmatter {
slug
title
}
}
}
`;
결론
캐노니컬 URL을 설정하는 것은 모든 웹사이트에서 수행해야 할 첫 번째 SEO 단계 중 하나입니다. 특히 콘텐츠를 다른 플랫폼(Medium, dev.to 등)으로 배포할 때 중요합니다.
Gatsby를 사용하면 정적 페이지와 동적 템플릿 모두에 대해 캐노니컬 URL을 자동으로 생성할 수 있으며, 작은 재사용 가능한 Seo 컴포넌트가 코드를 DRY하게 유지하고 관리하기 쉽게 해줍니다.
