Category: tool
Pagefind — Full-text Search สำหรับ Static Site
Pagefind คือ library สำหรับเพิ่มระบบค้นหาให้กับ static site โดยไม่ต้องมี server หรือ external API ทำงานได้หลัง build เลย
สารบัญ
Pagefind คืออะไร
Pagefind สร้าง search index จากไฟล์ HTML ที่ build แล้ว แล้วให้ผู้ใช้ค้นหาฝั่ง client โดยไม่ส่ง request ไปที่ server เลย — เหมาะมากสำหรับ static site บน Netlify, Vercel หรือ GitHub Pages
ทำไมถึงดีกว่าทางเลือกอื่น
| วิธี | ข้อเสีย |
|---|---|
| Algolia | ต้องจ่ายเงิน, ส่งข้อมูลออกนอก |
| Lunr.js | index ใหญ่ โหลดทั้งก้อน |
| ค้นหาด้วย AI | expensive, 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