Astro + Pagefind 站內搜尋完整指南:安裝、索引、UI、SEO 與效能優化

一步步在 Astro 網站導入 Pagefind 全文搜尋:安裝設定、索引調整、前端 UI、SEO 影響、效能最佳化與常見坑排查。

Astro 與 Pagefind 的站內搜尋架構與索引流程圖
Astro 與 Pagefind 的站內搜尋架構與索引流程圖

站內搜尋是內容型網站的核心能力。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>

發布前檢查清單

Checklist

避免踩坑,確保體驗良好

  • astro-pagefind 已安裝並於 astro.config.mjs 啟用
  • ✅ 文章頁語意化標題(h2/h3)明確
  • ✅ 不應被索引的區塊加上 .no-search
  • ✅ 首次互動時才動態載入 UI(或只在搜尋頁載入)
  • npm run build && npm run preview 可看到 /pagefind/ 與 UI 正常

延伸閱讀

結論:Pagefind 能以最低維護成本為 Astro 帶來高品質站內搜尋。先以預設落地,再逐步優化權重、UI 與載入策略,能在效能與體驗間取得最佳平衡。

作者:Drifter

·

更新:2025年8月13日 上午12:00

· 回報錯誤
下拉重新整理