๐ผ๏ธ Next.js App Router ๋ฉํ๋ฐ์ดํฐ & OG ์ด๋ฏธ์ง ์ค์ ์์ ๊ฐ์ด๋
๐ผ๏ธ Next.js App Router ๋ฉํ๋ฐ์ดํฐ & OG ์ด๋ฏธ์ง ์ค์ ์์ ๊ฐ์ด๋
Next.js App Router์์๋ ํ์ด์ง๋ณ ๋ฉํ๋ฐ์ดํฐ(SEO์ฉ ์ ๋ชฉ, ์ค๋ช
, OG ์ด๋ฏธ์ง ๋ฑ)๋ฅผ ์ฝ๊ฒ ์ค์ ํ ์ ์๊ณ ,
Open Graph ์ด๋ฏธ์ง(์์
๊ณต์ ์ธ๋ค์ผ)๋ ์ ์ ๋๋ ๋์ ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค.
โ 1. ์ ์ Open Graph ์ด๋ฏธ์ง ์ค์ ๋ฐฉ๋ฒ
๐ ๋๋ ํ ๋ฆฌ์ ์ด๋ฏธ์ง ํ์ผ ์ถ๊ฐํ๊ธฐ
ํด๋ ์์ opengraph-image.png ๋๋ twitter-image.png๋ฅผ ๋ฃ์ผ๋ฉด, ํด๋น ๊ฒฝ๋ก๋ก ์ ๊ทผ ์ ์๋์ผ๋ก ์ ์ฉ๋ฉ๋๋ค.
์์ ํด๋ ๊ตฌ์กฐ:
app/
โโโ opengraph-image.png ← ๋ฃจํธ ๋ฉํ ์ด๋ฏธ์ง
โโโ twitter-image.png
โโโ about/
โ โโโ page.tsx
โ โโโ opengraph-image.png ← about ํ์ด์ง ์ ์ฉ OG ์ด๋ฏธ์ง
- /about ํ์ด์ง ๊ณต์ ์: /about/opengraph-image.png๊ฐ OG ์ด๋ฏธ์ง๋ก ์ค์ ๋จ
- ์ด๋ฏธ์ง ํ์: .jpg, .png, .gif ๋ฑ
๐ง metadata ๊ฐ์ฒด๋ก ๋ฉํ์ ๋ณด ์ง์ ์ค์ ํ๊ธฐ
layout.tsx ๋๋ page.tsx ์์ metadata ๊ฐ์ฒด๋ฅผ export ํ๋ฉด, ๋ฉํ๋ฐ์ดํฐ๋ฅผ ํ๋ก๊ทธ๋๋ฐ์ ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
// app/about/page.tsx
export const metadata = {
title: 'ํ์ฌ ์๊ฐ - About Us',
description: '์ฐ๋ฆฌ ํ์ฌ์ ๋ํด ์์๋ณด์ธ์',
openGraph: {
title: 'About | MySite',
description: '์ฐ๋ฆฌ๋ ์ด๋ ๊ฒ ์ผํฉ๋๋ค.',
images: ['/about/opengraph-image.png'],
},
twitter: {
card: 'summary_large_image',
title: 'About Us',
images: ['/about/twitter-image.png'],
},
};
- openGraph.images์ twitter.images๋ ๋ฐฐ์ด ํํ๋ก ์ฌ๋ฌ ๊ฐ ์ค์ ๊ฐ๋ฅ
- SEO ๋ฐ ๊ณต์ ์ต์ ํ์ ๋งค์ฐ ์ค์
โ๏ธ 2. ๋์ OG ์ด๋ฏธ์ง ์์ฑ (ImageResponse)
๋ผ์ฐํธ๋ง๋ค ๋ค๋ฅธ OG ์ด๋ฏธ์ง๋ฅผ ๋ ๋๋งํ๊ณ ์ถ๋ค๋ฉด, Next.js์ ImageResponse API๋ฅผ ์ฌ์ฉํด ์๋ฒ์์ ์ด๋ฏธ์ง ์์ฑ์ด ๊ฐ๋ฅํฉ๋๋ค.
// app/posts/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og';
export const size = {
width: 1200,
height: 630,
};
export default async function OGImage({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(res => res.json());
return new ImageResponse(
(
),
size
);
}
- ๊ฐ ๊ฒ์๊ธ๋ง๋ค ๋์ ์ผ๋ก ์ ๋ชฉ์ด๋ ์ธ๋ค์ผ ํฌํจ ๊ฐ๋ฅ
- ๋ธ๋ผ์ฐ์ ๊ฐ ์์ฒญํ ๋๋ง๋ค ์ค์๊ฐ ์์ฑ๋จ
๐ ๋ฉํ ์ด๋ฏธ์ง ์ฌ์ด์ฆ ๊ฐ์ด๋
ํ๋ซํผ ๊ถ์ฅ ํฌ๊ธฐ ๋น๊ณ
Open Graph (Facebook ๋ฑ) | 1200×630 px | ๋น์จ 1.91:1 |
Twitter Card | 1200×600 px | summary_large_image ๊ธฐ์ค |
๊ฐ๋ฅํ ํ ์ด๋ฏธ์ง ์ฉ๋์ 1MB ๋ฏธ๋ง์ผ๋ก ์ ์งํ์ธ์.
๐งช ํ์ฉ ํ
- Open Graph, Twitter ๋ ๋ค ์ค์ ๊ฐ๋ฅ (์๋ก ๋ค๋ฅธ ์ด๋ฏธ์ง๋ ๊ฐ๋ฅ)
- SEO๋ฅผ ์ํด title, description, canonical๋ ํจ๊ป ๊ด๋ฆฌ
- ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ public ๊ฒฝ๋ก๋ CDN ๊ฒฝ๋ก๋ ์ฌ์ฉ ๊ฐ๋ฅ
- ๋์ ์์ฑ ์ Edge Runtime ์ฌ์ฉ ๊ฐ๋ฅ (๋น ๋ฅด๊ณ ํจ์จ์ )
โ ์์ฝ
ํญ๋ชฉ ์ค์ ๋ฐฉ์ ์์น/์ฌ์ฉ๋ฒ
์ ์ OG ์ด๋ฏธ์ง | ํ์ผ ์ง์ ์ถ๊ฐ | opengraph-image.png, twitter-image.png |
ํ๋ก๊ทธ๋๋ฐ ์ค์ | metadata export | layout.tsx, page.tsx |
๋์ ์ด๋ฏธ์ง ์์ฑ | ImageResponse() | opengraph-image.tsx ํ์ผ๋ก ์์ฑ |
Next.js, App Router, ๋ฉํ๋ฐ์ดํฐ ์ค์ , OG ์ด๋ฏธ์ง, Open Graph, Twitter ์นด๋, SEO ์ต์ ํ, ๋์ ์ธ๋ค์ผ, ImageResponse, ํ์ด์ง ๊ณต์ ์ต์ ํ