站內搜尋是內容型網站的核心能力。Pagefind 以「建置期索引、客戶端查詢」為設計,零伺服器依賴、效能佳、部署簡單,特別適合 Astro 這類靜態站。本文提供一套可落地的實作路徑與最佳化心法。
為什麼選 Pagefind?
Pagefind 的關鍵優勢
- 適合 SSG/靜態站:索引在建置時產生,查詢在前端執行
- 即裝即用:Astro 有現成整合(astro-pagefind)
- 高效能:分片索引 + 漸進式載入,首屏負擔小
- 可控可擴充:支援欄位權重、語言斷詞、UI 客製
一、安裝與基本設定
假設你已使用 Astro v5,並採用 npm。以下以最小可行設定為例。
# 安裝套件
npm i -D astro-pagefind
在 astro.config.mjs
啟用整合:
import { defineConfig } from 'astro/config';
import pagefind from 'astro-pagefind';
export default defineConfig({
integrations: [
pagefind({
// 基本建議:繁體中文網站可先不啟用中文斷詞,觀察結果再調整
// outputPath: 'pagefind', // 預設即可
// excludeSelectors: ['.no-search'],
})
]
});
建置後會在 dist/
生成 pagefind/
索引資料夾,前端即可載入使用。
二、將搜尋 UI 嵌入頁面
最簡便作法:在導覽或搜尋頁嵌入搜尋欄位與結果容器。
<!-- 建議放在全站 Layout 或 Header 中 -->
<input id="search" type="search" placeholder="搜尋關鍵字…" />
<div id="results"></div>
載入 Pagefind 前端腳本並綁定事件:
<script type="module">
import PagefindUI from "/pagefind/pagefind-ui.js";
const ui = new PagefindUI({
element: "#results",
showSubResults: true,
translations: {
placeholder: "搜尋文章…",
zero_results: "沒有找到相關內容",
clear_search: "清除搜尋"
}
});
const input = document.querySelector('#search');
input?.addEventListener('input', (e) => {
const q = e.target?.value ?? '';
ui.triggerSearch(q);
});
</script>
注意:
/pagefind/pagefind-ui.js
與索引檔案會在建置後生成,因此在開發模式下請確保使用 astro dev
時有對應的資源路徑。 三、內容欄位與權重:如何讓好內容排更前?
Pagefind 支援將 HTML 中特定選擇器內容加入索引、設定權重。對內容站來說,建議:
- title(h1)權重最高
- 描述(摘要)與小標(h2/h3)中等
- 內文段落正常權重
在 astro-pagefind 中可用 CSS 選擇器微調(依官方文件版本而定):
pagefind({
normalizeUrl: (url) => url.replace(/index\.html$/, ''),
// excludeSelectors: ['.no-search'],
// 若需進階:自訂抽取欄位與加權,請參考 Pagefind 原始文件
})
四、與 Astro 的最佳實務
- 僅索引公開內容:將「不想被搜到」的區塊加上
.no-search
並於設定排除 - 盡量使用語意化標題層級(h2/h3),搜尋摘要會更精準
- 文章前言的
description
要精煉,提升點擊率 - 站內連結清晰,利於使用者瀏覽結果後的回訪
五、SEO 與 Pagefind:會影響 Google 嗎?
SEO 觀點
- Pagefind 僅影響「站內搜尋」體驗,對外部搜尋引擎(Google/Bing)沒有負面影響
- 請確保 sitemap 與 RSS 正常,外部搜尋依舊靠結構化資料與內文品質
- 搜尋結果頁請避免被索引(noindex),避免重複內容產生
六、效能優化策略
索引是分片載入的,但仍應注意初次互動成本。
- 延遲載入 Pagefind UI:在使用者聚焦到 input 或打字時才動態 import
- 只在需要的頁面載入 UI 腳本(例如獨立 /search 頁)
- 減少不必要的選擇器與大量 DOM 文字
- 建置時確保壓縮與資源分割(Astro/Vite 預設已佳)
動態載入範例:
<script type="module">
let ui;
const input = document.querySelector('#search');
async function ensureUI() {
if (!ui) {
const { default: PagefindUI } = await import('/pagefind/pagefind-ui.js');
ui = new PagefindUI({ element: '#results' });
}
}
input?.addEventListener('focus', ensureUI);
input?.addEventListener('input', async (e) => {
await ensureUI();
ui.triggerSearch(e.target?.value ?? '');
});
</script>
七、常見錯誤與排查
- 本地 dev 看不到
/pagefind/
:需執行一次npm run build && npm run preview
驗證路徑 - 部署後 404:確認
dist/pagefind/
有隨站點上傳,或 CDN 規則未擋住 - 結果不精準:調整標題/摘要權重,確保 HTML 結構語意正確
- 大量英文混中:可評估啟用對應語言斷詞或避免特殊字元破壞分詞
八、進階:自訂結果卡片與高亮
UI 客製化方向
- 自訂結果樣板:標題、摘要、路徑、發佈時間、標籤
- 關鍵字高亮:將命中詞用
<mark>
標記 - 導向行為:新分頁開啟或站內導航保持快取
簡單結果渲染示意:
<script type="module">
import PagefindUI from "/pagefind/pagefind-ui.js";
const ui = new PagefindUI({ element: "#results", showImages: false });
ui.on('results', (res) => {
const container = document.querySelector('#results');
container.innerHTML = res.results.map(r => `
<article class="py-3 border-b border-gray-200 dark:border-gray-800">
<a href="${r.url}" class="text-lg font-semibold hover:underline">${r.title}</a>
<p class="text-sm text-gray-600 dark:text-gray-300">${r.excerpt}</p>
</article>
`).join('');
});
</script>
發布前檢查清單
延伸閱讀
結論:Pagefind 能以最低維護成本為 Astro 帶來高品質站內搜尋。先以預設落地,再逐步優化權重、UI 與載入策略,能在效能與體驗間取得最佳平衡。