astro-pagefind のコードリーディング

astro-pagefind

特徴
Build pagefind index upon static build
Serve previously prebuilt search index in astro dev mode
Search Astro component
Supports customized base URL path
Supports multiple instances of the component on a page
Supports pre-filled search query
Supports Astro view transitions
今回はこの中から、以下の3点を実現する部分を読んでいく。
- 静的ビルド時にインデックスを作成する
- dev mode で事前にインデックスを作成する
- Astroコンポーネントの提供
Pagefind 自体も一切読んでおらず、コンポーネントが core のラッパーなのか、それとも別途作っているものなのかわからないので、3から読もうと思う。

エントリポイントを見るために実際に使ってみる
Pagefind 自体は知っているが、実際に使ったことはないため、実際に使ってみる。
READMEを見る限り、Astro Integration として追加できる形式ではなさそうなので、Manual Install する。
pnpm add astro-pagefind
//astro.config.ts
import { defineConfig } from "astro/config";
import pagefind from "astro-pagefind";
export default defineConfig({
build: {
format: "file",
},
integrations: [pagefind()],
});
build のオプションは次のとおり。
既存の検索機能の下に追加してみたものの、結果が出てこない。インデックスが作成されていない?

Search コンポーネント
Astro に合わせて愚直に実装されたコンポーネントだった。

ビルド時・開発時のインデックス作成
Astro Integration は AstroIntegration
型のオブジェクトであれば登録することができる。AstroIntegration
型は、name
と hooks
プロパティを持つ。
export interface AstroIntegration {
/** The name of the integration. */
name: string;
/** The different hooks available to extend. */
hooks: {
'astro:config:setup'?: (options: {
config: AstroConfig;
command: 'dev' | 'build' | 'preview';
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
/**
* @deprecated Use `addDevToolbarApp` instead.
* TODO: Fully remove in Astro 5.0
*/
addDevOverlayPlugin: (entrypoint: string) => void;
addDevToolbarApp: (entrypoint: DevToolbarAppEntry | string) => void;
addMiddleware: (mid: AstroIntegrationMiddleware) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:config:done'?: (options: {
config: AstroConfig;
setAdapter: (adapter: AstroAdapter) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:server:setup'?: (options: {
server: vite.ViteDevServer;
logger: AstroIntegrationLogger;
toolbar: ReturnType<typeof getToolbarServerCommunicationHelpers>;
}) => void | Promise<void>;
'astro:server:start'?: (options: {
address: AddressInfo;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:server:done'?: (options: {
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:ssr'?: (options: {
manifest: SerializedSSRManifest;
/**
* This maps a {@link RouteData} to an {@link URL}, this URL represents
* the physical file you should import.
*/
entryPoints: Map<RouteData, URL>;
/**
* File path of the emitted middleware
*/
middlewareEntryPoint: URL | undefined;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:start'?: (options: {
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:setup'?: (options: {
vite: vite.InlineConfig;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
updateConfig: (newConfig: vite.InlineConfig) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:generated'?: (options: {
dir: URL;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:done'?: (options: {
pages: {
pathname: string;
}[];
dir: URL;
routes: RouteData[];
logger: AstroIntegrationLogger;
cacheManifest: boolean;
}) => void | Promise<void>;
};
}

astro-pagefind でも AstroIntegration
を満たすように実装されている。

扱っている hooks は 次の 3 種類
hooks | 概要 |
---|---|
astro:config:setup |
Vite、Astro config の初期化前の段階 |
astro:server:setup |
Viteが dev mode で立ち上がった段階 |
astro:build:done |
production build が完了したタイミング |
astro:config:setup
ではindexの出力先ディレクトリを指定し、astro:server:setup
では sirv を用いてビルド結果を配信。astro:build:done
でnpx pagefind --site
によりindexを生成、といった感じ。

一回ビルドしないと検索結果でなさそう。

ビルド完了時に行なっている処理を、ビルド後に pnpm dlx で実行したら検索結果が出るようになった。
pnpm dlx pagefind --site "./dist"

dev mode における挙動
今の所 dist にデータが出力されていないと検索ができないと思っているいるが、sirv の挙動を勘違いしている可能性もあるか?
→インデックスがない場合、動的に作るようなことはしない。
もう少し sirv について調べる。
-
sirv(dir: string, opts?: { ... })
のインターフェース -
dev
オプションを true にすると、キャッシュをスキップして、すべてのリクエストごとにファイルシステムを走査する。
結局 outDir
(デフォルトでは./dist
)をみにいく構造上、一回インデックス作っていないとダメだな