Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Integrate lunrjs with a Hugo (gohugo.io) site.
const fs = require('fs').promises;
const {promisify} = require('util');
const frontMatterParser = require('parser-front-matter');
const parse = promisify(frontMatterParser.parse.bind(frontMatterParser));
async function loadPostsWithFrontMatter(postsDirectoryPath) {
const postNames = await fs.readdir(postsDirectoryPath);
const posts = await Promise.all(
postNames.map(async fileName => {
const fileContent = await fs.readFile(
`${postsDirectoryPath}/${fileName}`,
'utf8'
);
const {content, data} = await parse(fileContent);
return {
content: content.slice(0, 3000),
...data
};
})
);
return posts;
}
const lunrjs = require('lunr');
function makeIndex(posts) {
return lunrjs(function() {
this.ref('title');
this.field('title');
this.field('content');
this.field('tags');
posts.forEach(p => {
this.add(p);
});
});
}
async function run() {
const posts = await loadPostsWithFrontMatter(`${__dirname}/content/post`);
const index = makeIndex(posts);
console.log(JSON.stringify(index));
}
run()
.then(() => process.exit(0))
.catch(error => {
console.error(error.stack);
process.exit(1);
});
node ./build-lunrjs-index.js > static/search-index.json
{
"devDependencies": {
"lunr": "^2.3.6",
"parser-front-matter": "^1.6.4"
}
}
<form method="get" action="">
<input id="search" name="q" type="text" />
<button type="submit" class="button">Search</button>
<a href="/search">Clear</a>
</form>
<div id="#app"></div>
<script src="https://unpkg.com/lunr/lunr.js"></script>
<!-- Generate a list of posts so we can display them -->
{{ $p := slice }}
{{ range (where .Site.RegularPages "Section" "==" "post") }}
{{ $post := dict "link" .RelPermalink "title" .Title "content" (substr .Plain 0 200) -}}
{{ $p = $p | append $post -}}
{{ end }}
<script>
const posts = JSON.parse(
{{ $p | jsonify }}
);
const query = new URLSearchParams(window.location.search);
const searchString = query.get('q');
document.querySelector('#search').value = searchString;
const $target = document.querySelector('#app');
// Our index uses title as a reference
const postsByTitle = posts.reduce((acc, curr) => {
acc[curr.title] = curr;
return acc;
}, {});
fetch('/gen/search-index.json').then(function (res) {
return res.json();
}).then(function (data) {
const index = lunr.Index.load(data);
const matches = index.search(searchString);
const matchPosts = [];
matches.forEach((m) => {
matchPosts.push(postsByTitle[m.ref]);
});
if (matchPosts.length > 0) {
$target.innerHTML = matchPosts.map(p => {
return `<div>
<h3><a href="${p.link}">${p.title}</a></h3>
<p>${p.content}...</p>
</div>`;
}).join('');
} else {
$target.innerHTML = `<div>No search results found</div>`;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.