johnny-mh / devlog

6 stars 1 forks source link

astro-fuse difficulty... #8

Closed rickbsgu closed 1 year ago

rickbsgu commented 1 year ago

Can we do this without importing preact?

Would rather keep project as straight Astro.

Tried an approach that waited or the global, 'loadFuse' to be created. That seemed to work, but then when I try to call 'search', I get invalid hits.

Here is my astro.config.mjs:

export default defineConfig({
  integrations: [
    mdx(), 
    tailwind(),
    fuse({
      keys: ['content', 'frontmatter.title'],
      ignoreLocation: true
    })
  ],
});

And here is a simple controller I'm trying to bypass the preact crap. Written as a static class.

FuseCtlr.mjs

export default class FuseCtlr {
  static fuse;

  /// simple delay function set up as a promise.
  static _delay() {
    return new Promise((acc, rej) => {
      setTimeout(() => {
        acc();
      }, 500);
    }
  );
  }

  // initiazer - waits for 'loadFuse' to appear, and then calls it, assigning the
  // fuse object
  static async init() {
    if (!FuseCtlr.fuse) {
      while (!window.loadFuse)
        await FuseCtlr._delay();

      FuseCtlr.fuse = await loadFuse();
    }
  }

  // the search function
  static async search(term) {
    await FuseCtlr.init();
    return FuseCtlr.fuse.search(term);
  }
}
johnny-mh commented 1 year ago

Hi @rickbsgu You don't need to loop for loading index file. When content updated. dev-server reload it automatically. But it seems to be some side effect after Astrojs updates.

I'll check code and update library with pure astro component example.

johnny-mh commented 1 year ago

@rickbsgu I have just released version 0.0.4, which improves usability. I have also added basic usage examples to the README.md file. Please let me know if you have any issues. Thank you.

rickbsgu commented 1 year ago

@johnn-mh - Ok, tried a variation of your example and I get 'loadFuse' is not defined. I tried putting it in a 'window.onload' function and it still comes up undefined.

So, I seem to have to go back to my original implementation to get anything at all, but the problem continues that it's returning totally invalid results - the search term is not in any of the results it's returning(!!). I don't know if that's because of the fuse options or what.

