From 854c5a1097f77431d8eb81c48b17c063898a4b81 Mon Sep 17 00:00:00 2001 From: gbanyan Date: Thu, 20 Nov 2025 16:46:10 +0800 Subject: [PATCH] Fix search on Vercel by serving Pagefind as static files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous approach using an API route to serve Pagefind files doesn't work on Vercel's serverless environment because fs.readFile can't reliably access files in the deployed output. Solution: Serve Pagefind files directly from public/_pagefind as static assets, which is the standard Next.js approach and works reliably on all deployment platforms. Changes: - Update search modal to load from /_pagefind/ instead of /pagefind/ - Remove app/pagefind/[...path]/route.ts API route (no longer needed) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/pagefind/[...path]/route.ts | 40 --------------------------------- components/search-modal.tsx | 6 ++--- 2 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 app/pagefind/[...path]/route.ts diff --git a/app/pagefind/[...path]/route.ts b/app/pagefind/[...path]/route.ts deleted file mode 100644 index 982e9bc..0000000 --- a/app/pagefind/[...path]/route.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server'; -import { readFile } from 'fs/promises'; -import { join } from 'path'; - -export async function GET( - request: NextRequest, - { params }: { params: Promise<{ path: string[] }> } -) { - try { - const { path } = await params; - const filePath = join(process.cwd(), 'public', '_pagefind', ...path); - - // Read the file - const file = await readFile(filePath); - - // Determine content type - const ext = path[path.length - 1].split('.').pop(); - const contentTypes: Record = { - 'js': 'application/javascript', - 'css': 'text/css', - 'json': 'application/json', - 'wasm': 'application/wasm', - 'pf_meta': 'application/octet-stream', - 'pf_index': 'application/octet-stream', - 'pf_fragment': 'application/octet-stream', - }; - - const contentType = contentTypes[ext || ''] || 'application/octet-stream'; - - return new NextResponse(file, { - headers: { - 'Content-Type': contentType, - 'Cache-Control': 'public, max-age=31536000, immutable', - }, - }); - } catch (error) { - console.error('Error serving Pagefind file:', error); - return new NextResponse('File not found', { status: 404 }); - } -} diff --git a/components/search-modal.tsx b/components/search-modal.tsx index 54ea09d..4b7a571 100644 --- a/components/search-modal.tsx +++ b/components/search-modal.tsx @@ -32,17 +32,17 @@ export function SearchModal({ isOpen, onClose }: SearchModalProps) { // Load Pagefind UI CSS link = document.createElement('link'); link.rel = 'stylesheet'; - link.href = '/pagefind/pagefind-ui.css'; + link.href = '/_pagefind/pagefind-ui.css'; document.head.appendChild(link); // Load Pagefind UI JS script = document.createElement('script'); - script.src = '/pagefind/pagefind-ui.js'; + script.src = '/_pagefind/pagefind-ui.js'; script.onload = () => { if (searchContainerRef.current && (window as any).PagefindUI) { pagefindUIRef.current = new (window as any).PagefindUI({ element: searchContainerRef.current, - bundlePath: '/pagefind/', + bundlePath: '/_pagefind/', showSubResults: true, showImages: false, excerptLength: 15,