Next.js로 나만의 블로그 만들기 [3] <meta> 태그를 활용해서 SEO 향상시키기

May 12, 2023

블로그 공유에 겉멋 추가하기

Next.js로 나만의 블로그 만들기 [3] <meta> 태그를 활용해서 SEO 향상시키기

개요

일상 속에서 카카오톡이나 기타 메신저들을 사용하여 링크를 공유해본 경험이 다들 존재할 것이다. 링크를 공유할시 페이지의 썸네일과 간단한 정보들이 담기는걸 본 적이 있을텐데 이러한 기능은 SEO적인 측면에서 큰 도움이 된다.

Open Graph

Open Graph
Open Graph
오픈 그래프(Open Graph)HTMLmeta 태그 중 og:XXX 형태의 태그를 찾아서 웹 페이지를 공유할 때 이용자가 더욱 자세한 정보들을 얻을 수 있게 해주는 프로토콜의 일종이다.

적용법

오픈 그래프를 적용하는 법은 생각보다 간단하다. HTMLhead 영역에 오픈그래프가 요구하는 meta 태그 형식만 맞추어서 삽입하면 된다.
1import { DOMAIN, DOMAIN_KOR } from "@/constants/domain" 2import PageType from "@/types/page" 3import Post from "@/types/post" 4import Head from "next/head" 5import { useRouter } from "next/router" 6 7type Props = { 8 post?: Post, 9 page: PageType, 10} 11 12type MetaDataType = { 13 title: string, 14 url: string, 15 image?: string, 16 desc?: string, 17} 18 19type ctxType = { 20 category?: string, 21 slug?: string, 22 tag?: string, 23} 24 25const getMetaData = (pageType: PageType, ctx: ctxType, post?: Post) : MetaDataType => { 26 const { category, slug, tag } = ctx; 27 const BASIC_THUMBNAIL = '/assets/seo/meta_thumbnail.png' 28 const metaData = { 29 title: '', 30 url: '', 31 desc: '', 32 image: BASIC_THUMBNAIL 33 }; 34 35 switch (pageType) { 36 case PageType.Post: 37 if (!post) break; 38 metaData.title = `${post?.title} | ${DOMAIN}`, 39 metaData.url = `${DOMAIN}/post/?${category}/${slug}`; 40 metaData.desc = post.description; 41 metaData.image = post.thumbnail; 42 break; 43 case PageType.Main: 44 metaData.title = `${DOMAIN_KOR} | ${DOMAIN}`, 45 metaData.url = `${DOMAIN}`; 46 metaData.desc = `${DOMAIN_KOR}입니다`; 47 break; 48 case PageType.Category: 49 metaData.title = `${category} | ${DOMAIN}`; 50 metaData.url = `${DOMAIN}/category/${category}`; 51 metaData.desc = `${category} Category Posts`; 52 break; 53 case PageType.Tags: 54 metaData.title = `Tags | ${DOMAIN}`; 55 metaData.url = `${DOMAIN}/tags`; 56 metaData.desc = `Tags List`; 57 break; 58 case PageType.Tag: 59 metaData.title = `${tag} | ${DOMAIN}`; 60 metaData.url = `${DOMAIN}/tags/${tag}`; 61 metaData.desc = `${tag} Tag Posts`; 62 break; 63 case PageType.About: 64 metaData.title = `About | ${DOMAIN}`; 65 metaData.url = `${DOMAIN}/about`; 66 metaData.desc = 'About Myself'; 67 break; 68 } 69 70 return metaData; 71} 72 73const SeoHead = ({ post, page } : Props) => { 74 const router = useRouter(); 75 const metaData = getMetaData(page, router.query, post); 76 77 return ( 78 <Head> 79 <link rel="apple-touch-icon" sizes="57x57" href="/assets/seo/favicons/apple-icon-57x57.png"></link> 80 <link rel="apple-touch-icon" sizes="60x60" href="/assets/seo/favicons/apple-icon-60x60.png"></link> 81 <link rel="apple-touch-icon" sizes="72x72" href="/assets/seo/favicons/apple-icon-72x72.png"></link> 82 <link rel="apple-touch-icon" sizes="76x76" href="/assets/seo/favicons/apple-icon-76x76.png"></link> 83 <link rel="apple-touch-icon" sizes="114x114" href="/assets/seo/favicons/apple-icon-114x114.png"></link> 84 <link rel="apple-touch-icon" sizes="120x120" href="/assets/seo/favicons/apple-icon-120x120.png"></link> 85 <link rel="apple-touch-icon" sizes="144x144" href="/assets/seo/favicons/apple-icon-144x144.png"></link> 86 <link rel="apple-touch-icon" sizes="152x152" href="/assets/seo/favicons/apple-icon-152x152.png"></link> 87 <link rel="apple-touch-icon" sizes="180x180" href="/assets/seo/favicons/apple-icon-180x180.png"></link> 88 <link rel="icon" type="image/png" sizes="192x192" href="/assets/seo/favicons/android-icon-192x192.png"></link> 89 <link rel="icon" type="image/png" sizes="32x32" href="/assets/seo/favicons/favicon-32x32.png"></link> 90 <link rel="icon" type="image/png" sizes="96x96" href="/assets/seo/favicons/favicon-96x96.png"></link> 91 <link rel="icon" type="image/png" sizes="16x16" href="/assets/seo/favicons/favicon-16x16.png"></link> 92 <link rel="icon" href="/assets/seo/favicons/favicon.ico" /> 93 <meta name="msapplication-TileColor" content="#2A2A2A" /> 94 <meta name="msapplication-TileImage" content="/ms-icon-144x144.png" /> 95 <meta name="theme-color" content="#2A2A2A" /> 96 <meta property="og:title" content={metaData.title} /> 97 <meta property="og:url" content={metaData.url} /> 98 <meta property="og:image" content={metaData.image} /> 99 <meta 100 property="og:description" 101 content={metaData.desc} 102 /> 103 <meta name="twitter:card" content="summary" /> 104 <meta property="twitter:domain" content={DOMAIN} /> 105 <meta property="twitter:url" content={metaData.url} /> 106 <meta name="twitter:title" content={metaData.title} /> 107 <meta name="twitter:description" content={metaData.desc} /> 108 <meta name="twitter:image" content={metaData.image} /> 109 <meta 110 name="description" 111 content={metaData.desc} 112 /> 113 <title>{metaData.title}</title> 114 </Head> 115 ) 116} 117 118export default SeoHead; 119
1<meta property="og:title" content="{metaData.title}" /> 2<meta property="og:url" content="{metaData.url}" /> 3<meta property="og:image" content="{metaData.image}" /> 4<meta property="og:description" content="{metaData.desc}" /> 5<meta name="twitter:card" content="summary" /> 6<meta property="twitter:domain" content="{DOMAIN}" /> 7<meta property="twitter:url" content="{metaData.url}" /> 8<meta name="twitter:title" content="{metaData.title}" /> 9<meta name="twitter:description" content="{metaData.desc}" /> 10<meta name="twitter:image" content="{metaData.image}" /> 11
오픈 그래프에는 여러가지 어트리뷰트 옵션이 있지만 위와 같은 기본사항만 입력해줘도 충분히 멋진 결과물을 얻을 수 있다. content 어트리뷰트에는 각자 알맞은 값들을 할당해주면 된다. 썸네일 이미지 같은 경우에는 1200*630px 해상도가 권장된다. 나는 페이지별로 content 영역을 다르게 표현해주고 싶어서 페이지에 따른 메타데이터를 반환하는 함수를 따로 분리하였다.
1const getMetaData = (pageType: PageType, ctx: ctxType, post?: Post): MetaDataType => { 2 const { category, slug, tag } = ctx; 3 const BASIC_THUMBNAIL = '/assets/seo/meta_thumbnail.png'; 4 const metaData = { 5 title: '', 6 url: '', 7 desc: '', 8 image: BASIC_THUMBNAIL, 9 }; 10 11 switch (pageType) { 12 case PageType.Post: 13 if (!post) break; 14 (metaData.title = `${post?.title} | ${DOMAIN}`), (metaData.url = `${DOMAIN}/post/?${category}/${slug}`); 15 metaData.desc = post.description; 16 metaData.image = post.thumbnail; 17 break; 18 case PageType.Main: 19 (metaData.title = `${DOMAIN_KOR} | ${DOMAIN}`), (metaData.url = `${DOMAIN}`); 20 metaData.desc = `${DOMAIN_KOR}입니다`; 21 break; 22 case PageType.Category: 23 metaData.title = `${category} | ${DOMAIN}`; 24 metaData.url = `${DOMAIN}/category/${category}`; 25 metaData.desc = `${category} Category Posts`; 26 break; 27 case PageType.Tags: 28 metaData.title = `Tags | ${DOMAIN}`; 29 metaData.url = `${DOMAIN}/tags`; 30 metaData.desc = `Tags List`; 31 break; 32 case PageType.Tag: 33 metaData.title = `${tag} | ${DOMAIN}`; 34 metaData.url = `${DOMAIN}/tags/${tag}`; 35 metaData.desc = `${tag} Tag Posts`; 36 break; 37 case PageType.About: 38 metaData.title = `About | ${DOMAIN}`; 39 metaData.url = `${DOMAIN}/about`; 40 metaData.desc = 'About Myself'; 41 break; 42 } 43 44 return metaData; 45}; 46

결과

메인 페이지
메인 페이지
포스트 페이지
포스트 페이지
게다가 오픈 그래프의 적용 여부를 테스트해주는 사이트 또한 존재한다.

favicon

파비콘은 브라우저의 주소창에 표시되는 웹페이지를 대표하는 아이콘이다. 간단한 아이콘을 추가하여 유저에게 사이트에 대한 이미지를 심어줄 수 있다.
유명 기업의 favicons
유명 기업의 favicons

favicon generator

이러한 favicon들을 브라우저가 요구하는 양식에 맞춰 자동으로 생성해주는 사이트가 있다. 192*192px의 png 파일을 업로드하면 다양한 양식의 아이콘 이미지 파일과 태그들을 출력해준다.
세상엔 좋은 사이트들이 참 많습니다
세상엔 좋은 사이트들이 참 많습니다

결과

favicon이 적용된 모습
favicon이 적용된 모습