meta 태그
<meta> 태그는 HTML 문서의 <head>와 </head> 사이에 입력하는 특수 태그로서 해당 문서에 대한 정보인 메타데이터(metadata)를 정의할 때 사용합니다.
meta태그 종류
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="keywords" content="HTML, CSS, JavaScript">
<meta name="description" content="탐구한 것들을 기록하는 장소입니다." />
<meta name="author " content="minsun">
OpenGraph
오픈그래프는 웹페이지가 소셜 미디어 또는 오픈그래프를 활용한 사이트로 공유될때 사용되어지는 정보이다.
기본적으로 설정해야하는 og 메타태그
<meta property="og:type" content="website"> <meta property="og:url" content="https://example.com/page.html"> <meta property="og:title" content="Content Title"> <meta property="og:image" content="https://example.com/image.jpg"> <meta property="og:description" content="Description Here"> <meta property="og:site_name" content="Site Name"> <meta property="og:locale" content="en_US"> <!-- 다음의 태그는 필수는 아니지만, 포함하는 것을 추천함 --> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="630">
Naver 블로그, 카카오톡 미리보기 설정
<meta property="og:title" content="콘텐츠 제목" /> <meta property="og:url" content="웹페이지 URL" /> <meta property="og:type" content="웹페이지 타입(blog, website 등)" /> <meta property="og:image" content="표시되는 이미지" /> <meta property="og:title" content="웹사이트 이름" /> <meta property="og:description" content="웹페이지 설명" />
트위터 미리보기 설정
<meta name="twitter:card" content="트위터 카드 타입(요약정보, 사진, 비디오)" /> <meta name="twitter:title" content="콘텐츠 제목" /> <meta name="twitter:description" content="웹페이지 설명" /> <meta name="twitter:image" content="표시되는 이미지 " />
모바일 앱 미리보기 설정
<--iOS--> <meta property="al:ios:url" content=" ios 앱 URL" /> <meta property="al:ios:app_store_id" content="ios 앱스토어 ID" /> <meta property="al:ios:app_name" content="ios 앱 이름" /> <--Android--> <meta property="al:android:url" content="안드로이드 앱 URL" /> <meta property="al:android:app_name" content="안드로이드 앱 이름" /> <meta property="al:android:package" content="안드로이드 패키지 이름" /> <meta property="al:web:url" content="안드로이드 앱 URL" />
Next.js에서 meta 태그 적용하기
개인적으로 Layout에서 화면 구성을 하고 싶어서 seo를 컴포넌트 화 시킨 후 Layout파일에 배치시킨 후 최상단인 _app.tsx에 Component 를 Layout로 감쌌다.
// components/seo.tsx import Head from "next/head"; export default function Seo() { return ( <Head> <title>MinSun's Blog</title> <meta name="viewport" content="initial-scale=1.0, width=device-width" /> <meta property="og:title" content={"MinSun's Blog"} /> <meta property="og:site_name" content="MinSun's Blog" /> <meta property="og:description" content={"탐구한 것들을 기록하는 장소입니다."} /> <meta property="og:type" content="website" /> <meta property="og:url" content={"https://min-sun.vercel.app/"} /> <meta property="og:image" content={"https://images.unsplash.com/image"} /> <meta property="og:image:width" content="1200" /> <meta property="og:image:height" content="630" /> <meta property="og:article:author" content="MinSun" /> </Head> ); }
// components/Layout.tsx import Footer from "./Footer"; import Header from "./Header"; import Seo from "./Seo"; export default function Layout({ children }) { return ( <main> <Seo /> <Header /> <section> {children} </section> <Footer /> </main> ); }
// _app.tsx import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; export default function App({Component, pageProps: { session, ...pageProps },}) { return ( <Layout> <Component {...pageProps} /> </Layout> ); }
만약 적용안되면 next/head들을 _app.jsx로 옮기기
Seo를 컴포넌트 화 시킨 후 각 페이지마다(pages 폴더 하위에 있는 파일 모두 다) return 바로 하위에서 불러오면 된다.
해당 seo 컴포넌트는 title, desc, url, image 값이 있으면 적용한 값을 없으면 || 옆 defult 값이 적용되도록 되어있다.
// components/seo.tsx import Head from "next/head"; interface SeoType { title: string; desc?: string; url?: string; image?: string; } export default function Seo({ title, desc, url, image }: SeoType) { return ( <Head> <title>{title ? title : "MinSun's Blog"}</title> <meta name="viewport" content="initial-scale=1.0, width=device-width" /> <meta property="og:title" content={title ? title : "MinSun's Blog"} /> <meta property="og:site_name" content="MinSun's Blog" /> <meta property="og:description" content={desc || "탐구한 것들을 기록하는 장소입니다."} /> <meta property="og:type" content="website" /> <meta property="og:url" content={url || "https://min-sun.vercel.app/"} /> <meta property="og:image" content={ image || "https://images.unsplash.com/image" } /> <meta property="og:image:width" content="1200" /> <meta property="og:image:height" content="630" /> <meta property="og:article:author" content="MinSun" /> </Head> ); }
동적으로 들어오는 값들은 getServerSideProps로 받아온 데이터만 쓸 수 있다.
// index.tsx import Seo from "@/components/seo"; export default function About() { return ( <> <Seo title={`MinSun's Blog | About`} /> <div> <div className="flex items-center justify-center gap-5 flex-col-reverse lg:flex-row"> <p className="text-center lg:text-left"> About </p> </div> </div> </> ); } // blog/[...id].tsx import axios from "axios"; import { NextPageContext } from "next"; import UseProperties from "libs/useProperties"; import { BASE_URL, TOKEN } from "libs/config"; import Seo from "@/components/seo"; import { useRouter } from "next/router"; export default function blockDetail({ propertiesData }: any) { const itemData = UseProperties(propertiesData); const router = useRouter(); return ( <> <Seo title={itemData.name} url={BASE_URL + "/" + router.asPath} desc={itemData.description} image={propertiesData.cover?.external.url} /> <p className="text-center lg:text-left"> blogDetail </p> </> ); } export async function getServerSideProps(context: NextPageContext) { const { query } = context; const axiosConfig = { headers: { .... }, }; const responseProperties = axios.get( `https://api.notion.com/v1/pages/${query.id}`, axiosConfig ); const data = responseProperties.data; return { props: {data}, }; }
후기
동적 메타 태그적용 하면서 해맸던 점이 meta태그들이 중복으로 들어가는 문제 때문이었다.
알고 보니 정적 메타 태그에서처럼 layout에 <Seo />를 주면 안된다. layout에 선언한 <Seo />가 선언 안 한 페이지들에는 default 값으로만 이루어진 meta태그들이 들어가는 줄 알았는데 그러면 선언한 페이지 meta와 layout meta 두 개가 중복되기 때문에 layout에있는 <Seo />를 삭제 해야 한다.
meta 태그 적용 확인하는 방법
카카오 공유 디버그
url에 해당 주소 넣으면 스크랩 결과, Open Graph 정보 보여줌
만약 이미지 등 무언가를 변경했는데 적용이 안되면 캐시 초기화 후 디버그 다시하면된다.