Astro 博客接入 Algolia DocSearch JS 实战
最近在优化博客的阅读体验时,我希望像主流技术文档网站一样,在顶部导航栏里加入一个搜索框,支持快捷键唤起、弹窗搜索和结果跳转。最终选择的是 Algolia 官方提供的 DocSearch JS。
这篇文章记录一下完整接入过程,项目技术栈是:
- Astro
- Vue 组件
- pnpm
- Algolia DocSearch JS v4
为什么选择 DocSearch
对技术博客来说,搜索体验非常影响阅读效率。相比自己手写一个搜索弹窗,DocSearch 已经提供了比较完整的能力:
- 默认生成可访问的搜索按钮和弹窗
- 支持
Ctrl / Command + K快捷键 - 支持搜索结果高亮
- 支持键盘导航
- 和 Algolia 索引直接对接
官方接入方式也比较简单,核心就是准备一个容器,然后调用 docsearch() 初始化。
准备 Algolia 配置信息
接入前需要先准备三项信息:
appId:Algolia Application IDapiKey:Search API KeyindexName:DocSearch 使用的索引名称
本项目使用的信息如下:
const appId = 'PEKHQFSYYO';
const apiKey = 'ffa9cd55f1c2d8f18c5c7742ba487764';
const indexName = 'momoc_robot';
需要注意的是,浏览器端只能放 Search API Key,不要把 Admin API Key 写到前端代码里。
安装依赖
项目里先安装 DocSearch JS:
pnpm add @docsearch/js@4
DocSearch 的官方示例中还会引入样式:
import '@docsearch/css';
所以也需要安装对应的 CSS 包:
pnpm add @docsearch/css@4
安装完成后,package.json 中会出现:
{
"dependencies": {
"@docsearch/css": "^4.6.3",
"@docsearch/js": "^4.6.3"
}
}
封装搜索组件
在 src/components 下新增 DocSearchBox.vue,用于初始化 DocSearch。
核心代码如下:
<script setup lang="ts">
import docsearch from '@docsearch/js';
import '@docsearch/css';
import { onBeforeUnmount, onMounted, ref } from 'vue';
const searchContainer = ref<HTMLElement | null>(null);
let searchInstance: ReturnType<typeof docsearch> | undefined;
onMounted(() => {
if (!searchContainer.value) return;
searchInstance = docsearch({
container: searchContainer.value,
appId: 'PEKHQFSYYO',
indexName: 'momoc_robot',
apiKey: 'ffa9cd55f1c2d8f18c5c7742ba487764',
});
});
onBeforeUnmount(() => {
searchInstance?.destroy();
});
</script>
<template>
<div ref="searchContainer" class="docsearch-root" />
</template>
这里有几个细节:
container使用真实 DOM 元素,而不是手动写一个 input。onMounted后再初始化,避免服务端渲染阶段访问浏览器 DOM。onBeforeUnmount中调用destroy(),避免组件卸载后留下事件监听。
适配博客现有样式
DocSearch 自带默认样式,但直接使用会和博客当前风格有一点割裂,所以可以通过覆盖 CSS 变量和按钮样式来适配。
例如:
.docsearch-root :global(.DocSearch-Button) {
width: 100%;
height: 36px;
margin: 0;
padding: 0 10px 0 12px;
border: 1px solid var(--c-hairline);
border-radius: 8px;
background: var(--c-surface-soft);
color: var(--c-muted);
box-shadow: none;
}
:global(.DocSearch) {
--docsearch-primary-color: var(--c-primary);
--docsearch-highlight-color: var(--c-primary);
--docsearch-text-color: var(--c-ink);
--docsearch-muted-color: var(--c-muted);
--docsearch-modal-background: var(--c-canvas);
}
如果站点支持暗色模式,也可以继续覆盖暗色主题下的变量:
:global([data-theme="dark"] .DocSearch) {
--docsearch-container-background: rgba(0, 0, 0, 0.58);
--docsearch-modal-background: var(--c-surface-dark-elevated);
--docsearch-footer-background: var(--c-surface-dark-soft);
--docsearch-hit-background: var(--c-surface-dark-soft);
}
这样既保留 DocSearch 的完整交互,又能让视觉风格和站点保持统一。
接入顶部导航栏
本项目顶部导航是 Vue 组件 NavBar.vue,因此只需要引入刚刚封装好的搜索组件:
<script setup lang="ts">
import DocSearchBox from './DocSearchBox.vue';
</script>
然后把它放到 logo 旁边:
<div class="brand-search">
<a href="/" class="logo" aria-label="Momoc's Blog — 首页">
<span class="logo-text">Momoc's Blog</span>
</a>
<DocSearchBox />
</div>
再补充一段布局样式:
.brand-search {
display: flex;
align-items: center;
gap: 18px;
min-width: 0;
}
移动端空间比较紧张,可以隐藏搜索按钮里的占位文字和快捷键,只保留图标按钮。
增加 Algolia 预连接
为了让首次打开搜索弹窗时请求更快,可以在全局布局 Layout.astro 的 <head> 中添加 Algolia 的 preconnect:
<link rel="preconnect" href="https://PEKHQFSYYO-dsn.algolia.net" crossorigin>
这一步不是必须的,但属于比较低成本的体验优化。
验证配置是否可用
前端能打开搜索弹窗,不代表索引一定配置正确。最直接的方式是用 Algolia 查询接口验证 indexName。
例如:
curl -X POST \
'https://PEKHQFSYYO-dsn.algolia.net/1/indexes/momoc_robot/query' \
-H 'X-Algolia-Application-Id: PEKHQFSYYO' \
-H 'X-Algolia-API-Key: ffa9cd55f1c2d8f18c5c7742ba487764' \
-H 'Content-Type: application/json' \
--data '{"query":"javascript","hitsPerPage":1}'
如果返回 200,并且能看到 nbHits,说明索引名和 Search API Key 是可用的。
本项目验证结果中,momoc_robot 返回了搜索结果,说明配置正确。
本地构建验证
最后执行构建:
pnpm build
构建通过后,再本地预览:
pnpm preview
打开页面后检查:
- 顶部导航栏是否出现搜索按钮
- 点击按钮是否能打开 DocSearch 弹窗
- 输入关键词后是否有搜索结果
Ctrl / Command + K是否能唤起搜索- 暗色模式下弹窗颜色是否正常
- 移动端下按钮是否不会挤压导航
常见问题
搜索弹窗能打开,但没有结果
优先检查 indexName。appId 和 apiKey 正确时,如果索引名写错,查询通常会返回 404。
前端代码里能不能放 apiKey
可以放 Search API Key,因为它本来就是用于浏览器查询的公开 key。但不要放 Admin API Key。
构建时出现 chunk size warning
DocSearch 自身包含弹窗、搜索、快捷键和 Algolia 客户端逻辑,体积不算特别小。Vite 可能会提示部分 chunk 超过 500 kB,这不是构建错误。
如果后续很在意首屏体积,可以考虑把搜索组件改成按需加载,在用户点击搜索按钮时再动态加载 DocSearch。
小结
这次接入的改动主要集中在三个地方:
- 新增
DocSearchBox.vue封装官方docsearch()初始化逻辑。 - 在
NavBar.vue中把搜索框放到 logo 旁边。 - 在
Layout.astro中增加 Algolia preconnect。
整体改动不算大,但体验提升很明显。对于自定义 Astro 博客来说,DocSearch 是一个很适合用来补齐站内搜索体验的方案。