XSLT ile süslenen sitemap.xml'den gerçek bir HTML site haritasına
sitemap.xml'i insanlar da okuyabilsin diye önce bir XSLT stil dosyasıyla süsledim. Tarayıcılar XSLT desteğini kaldırma yoluna girince bundan vazgeçtim: XML yalnızca makineler için kaldı, insanlar için iki dilli ve prerender edilen bir /sitemap sayfası yazdım.
01XML'i insanlara göstermek
Sitenin sitemap.xml dosyası her sayfayı iki dilde listeliyor; her kayıtta diğer dildeki karşılık ve sayfanın paylaşım kartı da var. Arama motorları için tam olarak gereken bu. Ama dosyayı tarayıcıda açan bir insan, iç içe geçmiş etiketlerden oluşan bir ağaç görüyor. Site haritasının insanlar için de bir işe yaramasını istedim: hangi sayfalar var, hangi dilde, hangi adreste.
İlk çözüm eski ve bilinen bir yöntemdi. XML dosyasının başına bir xml-stylesheet işleme talimatı ekledim ve tarayıcıyı /sitemap.xsl adresindeki bir XSLT dosyasına yönlendirdim. Bu dosya da scripts/seo-files.mjs içinde üretiliyor ve text/xsl türüyle sunuluyordu. Tarayıcı XML'i bu dönüşümden geçirip sitenin renklerinde bir HTML tablosu gösteriyordu: paylaşım kartları, dil etiketleri ve diğer dile geçiş bağlantıları. Arama motorlarının tarayıcıları ise ham XML'i okumaya devam ediyordu.
<?xml-stylesheet type="text/xsl" href="/sitemap.xsl"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.sitemaps.org/schemas/sitemap/0.9">
<xsl:output method="html" encoding="UTF-8" indent="yes"
doctype-system="about:legacy-compat"/>
<xsl:template name="rel">
<xsl:param name="u"/>
<xsl:variable name="rest"
select="substring-after(substring-after($u, '://'), '/')"/>
<xsl:value-of select="concat('/', $rest)"/>
</xsl:template>02Neden vazgeçtim
Sayfayı Chrome'da açtığımda konsolda XSLT'nin kullanımdan kaldırılacağına dair bir uyarı çıktı. Tarayıcılar XSLT desteğini kaldırma yolunda. Bir özelliği, ortadan kalkacağı açıkça söylenen bir teknolojiye bağlamak çıkmaz sokak; bugün çalışıyor olması, bir gün sessizce çalışmayı bırakmayacağı anlamına gelmiyor.
Uyarı olmasa da bu yolun başka maliyetleri vardı. XSLT 1.0 ayrı bir dil ve oldukça kısıtlı: mutlak bir adresi göreli hale getirmek için bile yukarıdaki gibi iç içe substring-after çağrılarıyla bir şablon yazmak gerekiyordu. Görünüm, Vue uygulamasının tamamen dışında yaşıyordu; bileşenler, menü ve tasarım değişkenleri orada yoktu. Renkleri XSL dosyasının içindeki ayrı bir stil bloğunda yeniden yazmıştım. Sitedeki bir renk değiştiğinde bu kopyayı da hatırlamam gerekecekti.
03XML makineler için, HTML insanlar için
Sonunda işi ikiye ayırdım. XSL dosyası ve işleme talimatı kalktı; sitemap.xml yeniden düz bir XML oldu ve yalnızca makineler için duruyor. Dosyanın başındaki bir yorum, onu açan insanlara Türkçe ve İngilizce site haritası sayfalarının adreslerini ve robots.txt, llms.txt ve llms-full.txt dosyalarını gösteriyor.
Bu ayrımın sitemap.xml'e bir zararı olmadı. Arama motorları için önemli olan her şey yerinde: her adres için xhtml:link ile tr, en ve x-default alternatifleri, image:image ile paylaşım kartı, lastmod, changefreq ve priority. Ana sayfa 1.0, üst düzey sayfalar 0.8, proje ve yazı sayfaları 0.6, site haritası sayfasının kendisi ise 0.3 önceliğiyle listede.
İnsanlar için src/views/SitemapView.vue var. Bu, diğerleri gibi bir Vue rotası: /sitemap ve /en/sitemap adreslerinde yaşıyor, build sırasında iki dilde prerender ediliyor, kendi paylaşım kartı var ve publicPaths içinde olduğu için sitemap.xml'de de listeleniyor. Sayfaya altbilgideki bağlantıdan ulaşılıyor.
04/sitemap sayfası
Sayfa üç grup gösteriyor: sayfalar, projeler ve yazılar. Sayfalar ana sayfa ile menüdeki bağlantılardan, projeler kategori, yıl ve durumla, yazılar kategori ve tarihle listeleniyor. Her satırda sayfanın paylaşım kartından küçük bir görsel, başlık bağlantısı, mono yazıyla sayfanın adresi, kısa bir alt satır ve diğer dildeki karşılığa giden bir bağlantı var. Bu son bağlantı hreflang özelliği taşıyor. Kart görselleri bilerek göreli adresle yükleniyor; aynı sayfa localhost'ta, önizlemelerde ve canlı sitede aynı şekilde çalışıyor. Üstteki sayaç, publicPaths uzunluğunun iki katı kadar adres olduğunu gösteriyor.
En altta "Makineler için" bölümü var: sitemap.xml, robots.txt, llms.txt ve llms-full.txt, her biri kısa bir açıklamayla. Sayfanın JSON-LD'si bir CollectionPage düğümü ve bütün herkese açık sayfaları sırayla sayan bir ItemList içeriyor, yanında da bir BreadcrumbList var. Yani makineler de bu sayfayı bir dizin olarak tanıyabiliyor.
XML'i insanlara okutmaya çalışmak yerine insanlara kendi sayfalarını vermek daha dürüst bir çözüm.
05Geliştirme sunucusunda da aynı dosyalar
Site haritası sayfası makine dosyalarına bağlantı verip paylaşım kartlarını gösterdiği için, bu dosyaların geliştirme sırasında da var olması gerekiyordu. Normalde hepsi build sonunda üretiliyor. vite.config.ts içindeki küçük bir eklenti, yalnızca geliştirme sunucusunda çalışıyor ve /robots.txt, /sitemap.xml, /llms.txt, /llms-full.txt ile /og/<anahtar>.png isteklerini yakalıyor. İçeriği Vite'ın SSR yükleyicisiyle entry-server.ts üzerinden okuyor ve build'in kullandığı textFiles ile renderOg fonksiyonlarını çağırıyor.
const isText = ['/robots.txt', '/sitemap.xml', '/llms.txt', '/llms-full.txt'].includes(url)
const og = /^\/og\/([a-z0-9-]+)\.png$/.exec(url)
if (!isText && !og) return next()
const mod = await load(server) // ssrLoadModule('/src/app/entry-server.ts')
const seo = await import('./scripts/seo-files.mjs')Bunun güzel bir yan etkisi var: geliştirme sunucusunda gördüğüm dosya ile canlıya çıkan dosya aynı koddan geliyor. Bir yazının başlığını değiştirip sayfayı yenilediğimde sitemap.xml, llms.txt ve kart görseli de değişmiş oluyor.