Menambahkan Pencarian Statis dengan Pagefind di Website Statis

Pengertian

Pagefind adalah pustaka pencarian untuk website statis. Alih-alih menjalankan server pencarian (Elasticsearch, Meilisearch) atau menyewa layanan pihak ketiga, Pagefind membaca HTML hasil build lalu membuat indeks terkompresi yang diunduh dan dijalankan langsung di browser memakai WebAssembly.

Hasilnya: pencarian penuh dengan pemotongan kata (stemming), peringkat relevansi, dan cuplikan hasil — tanpa backend, tanpa API, dan tetap cepat karena indeks dibagi per bagian (chunk) sehingga browser hanya mengunduh apa yang diperlukan.

Cara kerjanya:

  1. Build HTML situs (mis. folder public/).
  2. Jalankan pagefind --site public untuk memindai seluruh HTML dan menulis indeks ke public/pagefind/.
  3. Halaman memuat pagefind-ui.js dan menampilkan kotak pencarian.

Kelebihan

  • Tanpa server: indeks statis, cocok untuk Vercel, Netlify, GitHub Pages.
  • Ringan bagi browser: indeks dipecah dan diunduh sesuai kebutuhan.
  • Mendukung banyak bahasa: stemming per bahasa, termasuk id dan en.
  • Customizable: penanda data-pagefind-* untuk mengatur apa yang diindeks.
  • Tema UI siap pakai: komponen siap pasang plus API untuk hasil kustom.
  • Tanpa layanan berbayar: sepenuhnya open source dan offline.

Kekurangan

  • Indeks dibangun saat build: perubahan konten perlu build ulang.
  • Bukan pencarian semantik: berbasis kata, bukan makna.
  • Ukuran indeks tumbuh seiring jumlah artikel.
  • Butuh HTML statis: konten yang hanya muncul via JavaScript tidak terindeks.
  • Tidak ada analitik bawaan: pencarian populer tidak terukur otomatis.
Catatan penting: Pagefind membaca HTML mentah, bukan DOM setelah JavaScript berjalan. Pastikan isi artikel sudah ada di HTML statis hasil pre-render, bukan di-inject lewat fetch saat halaman dibuka.

Instalasi

Pasang sebagai devDependency:

bash
npm install -D pagefind

Tambahkan ke package.json setelah langkah build HTML:

json
{
  "scripts": {
    "build": "node scripts/build-articles.js",
    "search": "pagefind --site public"
  }
}

Untuk produksi yang menyiapkan folder keluaran lalu mengindeksnya:

bash
node scripts/build-articles.js && node scripts/prep-output.js && pagefind --site public

Menandai Konten yang Diindeks

Secara bawaan Pagefind mengindeks seluruh <body>. Gunakan atribut berikut untuk mengatur cakupan:

html
<body>
  <header data-pagefind-ignore>...</header>

  <main data-pagefind-body>
    <h1 data-pagefind-meta="title">Judul Artikel</h1>
    <p>Isi yang diindeks...</p>
  </main>

  <footer data-pagefind-ignore>...</footer>
</body>

Penjelasan:

  • data-pagefind-body — batasi indeks hanya pada elemen ini.
  • data-pagefind-ignore — lewati elemen (mis. navbar, footer, popup).
  • data-pagefind-meta="judul" — simpan metadata kustom untuk ditampilkan di hasil.
  • data-pagefind-filter="kategori" — membuat filter (mis. per kategori artikel).

Memasang UI Pencarian

Muat aset CSS dan JS hasil build, lalu inisialisasi komponen:

html
<link rel="stylesheet" href="/pagefind/pagefind-ui.css" />
<script src="/pagefind/pagefind-ui.js"></script>

<div id="search"></div>

