I like Pagefind, there’s something about just having a simple js library that works instead of having to do tons of stuff backend for Meilisearch. Unlike for Astro, where there’s a package that does everything, there’s some config to do for Sveltekit and I didn’t find anything.
This is how I eventually got it to work.
Use Vite-plugin-pagefind – check out the site for more documentation, but basically ensures that the pagefind files are available after build.
Don’t overthink the pagefind.json you’ll need to create:
// pagefind.json { "site": "build", "vite_plugin_pagefind": { "assets_dir": "static", "build_command": "npm run build", "dev_strategy": "eager" } }
Add pagefind() to vite.config.js, I had success as the first entry.
// vite.config.js import { sveltekit } from '@sveltejs/kit/vite'; import { enhancedImages } from '@sveltejs/enhanced-img'; import { defineConfig } from 'vite'; import pagefind from 'vite-plugin-pagefind'; export default defineConfig({ plugins: [pagefind(), enhancedImages(), sveltekit()], });
Add it to the route +page.svelte file,
// src/routes/search/+page.svelte <script> import { onMount } from 'svelte'; onMount(async () => { const pagefind = await import('/pagefind/pagefind.js'); pagefind.init(); new PagefindUI({ element: '#search', showImages: false, resetStyles: true, autofocus: true, }); }); </script> <svelte:head> <link href="/pagefind/pagefind-ui.css" rel="stylesheet" /> </svelte:head> <div id="search"></div>
Added the relevant pagefind-ui.js and pagefind-ui.css imports to app.html and app.css respectively. It worked even if I dumped everything into app.html, I just found it neater to separate them.
Change handleHttpError to ‘warn’. Without doing this Cloudflare Pages was complaining about pagefind-ui.css being missing and this killed the build process. The package makes sure it’s there after build.
// svelte.config.js import adapter from '@sveltejs/adapter-static'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { adapter: adapter(), prerender: { handleHttpError: 'warn' }, }, preprocess: vitePreprocess(), }; export default config;
Next we need to process the URLs of the search results. Pagefind adds a .html to the results and that caused 404 errors for me. So let’s go back to +page.svelte to add this (credit to the plugin author’s suggestion to me):
// src/routes/search/+page.svelte <script> import { onMount } from 'svelte'; onMount(async () => { // @ts-expect-error - Pagefind will be present at runtime const pagefind = await import('/pagefind/pagefind.js'); pagefind.init(); new PagefindUI({ element: '#search', showImages: false, resetStyles: true, autofocus: true, // showSubResults is false by default, setting it to true causes duplicate results processResult: (result) => { const url = result.url.replace('.html', ''); result.url = url; return result; }, }); }); </script>
That’s all, actually.