DEV Community

Cover image for I accidentally created my new favorite search plugin.
CodeWithCaen
CodeWithCaen

Posted on • Updated on

I accidentally created my new favorite search plugin.

Introduction

The other day I set out to create a simple search plugin for HydePHP, the static site generator I'm developing. I wanted something that would quickly add a search feature to Hyde documentation sites.

When planning the feature I stated that More complex sites will probably (and should) use Algolia, which is an amazing service that I personally use for some sites (Thank you DocSearch!)

But since Algolia takes some time to get set up, I wanted something simple that I could ship as a default until/unless the user decides to use Algolia.

The tech stack

The entire search feature is created using object-oriented TypeScript and compiled to ES6 JavaScript.

While I'm a full-stack developer, my main language is PHP. I do on occasion write JavaScript (and TypeScript) as well, of course. And since this search feature needed to be fully client-side, using JS was a no-brainer. I did want to challenge myself though, and in PHP I write object-oriented code 99% of the time, but I realized I had never written a JS class before. So that's what I decided to do.

How it works

In short

It works by using a precompiled JSON search index that contains the searchable content for all the pages, as well as a link to them. The current version assumes that the searchable content is the entire page content, but it could just as well be a string of keywords, excerpts, or something else.

Creating the search index JSON

I started out with writing the Hyde backend code that generates the JSON search index in PHP.

I considered a few different strategies but ended up creating an array of objects, each containing the page's slug, URL, title, and searchable content.

For the searchable content, I used the page Markdown compiled to plain text, but I could have used the page's keywords, or even the page's excerpt to save space.

Creating the frontend API

When visiting a page, the search index is loaded by the HydeSearch script using AJAX.

Then when you type something in the search field, the results are filtered in realtime, and then sorted by the number of matches. The results are rendered in a description list element where the list header contains the page title and a link to it. For the list description, a context string is added.

In the context section for each result, HydeSearch finds the first occurrence of the search term in the page content, extracts the whole sentence, and highlights the matching word.

Screenshot of the search section

Built to be customized

The actual generated HTML comes unstyled but brings plenty of hooks to customize it. The screenshot above shows some example styles that I used. The following screenshot shows the unstyled elements. Since Semantic HTML is used, I think it looks pretty good just as it is.

Screenshot of unstyled search

How it became my new favourite

I promise the title is not clickbait. I actually love how this turned out. Besides how fast it is, my favourite feature is that it extracts the whole related sentence making it easy to see what the search term is actually referring to.

Try it out!

I created a hosted live demo. You can also find the source code on GitHub.

Update: The plugin has now been integrated into Hyde, and is live on the https://hydephp.com/docs!

Top comments (1)

Collapse
 
codewithcaen profile image
CodeWithCaen

Wow this is absolutely amazing feedback! Thank you so much! I come from a PHP background where I do OOP. I am still learning JS/TS, this was also my first time using OOP in JavaScript. Part of this the goal of this project was to learn object-oriented TypeScript, so I am aware it's application is probably overkill.

Yeah, I know exactly what the JSON response looks like, I did not know I can type the response properties. That's awesome. I'm also not familiar with the template element, but that sounds very promising and helpful. I've also had issues with multiple instances, so that is definitely something I want to refactor. Thank you for the tip on passing them as arguments!

Again, I can't stress enough how helpful this is and how grateful I am! Cheers!