Next.js’da SEO: metama’lumotlar, sitemap, robots.txt va OG-rasmlar
Amaliyot4 daqInnovialabs tahririyati
Qisqacha
App Router’da SEO metadata eksporti yoki generateMetadata, sitemap.ts, robots.ts va opengraph-image.tsx maxsus fayllari hamda JSON-LD skripti orqali sozlanadi; ko‘p tilli marshrutlarda har bir sahifaga canonical va hreflang alternativlari kerak.
Qisqacha javob
Next.js App Router loyihasida SEO plagini kerak emas — hammasi ichki:
- metadata yoki generateMetadata
layout.tsxvapage.tsxda — title, description, canonical, hreflang va Open Graph uchun; - app/sitemap.ts va app/robots.ts —
sitemap.xmlvarobots.txtni yaratadi; - opengraph-image.tsx — ijtimoiy tarmoqlar uchun rasmni koddan chizadi;
<script type="application/ld+json">tegi — tuzilgan ma’lumotlar uchun.
Quyidagi misollar App Router qoidalariga amal qiladi; o‘z Next.js versiyangiz uchun rasmiy hujjatlarni tekshiring — masalan, params Promise bo‘lgani kabi tafsilotlar vaqt o‘tishi bilan o‘zgargan.
Asosiy layout’dagi bazaviy sozlamalar
Canonical va Open Graph’dagi nisbiy URL’lar absolyut bo‘lishi uchun metadataBase ni bir marta belgilang:
// app/[lang]/layout.tsx
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: { default: 'Studio', template: '%s | Studio' },
}
template har bir sahifa sarlavhasiga sayt nomini avtomatik qo‘shadi.
Dinamik metama’lumotlar, canonical va hreflang
Ma’lumotlardan quriladigan sahifalar uchun generateMetadata dan foydalaning. Ko‘p tilli saytda har bir til versiyasining o‘z canonical i va x-default ni ham o‘z ichiga olgan to‘liq hreflang alternativlari bo‘lishi kerak:
// app/[lang]/blog/[slug]/page.tsx
type Props = { params: Promise<{ lang: string; slug: string }> }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { lang, slug } = await params
const post = await getPost(slug, lang)
return {
title: post.title,
description: post.description,
alternates: {
canonical: `/${lang}/blog/${slug}`,
languages: {
ru: `/ru/blog/${slug}`,
en: `/en/blog/${slug}`,
uz: `/uz/blog/${slug}`,
'x-default': `/ru/blog/${slug}`,
},
},
openGraph: { type: 'article', title: post.title, description: post.description },
}
}
Asosiy qoidalar:
- canonical asosiy til versiyasiga emas, sahifaning o‘ziga ishora qiladi;
- har bir til versiyasi o‘zini ham qo‘shib, barcha versiyalarni sanab o‘tadi;
- faqat haqiqatan mavjud tarjimalarni ko‘rsating.
Dinamik sitemap
// app/sitemap.ts
import type { MetadataRoute } from 'next'
const base = 'https://example.com'
const langs = ['ru', 'en', 'uz']
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts()
return posts.flatMap((p) =>
langs.map((lang) => ({
url: `${base}/${lang}/blog/${p.slug}`,
lastModified: p.updatedAt,
alternates: {
languages: Object.fromEntries(langs.map((l) => [l, `${base}/${l}/blog/${p.slug}`])),
},
})),
)
}
Bitta sitemap faylida ko‘pi bilan 50 000 ta URL bo‘lishi mumkin. Katta saytlar uchun Next.js’da xaritani bir nechta faylga bo‘ladigan generateSitemaps bor. lastModified ga build vaqtini emas, haqiqiy sanani yozing, aks holda qidiruv tizimlari unga ishonmay qo‘yadi.
robots.txt
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: '*', allow: '/', disallow: ['/api/', '/admin/'] },
sitemap: 'https://example.com/sitemap.xml',
}
}
Esda tuting: disallow indeksatsiyani emas, skanerlashni taqiqlaydi. Sahifani qidiruv natijalaridan olib tashlash uchun uning metama’lumotlarida robots: { index: false } ni ko‘rsating va qidiruv tizimi bu tegni ko‘rishi uchun sahifani skanerlashga ochiq qoldiring.
Generatsiya qilinadigan Open Graph rasmlar
Sahifa yonidagi opengraph-image.tsx fayli uning ijtimoiy tarmoqlar uchun prevyusini yaratadi. ImageResponse JSX’ni PNG’ga aylantiradi:
// app/[lang]/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export default async function Image({ params }: { params: Promise<{ lang: string; slug: string }> }) {
const { lang, slug } = await params
const post = await getPost(slug, lang)
return new ImageResponse(
<div style={{ display: 'flex', width: '100%', height: '100%', padding: 80, fontSize: 64, background: '#120B24', color: '#fff' }}>
{post.title}
</div>,
size,
)
}
og:image teglarini Next.js o‘zi qo‘shadi. Faqat flexbox va CSS’ning bir qismi qo‘llab-quvvatlanadi; kirill va o‘zbekcha belgilar uchun ularni o‘z ichiga olgan shriftni ulang.
JSON-LD tuzilgan ma’lumotlari
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
datePublished: post.date,
inLanguage: lang,
}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
/>
< ni ekranlash kontent orqali HTML kiritilishidan himoya qiladi. Natijani Google Rich Results Test’da tekshiring.
Relizdan oldingi chek-list
- Har bir sahifada noyob title va description.
- Barcha til versiyalarida canonical va hreflang.
- Barcha ochiq sahifalar sitemap’da, ichida redirect va 404 yo‘q.
- Bog‘liq sahifalar o‘rtasida ichki havolalar, robotlar har bir URL’ni sitemap’siz ham topishi uchun.
- Sitemap Google Search Console va Yandex Webmaster’ga qo‘shilgan.