Static Site Search with Middleman and lunrjs

A few months ago, someone opened an issue asking for a site search on my blog. Neat idea, it wasn’t high on my list of priorities at the time, but maybe I’d get to it someday.

Well, today’s the day 🎉

(Note: The original “the day” was two weeks ago but I had given up in frustration.)

Search is an interesting problem. Most search engines run on servers and not the browser client. This site, just like all static sites like those built with Middleman, is generated on a computer before being served statically. It’s a faster, easier, and more secure way of serving web pages that don’t need dynamism, but it does mean that you can’t run server code when a page is fetched.

Running search on servers makes sense for DuckDuckGo and Google because their search engines are trying to cover the whole internet. But for a site like mine, a client-side search engine written in Javascript can be a suitable solution.

Solr is an open source search engine. lunrjs is a Javascript-based search engine, which claims to be:

A bit like Solr, but much smaller and not as bright.

Lovely. I think the sun-vs-moon metaphor for server-vs-client search engines is really apt.

There are a few Middleman extensions that integrate lunrjs search into static sites, but I couldn’t get any to work for me because I didn’t understand how they worked. I ended up reading the source code of one to understand exactly how it worked. Even then, I couldn’t get things right. It turns out that I didn’t know enough Javascript to use a Javascript-based search engine. Not yet anyway.

I submitted a work-in-progress pull request and gave up again.

After a little break and some food, I went back and looked into a different extension. Actually it was the original extension I tried but I couldn’t get it working. I understood what it was doing on the Ruby side, and concentrated just on the Javascript. After looking up some jQuery syntax, I had something that worked.

Some fiddling with CSS and lining things up, I had a ready PR.

Screenshot of site search

Site search stumped me for weeks. Distinct from search engines in general, server-side static site search is a very interesting problem in its own right. Ruby code uses Javascript to generate a search engine index of the content of my entire site. Then client-side Javascript downloads that index and uses lunrjs to run queries against it. It crosses the dynamic-to-static barrier, which isn’t something many other features of static sites need to do.

After submitting the pull request, I realized I had been working into the late evening, that I’d had a beer or two, and that maybe pushing code to production wasn’t the best thing to do. I pinged Orta on the pull request and asked for a second opinion. It can never hurt to have someone double-check things for you.

Things checked out, and search is here.

The pull request is here, so feel free to comment on anything that you’d like clarification on or that you have a suggestion about. I’m sure there are ways this could be more idiomatically done. (Update: I’ve added documentation to all the code and linked to the relevant code in the readme.)

Writing new features into software can be overwhelming, and stepping back for a break is usually the right answer. It’s okay to give up if things are getting frustrating, and it’s okay to ask for help.

We’re all in this together.

Posted on August 7, 2016