cFyt
İletişim

Next.js Sitemap Oluşturma

Next.js'de daha iyi SEO için otomatik sitemap oluşturucu nasıl yapılır?

cFyt

cFyt tarafından

yazıldı.3786 görüntülenme

Next.js bir full stack react framework'ü olarak oldukça popüler. Şahsen en çok kullandığım ve bence en iyisi. Peki sizce de sitemap oluşturmak için eklentisi olması gerekmiyor mu ? Aslında sitemap.xml oluşturmak için yöntemler var fakat bunlar otomatik olarak yapmıyor. Tabi ki benim de kullandığım otomatik olarak oluşturulan dinamik yöntemi sizlerle paylaşıcam.

Paketler

Kullanacağımız bir paket olacak öncelikle bunu indirmemiz gerekiyor.

  • next-sitemap

npm

$ npm i next-sitemap

yarn

$ yarn add next-sitemap

Sayfamızı oluşturalım

pages klasörü altına sitemap.xml.js veya sitemap.xml adlı klasör açıp içerisine index.js dosyamızı oluşturalım.

import { getServerSideSitemap } from 'next-sitemap' import fs from 'fs' import path from 'path'

Bize gerekli olan import işlemleri bu şekilde.

İçerisinde bir şey olmayan default bir function oluşturalım.

export default function SitemapIndex() { }

Yapacağımız işlemler server-side olacağı için bu fonksiyonun bir şey döndürmesine gerek yok.

export const getServerSideProps = async (ctx) => {}

Sayfa render olmadan bu fonksiyon içerisinde bir return işlemi yapacağız. Fakat önce ne yaptığımızı anlayalım.

export const getServerSideProps = async (ctx) => { return getServerSideSitemap(ctx, [{ loc: 'https://cfyt.me', lastmod: new Date().toISOString() }]) }

Bu işlemin sonucunda sayfamız böyle gözükecek

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"> <url> <loc>https://cfyt.me</loc> <lastmod>2022-10-10T12:17:43.162Z</lastmod> </url> </urlset>

Anlayacağınız verdiğimiz array içerisindeki değerleri xml formatında bir çıktı veriyor. https://example.com/sitemap.xml adresinde oluştuğu için static bir dosyaymış gibi her istekte işlenecek. Şimdi ise tüm sayfalarımızı otomatik olarak ekleyelim.

let pagePath = "" if (process.env.NODE_ENV === 'production') { pagePath = path.join(process.cwd(), '.next', 'server', 'pages-manifest.json') } else { pagePath = path.join(process.cwd(), 'pages') }

pages klasörü altındaki dosyalarımıza erişmek istiyoruz. Vercel'de yayınlarken ise bu dosyalar oluşmuyor ve var olan sayfaları tespit etmek zorlaşıyor. Build işlemi sornası oluşan pages-manifest.json dosyası tüm oluşturulan sayfaların bilgisini içeriyor.

{ "/_app": "pages/_app.js", "/_error": "pages/_error.js", "/_document": "pages/_document.js", "/about": "pages/about.html", "/contact": "pages/contact.html", "/": "pages/index.html", "/portfolio": "pages/portfolio.html", "/projects": "pages/projects.html", "/support": "pages/support.html", "/blog": "pages/blog.js", "/profile": "pages/profile.js", "/blog/[id]": "pages/blog/[id].js", "/sitemap.xml": "pages/sitemap.xml.js", "/404": "pages/404.html" }
let urls = [] if (process.env.NODE_ENV === 'production') { const routes = JSON.parse(fs.readFileSync(pagePath, 'utf8')) let keys = Object.keys(routes) console.log(fs.statSync(pagePath)) console.log(routes) let date = new Date() keys.forEach((route) => { if (route !== '/sitemap.xml' && !route.includes('dashboard') && !route.includes('api') && !route.includes('_') && !route.includes('[') && !route.includes('404')) { urls.push({ loc: `https://cfyt.me${route}`, lastmod: date.toISOString(), priority: route === '/' ? 1 : 0.5, }) } }) }

Projemiz production ortamındayken bu verileri array içerisinde tutuyoruz. Dosyasımızı açıp bazı filtrelemelerden geçiriyoruz. Dosyada oluşan bazı yolları eklemememiz gerek. Bunları kendiniz de belirleyebilirsiniz. Array içerisine loc lastmod priority gibi değerler ile ekliyoruz. loc değeri urlyi belirtiyor. lastmod son değiştirilme tarihini. Burada son değiştirilme tarihini bulamadığımız için şuanki zamanı giriyoruz. priority ise öncelik değeridir. 0 ile 1 arasında değer alır ve sayfaların önceliğini belirler.

} else { urls = fs.readdirSync(pagePath).filter(x => !x.includes('_') && !x.includes('sitemap') && !x.includes('index') && !x.includes('api') && !x.includes('dashboard')).map(f => ({ loc: `https://cfyt.me/${f.split('.')[0]}`, lastmod: new Date(fs.statSync(`${pagePath}/${f}`).mtime).toISOString(), })) urls = [{ loc: 'https://cfyt.me', lastmod: new Date(fs.statSync(`${pagePath}/index.js`).mtime).toISOString(), priority: 1, }, ...urls] }

