🏠 Home

πŸ“‚ Kategori

πŸ“ TeknologiπŸ“ GadgetπŸ“ LekturπŸ“ Finansial

JSON-LD VitePress: Kenapa Komponen Tidak Terdeteksi Google Rich Results?

JSON-LD VitePress: Kenapa Komponen Tidak Terdeteksi Google Rich Results?

Salah satu hal yang cukup menjebak saat membangun blog dengan VitePress adalah soal structured data. Kamu sudah menambahkan JSON-LD, sudah inspect di browser dan hasilnya ada, tapi begitu dicek di Google Rich Results Test hasilnya kosong. "No items detected."

Ini bukan bug aneh atau masalah di sisi Google. Ada alasan teknis yang cukup mendasar kenapa hal ini terjadi, dan solusinya pun sebenarnya sudah tersedia di VitePress sejak lama.

Masalah yang Sering Terjadi ​

Pendekatan paling umum yang dipakai developer adalah membuat komponen Vue seperti ini:

vue
<component :is="'script'" type="application/ld+json" v-html="jsonld" />

Atau kadang ditulis langsung di layout:

vue
<script type="application/ld+json" v-html="jsonld" />

Di browser, ini kelihatan benar. Kalau kamu buka DevTools dan lihat source HTML yang sudah dirender, tag script-nya ada, isinya pun sesuai. Tapi begitu diuji di Rich Results Test atau Google Search Console, structured data-nya tidak terdeteksi sama sekali.

Kenapa Bisa Terjadi? ​

Ini berkaitan langsung dengan cara kerja VitePress sebagai framework berbasis SSR + hydration.

VitePress melakukan rendering di sisi server untuk menghasilkan HTML awal, kemudian Vue mengambil alih di browser melalui proses yang disebut hydration. Komponen Vue seperti <script> dengan v-html tidak selalu masuk ke output HTML SSR secara konsisten. Dalam beberapa kasus, komponen tersebut baru "muncul" setelah proses hydration di browser selesai berjalan.

Masalahnya, Google crawler tidak menunggu JavaScript selesai dieksekusi saat mengindeks halaman. Crawler membaca HTML awal yang dikirimkan server, bukan versi halaman setelah semua script berjalan. Jadi walaupun JSON-LD-nya terlihat di browser (karena sudah melalui hydration), Google tidak pernah benar-benar melihatnya.

Ini kenapa kamu bisa merasa "sudah benar" tapi hasilnya tetap tidak terdeteksi.

Solusi yang Benar: Gunakan transformHead ​

VitePress menyediakan hook bernama transformHead di file konfigurasi. Fungsi ini berjalan saat proses build dan hasilnya langsung disertakan di dalam <head> HTML SSR, sebelum ada JavaScript yang berjalan.

Artinya, structured data benar-benar ada di HTML dari awal, bukan ditambahkan belakangan oleh Vue.

Contoh implementasinya di .vitepress/config.ts:

ts
export default {
  transformHead({ pageData }) {
    const fm = pageData.frontmatter

    return [
      [
        'script',
        { type: 'application/ld+json' },
        JSON.stringify({
          '@context': 'https://schema.org',
          '@type': 'BlogPosting',
          headline: fm.title,
          description: fm.description,
          image: fm.thumbnail,
          author: {
            '@type': 'Person',
            name: fm.author || 'Admin'
          },
          datePublished: fm.date
        })
      ]
    ]
  }
}

Dengan cara ini, setiap halaman yang memiliki frontmatter akan otomatis mendapatkan JSON-LD yang sesuai, dan structured data tersebut sudah ada di HTML sebelum crawler atau browser melakukan apa pun.

Perbandingan Kedua Pendekatan ​

MetodeTerdeteksi GoogleMasuk ke HTML SSRStabil di Production
Vue Component + v-htmlTidakTidak konsistenTidak
transformHeadYaYaYa

Perbedaannya bukan soal preferensi, tapi soal bagaimana data tersebut disertakan di HTML output.

Kesalahan Lain yang Sering Ikut Menyebabkan Masalah ​

Walaupun sudah menggunakan transformHead, ada beberapa hal yang bisa membuat structured data tetap tidak valid atau tidak terbaca:

URL tidak absolute. Google mengharuskan semua URL di dalam schema menggunakan format lengkap dengan protokol. Jangan pakai /about atau /images/cover.jpg, harus https://situskamu.com/about dan https://situskamu.com/images/cover.jpg.

Format tanggal tidak sesuai ISO 8601. Field datePublished dan dateModified harus menggunakan format seperti 2024-06-15 atau 2024-06-15T08:00:00+07:00. Format seperti 15 Juni 2024 tidak akan dikenali.

Ada field yang nilainya undefined. Kalau frontmatter di halaman tidak mengisi thumbnail misalnya, dan kamu langsung masukkan ke JSON tanpa pengecekan, hasilnya adalah field dengan nilai undefined yang membuat JSON tidak valid.

Schema dibuat sepenuhnya di client-side. Ini kembali ke inti masalah tadi. Apapun yang baru ada setelah JavaScript berjalan, tidak akan terlihat oleh Google.

Sebaiknya tambahkan validasi sederhana sebelum memasukkan data ke schema:

ts
const jsonld: Record<string, unknown> = {
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
  headline: fm.title,
  description: fm.description,
  author: {
    '@type': 'Person',
    name: fm.author || 'BlogNvm'
  },
  datePublished: fm.date
}

if (fm.thumbnail) {
  jsonld.image = `https://blognvm.web.id${fm.thumbnail}`
}

Cara Memverifikasi Hasilnya ​

Setelah mengimplementasikan transformHead, lakukan build terlebih dahulu dengan npm run build. Kemudian:

  1. Buka file HTML hasil build di folder .vitepress/dist
  2. Cari tag <script type="application/ld+json"> secara manual
  3. Pastikan nilainya sudah ada dan benar

Kalau structured data sudah ada di file HTML statis tersebut, maka Google pun akan bisa membacanya. Kamu bisa verifikasi lebih lanjut menggunakan Rich Results Test dengan memasukkan URL setelah halaman sudah live, atau paste langsung source HTML-nya.

Kesimpulan ​

Masalah JSON-LD tidak terdeteksi di Google Rich Results hampir selalu berkaitan dengan cara structured data tersebut dimasukkan ke halaman. Komponen Vue tidak cocok untuk keperluan ini karena hasilnya bergantung pada hydration, bukan SSR.

Gunakan transformHead di konfigurasi VitePress. Data schema akan masuk langsung ke HTML dari awal, terlepas dari kondisi JavaScript di browser pengunjung maupun crawler Google.

Satu hal yang perlu diingat: Rich Results Test dan indexing Google butuh waktu untuk memperbarui hasilnya setelah kamu deploy ulang. Kalau sudah yakin implementasinya benar tapi belum muncul di Search Console, tunggu beberapa hari sebelum menyimpulkan ada masalah.

Komentar

Login dengan GitHub untuk berkomentar