<script>
  window.addEventListener('DOMContentLoaded', () => {
    new PagefindUI({
      element: '#search',
      showSubResults: false,
      showImages: false,
      translations: {
        placeholder: 'Cari artikel',
        zero_results: 'Tidak ada hasil untuk "[SEARCH_TERM]"',
        one_result: 'Ditemukan [COUNT] hasil untuk "[SEARCH_TERM]"',
        many_results: 'Ditemukan [COUNT] hasil untuk "[SEARCH_TERM]"'
      }
    });
  });
</script>

Contoh memuat aset secara dinamis agar tidak memperlambat halaman (pola yang dipakai situs ini):

javascript
function ensurePagefindAssets() {
  if (!document.getElementById('pf-ui-css')) {
    const l = document.createElement('link');
    l.id = 'pf-ui-css';
    l.rel = 'stylesheet';
    l.href = '/pagefind/pagefind-ui.css';
    document.head.appendChild(l);
  }
  if (!document.getElementById('pf-ui-js')) {
    const s = document.createElement('script');
    s.id = 'pf-ui-js';
    s.src = '/pagefind/pagefind-ui.js';
    s.defer = true;
    document.head.appendChild(s);
  }
}

Mengubah Hasil dengan processResult

Hapus bagian judul yang tidak perlu atau tambahkan label:

javascript
new PagefindUI({
  element: '#search',
  processResult: (r) => {
    if (r.meta && typeof r.meta.title === 'string') {
      r.meta.title = r.meta.title.replace(/\s*[-–]\s*masyarakat\.id\s*$/i, '');
    }
    return r;
  }
});

Pencarian via API (Tanpa UI)

Untuk kontrol penuh, pakai API langsung:

javascript
const pagefind = await import('/pagefind/pagefind.js');
await pagefind.options({ excerptLength: 20 });

const search = await pagefind.search('debian');
const hasil = await Promise.all(search.results.slice(0, 5).map((r) => r.data()));
console.log(hasil.map((h) => ({ judul: h.meta.title, url: h.url })));

Opsi CLI yang Sering Dipakai

OpsiFungsi
--site publicFolder keluaran HTML yang dipindai
--output-subdir pagefindNama subfolder indeks
--force-language idPaksa bahasa stemming tertentu
--exclude-selectors "nav,footer"Lewati elemen tanpa menandai HTML
--glob "**/*.html"Batasi berkas yang dipindai

Alur Build yang Benar

bash
npm run build           # pre-render HTML per artikel ke ./<slug>/
node scripts/prep-output.js   # salin aset ke public/
npx pagefind --site public    # buat indeks di public/pagefind/

Urutannya penting: Pagefind harus berjalan setelah semua HTML ada, dan sebelum folder public/ diunggah.

Troubleshooting

  • Hasil selalu kosong: jalankan pagefind --site public dan cek folder public/pagefind/ terbentuk. Pastikan HTML berada di dalam folder --site yang benar.
  • /pagefind/pagefind.js 404 saat dev: indeks belum dibangun di server lokal. Jalankan build terlebih dahulu atau sediakan rute statis untuk public/pagefind/.
  • Sebagian konten tidak muncul: elemen berada di luar data-pagefind-body, atau ditandai data-pagefind-ignore, atau merupakan konten yang dibuat JavaScript.
  • Judul tidak sesuai: atur via data-pagefind-meta="title" atau bersihkan dengan processResult.
  • Stemming salah bahasa: situs multi-bahasa perlu lang yang benar pada <html> atau --force-language.
  • Indeks terlalu besar: batasi cakupan dengan data-pagefind-body, buang blok kode dari indeks dengan data-pagefind-ignore.

Kesimpulan

Pagefind memberi pengalaman pencarian layaknya aplikasi dinamis tanpa biaya server. Kuncinya tiga langkah: tandai konten dengan data-pagefind-body, bangun indeks setelah HTML selesai, dan muat pagefind-ui.js di halaman. Untuk situs artikel seperti ini, Pagefind adalah pilihan paling hemat dan cepat.

Artikel Terkait