we've built a Middleman extension called middleman-search that'll enable client-side search in your Middleman site. Go get it!

After years of having our company site powered by Wordpress, we got tired of it and migrated to the oh-my-god-it-has-markdown Middleman, hoping it will make us want to blog more often than three times a year.

It was a great move - no more spambots, no more Wordpress vulnerabilities exploited, no more server maintaining. The migration process was really fun, and we could migrate 10+ years of blogposts without major headaches.

But, of all the issues we created during the migration, the first one was still open - enable site-wide search. The great thing about Middleman is it generates static sites, and a search engine doesn't seem that static.

We considered using one of those Google Search plugins that never look good, so we decided we could do better. We found a couple of solutions that didn't seem to work that much or weren't that easy to integrate, so with Palla we did what any obsessive programmer fiddling with a new tool would: we built an extension to do that ourselves.

The extension

The extension uses lunrjs, a full-text search engine that runs on the browser. It adds a new Resource to Middleman's Sitemap with the LunrJS index, so it's available to the client's browsers to perform the search.

When it's time to render the resource, the extension sets up a V8 context, loads LunrJS in there, and sends it each sitemap's resource that has to be indexed. The index will also have an extra field for mapping index resources with useful non-indexed data like the resource's URL, so the results give more information.

The user of the extension should specify which fields of each resource have to be indexed, and we take care of avoid rendering the resource's layouts: we don't want our company name to return each and every page of the site as a result.

The LunrJS source code is included as an asset, so the client just needs to //= require lunr.min in the site's all.js or similar and it'll get through Middleman's standard assets pipeline - so it'll be ready to be used on the browser.

Shut up and take my money!

If you want to use the extension - yay! - you should first add it to your project: add gem 'middleman-search' to your project's Gemfile and bundle install it.

Then you should activate it on your config.rb - with it's configuration.

activate :search do
  search.resources = ['blog/', 'index.html', 'contactus/index.html']
  search.index_path = 'search/lunr-index.json'
  search.fields = {
    title:   {boost: 100, store: true, required: true},
    content: {boost: 50},
    url:     {index: false, store: true}
  }
end

You should tell the extension which path's to index, where to generate the index, and how to treat each of the resource's fields.

After that, tell Sprockets to include lunr.min.js by adding //= require lunr.min to your all.js or equivalent, and then code some search.js that loads and queries the index. For example, you can load the generated index to a lunrData global, create the Lunr index storing lunr.Index.load(lunrData.index) in a lunrIndex variable, and query the results using lunrIndex.search(search_term). You can then access lunrData.docs[your_result] to get all the associated data you stored.

Here's our current code, using jquery-ui to get an autocomplete on the search bar:

If you want to test it - you already probably are in the right place. Look for a search box on the top of any page in our site and give it a try:

Searching on Manas' site using middleman-search

Contributing

The extension WorksForUs™ and seems to be customisable-enough to get published - it's already listed in the Middleman Extensions Directory - but it still may not suit your needs 100%. So we hope we can improve it toghether - did I say it's open source?

Feel free to report any issue you have or send a pull request with any new feature you implement.

Happy searching!