CloudCannon / pagefind

Static low-bandwidth search at scale
https://pagefind.app
MIT License
3.22k stars 97 forks source link

UI: how to pass a custom index to PagefindUI #572

Closed KonnorRogers closed 3 months ago

KonnorRogers commented 4 months ago

Hi there! I've been creating a custom index with the NodeJS API and writing the files to disk and it's been working well in dev. I was curious if there was a way to pass the in memory index of files to the PagefindUI constructor? I couldn't find anything in the docs. All I see are "bundlePath" and "mergeIndex" which seem to expect URLs and not an in memory Pagefind index.

bglw commented 3 months ago

Hmm I'm not sure I fully follow the question, do you have any project or code samples you could share for this?

The NodeJS API intends to run on a local machine or a server, and either build to disk or serve files in memory. In both cases the search files will be accessible via their URLs. The frontend Pagefind code typically wouldn't know which strategy is being used, as it just points to the URL of the index (whether or not your NodeJS process is serving it from memory).

I haven't done any exploration of an in memory index of files existing in the browser, but I don't think this would be a well supported workflow.

KonnorRogers commented 3 months ago

@bglw so the TLDR is I'm using Pagefind in Starlight / Astro. I have an endpoint that currently creates a custom index in Development and writes to a file, like this:

import * as pagefind from 'pagefind';
import * as path from 'node:path';

// clean up once complete
import { getCollection } from 'astro:content';

export async function generateSearch() {
  const { index } = await pagefind.createIndex({});
  if (!index) return;

  let json: Array<{ url: string; content: string }> = [];

  // Get all `src/content/docs/` entries
  let allContent = await getCollection('docs');

  allContent = allContent.filter(doc => {
    return doc.data.pagefind !== false;
  });

  await Promise.allSettled(
    allContent.map(async entry => {
      const { category, title, description } = entry.data;
      const resp = await fetch('http://localhost:4000/' + entry.slug);
      const html = await resp.text();

      return await index?.addHTMLFile({
        content: html,
        url: entry.slug
      });
    })
  );

  const { errors } = await index.writeFiles({
    outputPath: path.join(process.cwd(), 'public', 'pagefind')
  });

  return json;
}

export async function GET() {
  await generateSearch();

  return new Response(JSON.stringify({}), {
    status: 200,
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

Perhaps I'm the one who's misunderstanding and don't know what I'm asking 😆

I would love to avoid having to write those files to disk, but it's also fine, I'm going to close this as I found something that works for me by adding the "pagefind" files to being ignored by Astro's watch function.

  vite: {
    server: {
      watch: {
        ignored: ["./public/pagefind/**/*.*"], // HERE
      }
    },
  }