From e7aed90ac7a0c2f04c8be6cef8b80c1569021a5a Mon Sep 17 00:00:00 2001 From: Luca Del Puppo Date: Wed, 19 Aug 2026 18:41:00 +0000 Subject: [PATCH 1/2] fix(search): load Pagefind from same-origin base path --- README.md | 6 ++-- package.json | 3 +- scripts/check-search-build.mjs | 51 ++++++++++++++++++++++++++++++++++ src/components/Search.astro | 7 +++-- 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 scripts/check-search-build.mjs diff --git a/README.md b/README.md index 93572248..b40a6b7b 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,13 @@ requests-per-second velocity gauge in the hero. | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `npm install` | Install dependencies | | `npm run dev` | Start the dev server at `localhost:4321` | -| `npm run build` | Build to `build/` and generate the Pagefind search index | +| `npm run build:website` | Build to `build/`, generate the Pagefind search index, and verify the search assets | | `npm run preview` | Preview the production build locally | | `npm run lint` | Lint with [Biome](https://biomejs.dev) | | `npm run format` | Format with Biome (`format` to verify) | | `npm run check` | Type-check via [`astro check`](https://docs.astro.build/en/reference/cli-reference/#astro-check) (run by CI on every PR) | -> Search only works against a production build (`npm run build`), because the +> Search only works against a production build (`npm run build:website`), because the > Pagefind index is generated from the built HTML. In `dev` the search modal > shows a graceful fallback message. > @@ -70,7 +70,7 @@ Docusaurus site: The documentation is **not** stored in this repository — it lives in the [`fastify/fastify`](https://github.com/fastify/fastify) repo and is fetched at build time by [`scripts/fetch-docs.mjs`](scripts/fetch-docs.mjs), which runs -automatically via the `prebuild`/`predev` npm hooks. +as part of `npm run build:website`. The script: diff --git a/package.json b/package.json index 16990835..3849f05b 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,13 @@ "scripts": { "dev": "astro dev", "start": "astro dev", - "build:website": "npm run build:data && astro build", + "build:website": "npm run build:data && astro build && npm run check:search", "preview": "astro preview", "astro": "astro", "lint": "biome check", "lint:fix": "biome check --write", "check": "astro check", + "check:search": "node scripts/check-search-build.mjs", "build:data": "node scripts/postinstall.mjs", "generate:og-assets": "node scripts/generate-og-assets.mjs" }, diff --git a/scripts/check-search-build.mjs b/scripts/check-search-build.mjs new file mode 100644 index 00000000..ab516487 --- /dev/null +++ b/scripts/check-search-build.mjs @@ -0,0 +1,51 @@ +import assert from "node:assert/strict"; +import { readdir, readFile, stat } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const BUILD_DIR = path.join(ROOT, "build"); +const PAGEFIND_DIR = path.join(BUILD_DIR, "pagefind"); + +async function assertFile(file) { + assert( + (await stat(file)).isFile(), + `${path.relative(ROOT, file)} is missing`, + ); +} + +await assertFile(path.join(PAGEFIND_DIR, "pagefind.js")); + +const entryFile = path.join(PAGEFIND_DIR, "pagefind-entry.json"); +await assertFile(entryFile); + +const entry = JSON.parse(await readFile(entryFile, "utf8")); +const pageCount = Object.values(entry.languages ?? {}).reduce( + (total, language) => total + (language.page_count ?? 0), + 0, +); +assert(pageCount > 0, "Pagefind index contains no pages"); + +const assetsDir = path.join(BUILD_DIR, "_astro"); +const assetFiles = await readdir(assetsDir); +const bundles = await Promise.all( + assetFiles + .filter((file) => file.endsWith(".js")) + .map(async (file) => ({ + file, + content: await readFile(path.join(assetsDir, file), "utf8"), + })), +); +const searchBundles = bundles.filter(({ content }) => + content.includes("pagefind/pagefind.js"), +); + +assert(searchBundles.length > 0, "Built search bundle was not found"); +assert( + searchBundles.every( + ({ content }) => !content.includes("//pagefind/pagefind.js"), + ), + "Built search bundle contains a protocol-relative Pagefind URL", +); + +console.log(`Verified documentation search index (${pageCount} pages)`); diff --git a/src/components/Search.astro b/src/components/Search.astro index 4bdb6a0e..97d5c73d 100644 --- a/src/components/Search.astro +++ b/src/components/Search.astro @@ -71,14 +71,17 @@ import { withBase } from "~/lib/href"; let pagefind: any = null; let loadFailed = false; + const pagefindUrl = withBase('/pagefind/pagefind.js'); async function ensurePagefind() { if (pagefind || loadFailed) return pagefind; try { - pagefind = await import(/* @vite-ignore */ `${import.meta.env.BASE_URL}/pagefind/pagefind.js`); + pagefind = await import(/* @vite-ignore */ pagefindUrl); await pagefind.init?.(); - } catch (e) { + } catch (error) { + pagefind = null; loadFailed = true; + console.error(`Failed to load Pagefind from ${pagefindUrl}`, error); hint?.classList.add('hidden'); fallback?.classList.remove('hidden'); } From cfb1d0c2b2899dc4d7f1f31cd24767cd6d477321 Mon Sep 17 00:00:00 2001 From: Luca Del Puppo Date: Wed, 19 Aug 2026 18:46:33 +0000 Subject: [PATCH 2/2] chore(search): remove build smoke check --- README.md | 2 +- package.json | 3 +- scripts/check-search-build.mjs | 51 ---------------------------------- 3 files changed, 2 insertions(+), 54 deletions(-) delete mode 100644 scripts/check-search-build.mjs diff --git a/README.md b/README.md index b40a6b7b..67c58e63 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ requests-per-second velocity gauge in the hero. | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `npm install` | Install dependencies | | `npm run dev` | Start the dev server at `localhost:4321` | -| `npm run build:website` | Build to `build/`, generate the Pagefind search index, and verify the search assets | +| `npm run build:website` | Build to `build/` and generate the Pagefind search index | | `npm run preview` | Preview the production build locally | | `npm run lint` | Lint with [Biome](https://biomejs.dev) | | `npm run format` | Format with Biome (`format` to verify) | diff --git a/package.json b/package.json index 3849f05b..16990835 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,12 @@ "scripts": { "dev": "astro dev", "start": "astro dev", - "build:website": "npm run build:data && astro build && npm run check:search", + "build:website": "npm run build:data && astro build", "preview": "astro preview", "astro": "astro", "lint": "biome check", "lint:fix": "biome check --write", "check": "astro check", - "check:search": "node scripts/check-search-build.mjs", "build:data": "node scripts/postinstall.mjs", "generate:og-assets": "node scripts/generate-og-assets.mjs" }, diff --git a/scripts/check-search-build.mjs b/scripts/check-search-build.mjs deleted file mode 100644 index ab516487..00000000 --- a/scripts/check-search-build.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import assert from "node:assert/strict"; -import { readdir, readFile, stat } from "node:fs/promises"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -const BUILD_DIR = path.join(ROOT, "build"); -const PAGEFIND_DIR = path.join(BUILD_DIR, "pagefind"); - -async function assertFile(file) { - assert( - (await stat(file)).isFile(), - `${path.relative(ROOT, file)} is missing`, - ); -} - -await assertFile(path.join(PAGEFIND_DIR, "pagefind.js")); - -const entryFile = path.join(PAGEFIND_DIR, "pagefind-entry.json"); -await assertFile(entryFile); - -const entry = JSON.parse(await readFile(entryFile, "utf8")); -const pageCount = Object.values(entry.languages ?? {}).reduce( - (total, language) => total + (language.page_count ?? 0), - 0, -); -assert(pageCount > 0, "Pagefind index contains no pages"); - -const assetsDir = path.join(BUILD_DIR, "_astro"); -const assetFiles = await readdir(assetsDir); -const bundles = await Promise.all( - assetFiles - .filter((file) => file.endsWith(".js")) - .map(async (file) => ({ - file, - content: await readFile(path.join(assetsDir, file), "utf8"), - })), -); -const searchBundles = bundles.filter(({ content }) => - content.includes("pagefind/pagefind.js"), -); - -assert(searchBundles.length > 0, "Built search bundle was not found"); -assert( - searchBundles.every( - ({ content }) => !content.includes("//pagefind/pagefind.js"), - ), - "Built search bundle contains a protocol-relative Pagefind URL", -); - -console.log(`Verified documentation search index (${pageCount} pages)`);