ข้ามไปเนื้อหาหลัก

Category: tool

Pagefind — Full-text Search สำหรับ Static Site

Pagefind คือ library สำหรับเพิ่มระบบค้นหาให้กับ static site โดยไม่ต้องมี server หรือ external API ทำงานได้หลัง build เลย

· อ่านประมาณ 2 นาที

สารบัญ

Pagefind คืออะไร

Pagefind สร้าง search index จากไฟล์ HTML ที่ build แล้ว แล้วให้ผู้ใช้ค้นหาฝั่ง client โดยไม่ส่ง request ไปที่ server เลย — เหมาะมากสำหรับ static site บน Netlify, Vercel หรือ GitHub Pages

ทำไมถึงดีกว่าทางเลือกอื่น

วิธีข้อเสีย
Algoliaต้องจ่ายเงิน, ส่งข้อมูลออกนอก
Lunr.jsindex ใหญ่ โหลดทั้งก้อน
ค้นหาด้วย AIexpensive, overkill
Pagefindฟรี, index แบ่งชิ้น, ไม่มี server

วิธีติดตั้งใน Astro

1. ติดตั้ง package

npm install --save-dev @pagefind/default-ui pagefind

2. เพิ่ม script ใน package.json

{
  "scripts": {
    "build": "astro build && pagefind --site dist"
  }
}

3. เพิ่ม UI ในหน้าเว็บ

---
// src/pages/search.astro
---
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
<div id="search"></div>
<script>
  import { PagefindUI } from '@pagefind/default-ui';
  new PagefindUI({ element: '#search' });
</script>

4. ระบุส่วนที่ต้องการ index (optional)

<!-- ใส่ attribute นี้ใน layout เพื่อ index เฉพาะ content หลัก -->
<main data-pagefind-body>
  <slot />
</main>

ประสิทธิภาพ

  • Index แบ่งเป็นชิ้นเล็กๆ โหลดเฉพาะส่วนที่ต้องการ
  • เว็บขนาด 10,000 หน้า ยังค้นหาได้ภายใน ~50ms
  • ไม่มี JavaScript ที่ต้องโหลดล่วงหน้า

ข้อจำกัด

  • ต้อง build ก่อนจึงจะค้นหาได้ — ใช้ใน dev mode ไม่ได้
  • ค้นหาได้เฉพาะข้อความ ไม่รองรับ fuzzy search แบบ full

กรองเนื้อหาที่ไม่ต้องการ index

เพิ่ม data-pagefind-ignore บน element ที่ไม่ควรปรากฏในผลการค้นหา

<!-- ซ่อน navigation, breadcrumb, share button ออกจาก index -->
<nav data-pagefind-ignore>...</nav>
<div class="share-row" data-pagefind-ignore>...</div>
<section class="related-section" data-pagefind-ignore>...</section>

ทำให้ผลการค้นหาแสดงเฉพาะเนื้อหาหลักของบทความ ไม่ปนกับ UI elements

Custom CSS สำหรับ Dark Mode

Pagefind UI ใช้ CSS custom properties ที่ override ได้ง่าย:

#search {
  --pagefind-ui-scale: 0.95;
  --pagefind-ui-primary: #2563eb;
  --pagefind-ui-text: #0f172a;
  --pagefind-ui-background: transparent;
  --pagefind-ui-border: rgba(15, 23, 42, 0.16);
  --pagefind-ui-tag: rgba(15, 23, 42, 0.06);
  --pagefind-ui-border-width: 1px;
  --pagefind-ui-border-radius: 10px;
  --pagefind-ui-font: 'Inter', system-ui, sans-serif;
}

[data-theme='dark'] #search {
  --pagefind-ui-primary: #60a5fa;
  --pagefind-ui-text: #e2e8f0;
  --pagefind-ui-background: transparent;
  --pagefind-ui-border: rgba(255, 255, 255, 0.12);
  --pagefind-ui-tag: rgba(255, 255, 255, 0.08);
}

การใช้กับ Astro View Transitions

เมื่อใช้ ClientRouter ของ Astro ต้อง init Pagefind UI ใหม่หลังทุก navigation:

function initPagefind() {
  const el = document.getElementById('search');
  // ตรวจ flag เพื่อกัน init ซ้ำในหน้าเดิม
  if (!el || el.dataset.pfInit || typeof PagefindUI === 'undefined') return;
  el.dataset.pfInit = '1';
  new PagefindUI({ element: '#search', showImages: false });
}

// ทำงานตอนโหลดหน้าแรก
document.addEventListener('DOMContentLoaded', initPagefind);
// ทำงานหลัง View Transition ทุกครั้ง
document.addEventListener('astro:page-load', initPagefind);

หากใช้ defer บน script CDN ให้ใช้ astro:page-load แทน DOMContentLoaded เพราะ DOMContentLoaded อาจ fire ก่อน script โหลดเสร็จ

CDN vs npm package

วิธีข้อดีข้อเสีย
CDN pagefind-ui.jsไม่ต้อง bundleโหลดจาก CDN ภายนอก
@pagefind/default-uiอยู่ใน bundleต้อง import และ config bundler

สำหรับ Astro ที่เป็น static site เต็มรูปแบบ วิธี CDN + defer ง่ายกว่าและทำงานได้เหมือนกัน

Tips

  • ใช้ pagefind --site dist ใน npm script หลัง astro build เสมอ
  • ถ้า index ว่างเปล่าให้ตรวจว่า data-pagefind-body ครอบ content จริง
  • ทดสอบ search ได้ด้วย npx serve dist แล้วเปิด localhost หลัง build