Appearance
Implement Search on 11ty Static Site
In this post, we will walk through the steps of implementing search on an 11ty static site with lunr
. This involves the following:
- Create a search index
- Implement user input for searching pages
Approach
We will create the search index during build time and store the index in JSON format. This JSON will be served on an endpoint (e.g. /search-index.json
). The browser client can then fetch this index, and allow user to perform a search. This approach of pre-building indexes is preferred to save time generating an index on the client side.
Create a Search Index
In this example, we want to index all pages with tag: posts
. We will make use of 11ty's collection of tag: posts
to generate a lunr
search index.
Template File to Store Index JSON
We need a template file to output search-index.json
during build time. We will use a Nunjucks file for this:
# src/search-index.njk
---
permalink: /search-index.json
---
{{ collections.posts | buildSearchIndex | safe }}
The basic idea is to start with collection.posts
which has all the page data relating to tag: posts
. The collection data then passes through a filter function buildSearchIndex
which generates a lunr
search index in JSON format. Finally, this JSON data passes through the the Nunjucks safe
filter to prevent escaping of JSON content.
buildSearchIndex
Filter
In this example, we will create an index based only on the title
field, and use the page url as the id or ref of each document. We can add the filter with the following:
js
eleventyConfig.addFilter('buildSearchIndex', function (arr) {
const docs = arr.map(function (doc) {
return {
url: doc.url,
...doc.data,
};
});
const idx = lunr(function () {
this.field('title');
this.ref('url');
docs.forEach(function (doc) {
this.add(doc);
}, this);
});
return JSON.stringify(idx);
});
The frontmatter data is nested within the data
field of each collection item while the url
field is at the root, which is why we will need to massage the data beforehand.
At the end of all this, the search index is served as a serialized JSON format. On the client side, lunr
will need to load this index before performing a search. This can be done with lunr.Index.load(JSON.parse(searchIndexJson))
. See related lunr
docs here: https://lunrjs.com/guides/index_prebuilding.html
Implement User Input for Searching Pages
Coming soon