I switched my personal site to Eleventy recently. It's a very good static site generator. Here are some tips and tricks I have discovered that are nice to have when you are creating a site.
Start using the _data folder
If you come from Jekyll you are used to different kinds of variables being available in your templates (site.time
, site.posts
).
Eleventy does not have these by default, but it's quite easy to add them (and more).
Each JSON/JS file in the _data
folder will become available under the filename namespace in your templates. So _data/meta.json
becomes available as meta.some_key_inside_file
.
eleventy.js
The first file I create contains things related to the engine and environment.
module.exports = {
production: process.env.ELEVENTY_ENV === 'production',
development: process.env.ELEVENTY_ENV === 'development',
env: process.env.ELEVENTY_ENV || 'development',
notReady: false, // Flag to prevent something from rendering.
time: () => {
return new Date(); // Simplest example, could use Moment.js to return another format.
},
};
This gives me access to information about environment so I can exclude Google Analytics if it's not production, or print more information in development.
metadata.json
{
"title": "Andeers.com",
"description": "Personal site of Anders Grendstadbakk",
"url": "https://andeers.com/",
"feed": {
"subtitle": "I mainly write about web development and tech.",
"filename": "feed.xml",
"path": "/feed/feed.xml",
"url": "https://andeers.com/feed/feed.xml",
"id": "https://andeers.com/"
},
"author": {
"name": "",
"email": ""
}
}
The metadata.json contains information about this site and me. I also have some fields for the RSS feed. It's nice to collect all this information in one file so when you make changes you have it all together.
.eleventy.js
This file is where you define collections, filters, and shortcodes.
A hot tip is that since this is node.js you can require()
your data files here and access the variables. This way you can use content from metadata
in helper functions, or output something different in development.
const eleventyVars = require('./_data/eleventy');
Create a collection based on a folder of files
eleventyConfig.addCollection('posts', function(collection) {
return collection.getFilteredByGlob('./_posts/*').reverse().filter(function(item) {
// Only include items with a permalink.
return !!item.data.permalink;
});
});
This gives you a collection of all items in the _posts
folder.
Latest posts
eleventyConfig.addCollection('latestPosts', function(collection) {
const posts = collection.getSortedByDate().reverse();
let items = [];
for( let item of posts ) {
if(!!item.inputPath.match(/\/_posts\//)) {
items.push( item );
if( items.length >= 5 ) {
return items;
}
}
}
});
This snippet gives you a variable with the 5 latest posts you can use on your front page.
Date functions
eleventyConfig.addFilter('readableDate', dateObj => {
return DateTime.fromJSDate(dateObj).toLocaleString(DateTime.DATE_FULL);
});
// Used in Handlebars like this: {{readableDate post.date }}
This function renders the date in a specific way, but it could easily take another argument that specifies format, or use Moment.js in stead of Luxon.
Meta functions
eleventyConfig.addFilter('pageTitle', title => {
if (title && title !== '') {
return `${title} | ${metadata.title}`;
}
return metadata.title;
});
eleventyConfig.addFilter('pageDescription', (description, opt) => {
const {content, excerpt } = opt.data.root;
if (description && description !== '') {
return description;
}
else if (excerpt && excerpt !== '') {
return excerpt;
}
else if (content && content !== '' && !opt.data.root.isFront) {
return snippetGenerator(content);
}
return metadata.description;
});
I have two functions I use for <title>
and <description>
. The first one renders the page title with the site name appended, and if a page title is not available it just returns the site name.
The pageDescription check multiple places for a description, first if one was specifically defined, then it tries to generate one from the content of the page. If that does not work it falls back to the generic site description.
Other stuff
In the root index.html I add a isFront: true
to the front matter, this makes it possible to do conditional stuff when rendering the front page:
<section>
<p>This paragraph is only written to the front page.</p>
<p>This paragraph is rendered on all pages.</p>
</section>
Since my website is a work in progress I will probably find other useful snippets to make Eleventy even better, so check this site out on Github.