(FWIW, I'm doing the query on another page, and then sending the search term to a results page via a URL parameter. The parameter is coming through to the results page just fine, but the search results are completely bogus.)

Update: If I put a term that exists in a title, it seems to do the right thing - I get valid hits. But, if I put in a term that exists in content, I get totally bogus results. These are .mdx files. Is that an issue with Fuse, do you know?

johnny-mh commented 1 year ago

@rickbsgu I just created a CodeSandbox demo based on the basic example. It seems to work and does not error with the message 'loadFuse' is not defined.

https://codesandbox.io/p/sandbox/magical-field-zd6tqv

If you see any errors related to the message cant find dist/fuse.js, you can go to the 'Blog' page and you will see the message dist/fuse.js created/updated. I am still trying to find a way to build all markdown files before they are noticed by the Vite builder.

image

I also just tried checking the search results.

I really appreciate your interest and for reporting the issue.

rickbsgu commented 1 year ago

I really appreciate your interest and for reporting the issue.

Hey, I really appreciate you're taking the time to respond and try various things.

I get the sense that some of my issues are Fuse related. I've been poring over the README.md for the project, but there are a lot of principles I don't understand. Been playing with different options, too, but not getting any further.

I think one issue may be my use of .mdx files. I use a lot of components in the .mdx (that's why I'm using mdx). I looked at the generated fuse.json file and it seems like the content is all there, but it yields wrong results as if it's interpreting the fuse.json file incorrectly/lookups are invalid or something.

johnny-mh commented 1 year ago

@rickbsgu I have just tested and published the new draft 0.0.5-alpha.0, which attempts to support searching static rendered content that includes components in MDX.

(This does not fix the wrong searching problem of Fuse.js, but I will check it soon.)

However, due to its limitations, dynamic rendered content that is rendered after the page loads is not searchable.

And the fuse.json only created build runs. (you can make it with "build" buttons on terminal section")

image

You can use the following additional plugin configuration to enable this feature:

[
fuse({
  keys: [...],
  basedOn: 'output', // this will activate output base searching mode
  filter?: (pathname: string) => boolean, // filter searching pages

  // this mode creates an index after the HTML files are created. I can't find a way to reference the original contents, so this function can help create frontmatter from HTML files.
  // ex) $ => ({ title: $('h1').first().text() })
  // ex) $ => ({ title: $('meta[property="og:title"]').text() })
  extractFrontmatterFromHTML?: ($: CheerioAPI, pathname: string) => any,
})
]

I have not yet written documentation. If you do not mind, please test it. You can refer to my codesandbox. (you can pass fuse.js options to LoadFuse method too. please refer codesandbox)

https://codesandbox.io/p/sandbox/astro-fuse-test-forked-vkgdrq?file=%2Fsrc%2Fcomponents%2FSearch.astro%3A16%2C16

You can see the SearchMe.astro render text 'YYUUNNKK' and you can search it. (i've tested preact too.)

Thank you very much.

rickbsgu commented 1 year ago

Ok, trying this. I presume it goes in the fuse section of astro.config.mjs?

First issue is a lot of syntax errors - the object members 'filter?' and 'extractFrontmatterFromHTML?' can't be conditional.

Second issue is types: they're not allowed in an .mjs file, as far as I know?

I did upgrade and install 0.0.5-alpha.0

I looked at the codesandbox but didn't see any configuration settings that looked like this.

Help me out, here...

On Sun, Aug 13, 2023 at 3:22 AM johnny kim @.***> wrote:

@rickbsgu https://github.com/rickbsgu I have just tested and published the new draft 0.0.5-alpha.0, which attempts to support searching static rendered content that includes components in MDX.

(This does not fix the wrong searching problem of Fuse.js, but I will check it soon.)

However, due to its limitations, dynamic rendered content that is rendered after the page loads is not searchable.

You can use the following additional plugin configuration to enable this feature:

[fuse({ keys: [...], basedOn: 'output', // this will activate output base searching mode filter?: (pathname: string) => boolean, // filter searching pages

// this mode creates an index after the HTML files are created. I can't find a way to reference the original contents, so this function can help create frontmatter from HTML files. // ex) $ => $('h1').first().text() // ex) $ => $('meta[property="og:title"]').text() extractFrontmatterFromHTML?: ($: CheerioAPI, pathname: string) => any,})]

I have not yet written documentation. If you do not mind, please test it. You can refer to my codesandbox.

Thank you very much.

https://codesandbox.io/p/sandbox/astro-fuse-test-forked-vkgdrq?file=%2Fsrc%2Fcomponents%2FSearch.astro%3A16%2C16

— Reply to this email directly, view it on GitHub https://github.com/johnny-mh/blog2/issues/8#issuecomment-1676293989, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABHNQRJEDXK4ERUIXJXUOLXVCMFJANCNFSM6AAAAAA3HK4AWU . You are receiving this because you were mentioned.Message ID: @.***>

rickbsgu commented 1 year ago

Don't quite understand this function and comment:

      filter: (pathname) => boolean, // filter searching pages

      // this mode creates an index after the HTML files are created. I can't find a way to reference the original contents, so this function can help create frontmatter from HTML files.
      // ex) $ => $('h1').first().text()
      // ex) $ => $('meta[property="og:title"]').text()

Where does the pathname come from? (fuse or astro is calling the function with that argument, presumably...), what are the ex) fragments and what is the '$' variable (jquery?)? Would this work?

  filter (pathname) => ('body').text());

?

Sorry if I'm being dense. If you can point me to some documentation I'll scour it.

johnny-mh commented 1 year ago

@rickbsgu When you use the baseOn: 'output' option, as shown in the code below, the Fuse.js index will be created based on the bundle files in the dist folder.

// astro.config.mjs

export default defineConfig({
  integrations: [mdx(), fuse({ keys: [...], basedOn: 'output' })]
})

In this mode, the library simply reads all HTML files and extracts the content for searching. As a result, it is difficult to know the frontmatter data for each document.


The filter option is used to filter files that will be searched. If you write the configuration below, only HTML files within the /blog/* path will be searchable.

fuse({
  keys: [...],
  basedOn: 'output',
  filter: pathname => /^\/blog\/g.test(pathname)
})

And I can't tell which HTML file was created from a .mdx or .astro source. The extractFrontmatterFromHTML option can be used to create a frontmatter object from an HTML file.

For example, if you need the original title value because the pathname is sluggified, the following MDX file can be bundled into various path HTML files like /content/2023-08-14-a-page-title.mdx => blog/2023/08/a-page-title.html.

---
title: A Page Title
---

In this situation, the extractFrontmatterFromHTML option can be helpful. If you render the title to the meta[property="og:title"] tag, you can get it with the following options.

The $ is a Cheerio instance, and you can use it to search for elements. For more information, see the Selecting Elements links. Selecting Elements

fuse({
  keys: [...],
  basedOn: 'output',
  extractFrontmatterFromHTML: $ => ({ title: $('meta[property="og:title"]').text() })
})

If you need all frontmatter content. then you can use like below.

// SUDO-CODE
---
const {frontmatter} = Astro.props;
const {title, description} = frontmatter;
---
<html>
   <!-- ... -->
<input
    type="hidden"
    data-frontmatter
    value={JSON.stringify({ title, description })}
/>
</html>
fuse({
  keys: ["content", "frontmatter.title"],
  basedOn: "output",
  extractFrontmatterFromHTML: ($) => {
    const el = $("[data-frontmatter]");

    if (el.length) {
      return JSON.parse(el.first().val());
    }

    return { title: $("h1").first().text() };
  },
}),

I hope this can help.

rickbsgu commented 1 year ago

Ok. Bunch to parse here, but I think I'm cutting through the haze... Cheerio is new to me, but I'm pretty familiar with jquery. I think I understand the filter function better, and the frontmatter issues, as well.

Will try later and respond - got some other things to do, today.

Thanks, rickb

rickbsgu commented 1 year ago

@johnny-mh Ok, had to take a couple of days to address some other issues.

So, I tried this a completely different way, bypassing astro-fuse and, results are exactly the same. Bogus. Exactly the same way.

It's got to have something to do with my fuse options, but I don't now what. At this stage of the game, I'm tempted to blow off fuse and just do a js caseless search through the json structure, to begin with, and see how that works. Move from there.

Cheers, rickb