Add search function to your static site using jQuery and JSON
An example on how to add search function to your (Hugo) static site using jQuery and JSON.
Static sites have many advantages including fast-loading, lower server requirement, a lot of flexibility and many free hosting services. Many static site generators have appeared in the recent years and some of them got quite popular, e.g., Jekyll, Hugo, Hexo and Middleman. But one of the downsides is the search function.
One of the general solutions is to use a third-party searching engine like Google site search, but you might not get what you were looking for because it takes a while unitl your site content has been indexed. So many people wish to have a client-side search function on their sites. For sites built with Hexo the Algolia plugin has been well supported, but currently not for Jekyll and Hugo sites.
But luckily there is a good searching solution using jQuery + JSON, and another JavaScript library like Lunr.js, and Fuse.js. Here is the main steps:
Run Hugo build, change /Public/json/index.html to PagesIndex.json, delete the first “,” and move it to your index directory (e.g., /js/lunr/PagesIndex.json)
Resulting JSON looks like this (THE LAST LINE OF EACH ITEM HAS NO ‘,’ AT THE END)
1
2
3
4
5
6
7
8
9
10
11
12
13
[{"title":"Smp_000020","href":"/geneexp/sm/Smp_000020.1/","content":"bifunctional protein NCOAT"},{"title":"Smp_000030","href":"/geneexp/sm/Smp_000030.1/","content":"26s proteasome regulatory particle subunit"},//...]
<scripttype="text/javascript"src="/js/jquery.min.js"></script><scripttype="text/javascript"src="/js/vendor/lunr.min.js"></script><scripttype="text/javascript">varlunrIndex,$results,pagesIndex;// Initialize lunrjs using our generated index file
functioninitLunr(){// First retrieve the index file
$.getJSON("/js/lunr/PagesIndex.json").done(function(index){pagesIndex=index;console.log("index:",pagesIndex);// Set up lunrjs by declaring the fields we use
// Also provide their boost level for the ranking
lunrIndex=lunr(function(){this.field("title",{boost:10});// this.field("tags", {
// boost: 5
//});
// this.field("content");
// ref is the result item identifier (I chose the page URL)
this.ref("href");});// Feed lunr with each file and let lunr actually index them
pagesIndex.forEach(function(page){lunrIndex.add(page);});}).fail(function(jqxhr,textStatus,error){varerr=textStatus+", "+error;console.error("Error getting Hugo index flie:",err);});}// Nothing crazy here, just hook up a listener on the input field
functioninitUI(){$results=$("#results");$("#search").keyup(function(){$results.empty();// Only trigger a search when 2 chars. at least have been provided
varquery=$(this).val();if(query.length<8){return;}varresults=search(query);renderResults(results);});}/**
* Trigger a search in lunr and transform the result
*
* @param {String} query
* @return {Array} results
*/functionsearch(query){// Find the item in our index corresponding to the lunr one to have more info
// Lunr result:
// {ref: "/section/page1", score: 0.2725657778206127}
// Our result:
// {title:"Page1", href:"/section/page1", ...}
returnlunrIndex.search(query).map(function(result){returnpagesIndex.filter(function(page){returnpage.href===result.ref;})[0];});}/**
* Display the 10 first results
*
* @param {Array} results to display
*/functionrenderResults(results){if(!results.length){return;}// Only show the ten first results
results.slice(0,10).forEach(function(result){var$result=$("<li>");$result.append($("<a>",{href:result.href,text:"» "+result.title+" "}),result.content);$results.append($result);});}// Let's get started
initLunr();$(document).ready(function(){initUI();});</script>
// Extract the `q` query parameter
varqueryStringRegex=/[\?&]q=([^&]+)/g;varmatches=queryStringRegex.exec(window.location.search);if(matches&&matches[1]){varvalue=decodeURIComponent(matches[1].replace(/\+/g,'%20'));// Load the posts to search
$.getJSON('/search/posts.json').then(function(posts){// Remember to include Fuse.js before this script.
varfuse=newFuse(posts,{keys:['title','tags']// What we're searching
});// Run the search
varresults=fuse.search(value);// Generate markup for the posts, implement SearchResults however you want.
var$results=SearchResults(results);// Add the element to the empty <div> from before.
$('#searchResults').append($results);});}
Link your search box to the script to search and show results