| Tags: front-end

Excerpts are short extracts of an article —usually the first sentences—, and are used in blogs to show only a fragment of a post, either to break a long article and put a “Read more…” link, or to display a list of posts with a bit more of context than just the title. In this article I’ll share how I implemented excerpts for this website.

Eleventy, the system that I’m now using to generate this blog, has an API to handle excerpts, but it has some shortcomings:

While useful, it didn’t quite handle my use case. I wanted to have an implicit, default excerpt for my articles and I also wanted to use Markdown for my excerpts. After some searching, I found a plugin that handled default excerpts —but bypassed Eleventy’s own API, so I couldn’t have both implicit and explicit excerpts. And for Markdown parsing, I could just use a npm module to do that.

In the end, I used the plugin’s idea to just graph the first paragraph of a post as a default excerpt, unless there was one already defined via Eleventy’s API, and then use the markdown-it module to parse it. This is how it looks like:

First, we separate the excerpts code in a separate file, for readability.

plugins/excerpt.js:

const markdown = require('markdown-it');

module.exports = function excerpt(item) {
const separator = '</p>';
const excerpt = item.data?.page?.excerpt;

// If it has an explicit excerpt (see setFrontMatterParsingOptions),
// use it.
if (excerpt) {
return markdown({ html: true }).render(excerpt);
}

// If there's no explicit excerpt, use the first paragraph as the
// excerpt. This is already parsed to HTML, so no need to use
// markdown-it here
const location = item.templateContent?.indexOf(separator);
return location >= 0
? item.templateContent.slice(0, location + separator.length)
: '';
};

Then Eleventy’s config file would look like this:

.eleventy.js:

// import my own plugin
const excerpt = require('./plugins/excerpt');

module.exports = function (eleventyConfig) {
// ...

// Setup excerpts
eleventyConfig.setFrontMatterParsingOptions({
excerpt: true,
excerpt_separator: '<!-- excerpt -->',
});

eleventyConfig.addShortcode('excerpt', (article) => {
return excerpt(article);
});
};

With that in place, in the templates I only need to use the shortcode excerpt to output it:

 {%- for article in collections.articles -%}
<article>
<h3>{{ article.data.title }}</h3>
{% excerpt article %}
</article>
{%- endfor -%}

And that’s about it. Quick and simple, and since it uses Eleventy’s own API, I hope it won’t give much headache to maintain in the future.