Next.js’da SEO: App Router’da metadata, sitemap va robots
Amaliyot3 daqInnovialabs tahririyati
Qisqacha
App Router’da SEO kod orqali sozlanadi — sarlavha, canonical va hreflang uchun metadata obyekti yoki generateMetadata, skanerlash uchun sitemap.ts va robots.ts, prevyu uchun opengraph-image; asosiysi — metadataBase orqali absolyut URL va har bir sahifaning o‘z canonical’i.
App Router’da SEO qanday tuzilgan
App Router’da <head> teglarini qo‘lda yozish shart emas. Next.js ularni bir nechta manbadan yig‘adi:
metadata—layout.tsxyokipage.tsxdagi statik obyekt;generateMetadata— dinamik sahifalar uchun funksiya;apppapkasidagi maxsus fayllarsitemap.ts,robots.ts,opengraph-image.tsx.
Metadata meros qilib olinadi: sahifa yuqoridagi barcha layout’lardan maydonlarni oladi va o‘zinikilari bilan almashtiradi. Bu qulay, ammo quyida keltirilgan xatolarning manbai ham shu.
Layout’dagi asosiy metadata
// app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: { default: 'Kompaniya', template: '%s — Kompaniya' },
description: 'Sayt haqida qisqa tavsif',
}
metadataBase canonical, hreflang va Open Graph’dagi nisbiy yo‘llarni (/blog/post) absolyut URL’ga aylantiradi. Usiz ijtimoiy tarmoqlardagi prevyu havolalari buzilishi mumkin.
Dinamik sahifalar uchun generateMetadata
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'
type Props = { params: Promise<{ slug: string }> }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const post = await getPost(slug)
return {
title: post.title,
description: post.description,
alternates: {
canonical: `/blog/${slug}`,
languages: {
uz: `/uz/blog/${slug}`,
en: `/en/blog/${slug}`,
'x-default': `/en/blog/${slug}`,
},
},
openGraph: { type: 'article', title: post.title },
}
}
Next.js’ning yangi versiyalarida params — Promise, shuning uchun uni await qilish kerak. generateMetadata va sahifaning o‘zidagi bir xil parametrli fetch so‘rovlari dedublikatsiya qilinadi, ortiqcha yuk bo‘lmaydi. Mavjud bo‘lmagan slug uchun notFound() chaqiring, shunda server 200 kodli bo‘sh sahifa emas, 404 qaytaradi.
sitemap.ts va robots.ts
// app/sitemap.ts
import type { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts()
return posts.map((p) => ({
url: `https://example.com/uz/blog/${p.slug}`,
lastModified: p.updatedAt,
alternates: {
languages: { en: `https://example.com/en/blog/${p.slug}` },
},
}))
}
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: '*', allow: '/', disallow: '/admin/' },
sitemap: 'https://example.com/sitemap.xml',
}
}
Sitemap’ga faqat 200 kodli kanonik URL’larni qo‘ying. Manzillar bitta fayl limitidan (50 000) ko‘p bo‘lsa, kartani generateSitemaps orqali bo‘ling.
Open Graph rasmlari
Sahifa yonidagi opengraph-image.tsx (yoki .png/.jpg) fayli og:imageni avtomatik qo‘shadi. next/ogdagi ImageResponse yordamida rasmni maqola sarlavhasidan generatsiya qilish mumkin. Tavsiya etilgan o‘lcham — 1200×630.
Sahifalar indekslanmasligiga olib keladigan odatiy xatolar
- Ildiz layout’dagi canonical.
alternates.canonical: '/'barcha sahifalarga meros bo‘lib o‘tadi va ularning hammasi bosh sahifaga ishora qiladi. Canonical’ni har bir sahifada bering. metadataBaseyo‘q — nisbiy canonical va og:image noto‘g‘ri yig‘iladi.robots: { index: false }staging’dan qolib ketgan yoki umumiy layout’da berilgan.- O‘zaro bo‘lmagan hreflang: o‘zbekcha versiya inglizchaga havola beradi, inglizchasi esa yo‘q. Har bir versiya qolgan barchasini va o‘zini sanab o‘tishi kerak.
- Sitemap’da redirektlar, 404 va kanonik bo‘lmagan manzillar — robot byudjetni behuda sarflaydi va kartaga kamroq ishonadi.
- Bo‘sh HTML. Kontent faqat klientda
'use client'vauseEffectorqali yuklansa, robot bo‘sh sahifani ko‘rishi mumkin. Asosiy matnni serverda render qiling. - Yumshoq 404: «topilmadi» sahifasi
notFound()o‘rniga 200 kodini qaytaradi. - Slesh bilan nomuvofiqlik:
/blogva/blog/ikkalasi ham redirektsiz ochiladi. - Yupqa va takroriy sahifalar: Google minglab deyarli bir xil sahifalarni ko‘pincha skanerlaydi, lekin indekslamaydi.
Natijani qanday tekshirish mumkin
- Sahifaning manba kodini oching va
<title>,canonical,hreflang,og:imageni toping. - Brauzerda
/sitemap.xmlva/robots.txtni tekshiring. - Search Console’da URL tekshiruvidan foydalaning: u Google qaysi canonical’ni tanlaganini va kontentni ko‘rayotganini ko‘rsatadi.