Burada ise benzer işlemi development ortamı için yapıyoruz. (Ben development ortamında bunu oluşturmayacağım diyorsanız esgeçebilirsiniz). Buradaki mantık ise oldukça basit. Tüm pages klasörü altındaki dosyalarımı alıp array içerisine ekliyoruz. Buradaki tek fark dosyaların en son ne zaman değiştirildiğini görebilmek. (fs.statSync)

Eğer farklı klasörleme yapısı kullanıyorsanız klasör içerisindeki dosyalarınızı da eklemeniz gerek. Bunu yapmak ise basit size bırakıyorum :)

Şimdi ise fikir olması amacıyla dinamik url yollarını ekleyelim.

let client = await clientPromise let db = await client.db('blog') let posts = await db.collection('posts').find({}).toArray() posts.forEach((post) => { urls.push({ loc: `https://cfyt.me/blog/${post.title.toLowerCase().replace(/ /g, '-')}`, lastmod: new Date(post.date).toISOString(), }) })

Burada ise tüm blog verileri alıp teker teker url olarak ekliyoruz. Sizde yoksa veya farklı bir projeniz var ise buna göre ayarlayabilirsiniz.

return getServerSideSitemap(ctx, urls)

ve son olarak urllerimizi ekliyip return ediyoruz.

Son Görüntü

import { getServerSideSitemap } from 'next-sitemap' import fs from 'fs' import path from 'path' import clientPromise from 'lib/mongodb' export const getServerSideProps = async (ctx) => { let pagePath = "" if (process.env.NODE_ENV === 'production') { pagePath = path.join(process.cwd(), '.next', 'server', 'pages-manifest.json') } else { pagePath = path.join(process.cwd(), 'pages') } let urls = [] if (process.env.NODE_ENV === 'production') { const routes = JSON.parse(fs.readFileSync(pagePath, 'utf8')) let keys = Object.keys(routes) console.log(fs.statSync(pagePath)) console.log(routes) let date = new Date() keys.forEach((route) => { if (route !== '/sitemap.xml' && !route.includes('dashboard') && !route.includes('api') && !route.includes('_') && !route.includes('[') && !route.includes('404')) { urls.push({ loc: `https://cfyt.me${route}`, lastmod: date.toISOString(), priority: route === '/' ? 1 : 0.5, }) } }) } else { urls = fs.readdirSync(pagePath).filter(x => !x.includes('_') && !x.includes('sitemap') && !x.includes('index') && !x.includes('api') && !x.includes('dashboard')).map(f => ({ loc: `https://cfyt.me/${f.split('.')[0]}`, lastmod: new Date(fs.statSync(`${pagePath}/${f}`).mtime).toISOString(), })) urls = [{ loc: 'https://cfyt.me', lastmod: new Date(fs.statSync(`${pagePath}/index.js`).mtime).toISOString(), priority: 1, }, ...urls] } let client = await clientPromise let db = await client.db('blog') let posts = await db.collection('posts').find({}).toArray() posts.forEach((post) => { urls.push({ loc: `https://cfyt.me/blog/${post.title.toLowerCase().replace(/ /g, '-')}`, lastmod: new Date(post.date).toISOString(), priority: 0.9, }) }) return getServerSideSitemap(ctx, urls) } export default function SitemapIndex() { }

Çıktı:

https://cfyt.me/sitemap.xml

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"> <url> <loc>https://cfyt.me/about</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/contact</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>1</priority> </url> <url> <loc>https://cfyt.me/portfolio</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/projects</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/support</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/blog</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/profile</loc> <lastmod>2022-10-14T15:38:54.488Z</lastmod> <priority>0.5</priority> </url> <url> <loc>https://cfyt.me/blog/arrow-functions</loc> <lastmod>2022-10-07T14:01:30.288Z</lastmod> <priority>0.9</priority> </url> <url> <loc>https://cfyt.me/blog/dall-e-herkese-açık-hale-geldi</loc> <lastmod>2022-10-08T14:01:30.288Z</lastmod> <priority>0.9</priority> </url> <url> <loc>https://cfyt.me/blog/next.js-sitemap-oluşturma</loc> <lastmod>2022-10-10T12:42:54.846Z</lastmod> <priority>0.9</priority> </url> </urlset>

Robots.txt

robots.txt dosyasını ise public klasörü altında oluşturalım.

User-Agent: * Allow: Sitemap: https://cfyt.me/sitemap.xml

Sitemap urlmizi belirtiyoruz ve artık arama motoru botları sitemizi daha iyi bir şekilde indexliyor.

Umarım işinize yaramıştır.

Yorumlar

Yorum yapabilmek için giriş yapmalısınız.

Henüz yorum yapılmamış.