Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 11, 2018 12:00 pm GMT

Turn Jekyll up to Eleventy

Paul Lloyd assembles a heavenly host of cherubs to sing the virtues of the Eleventy static site generator. By looking at how it compares to the familiar Ruby-based Jekyll (which we have espoused the virtues of here before), he may have you humming its tune for this seasons holiday projects. But will it put you on cloud eleven?


Sometimes it pays not to over complicate things. While many of the sites we use on a daily basis require relational databases to manage their content and dynamic pages to respond to user input, for smaller, simpler sites, serving pre-rendered static HTML is usually a much cheaper and more secure option.

The JAMstack (JavaScript, reusable APIs, and prebuilt Markup) is a popular marketing term for this way of building websites, but in some ways its a return to how things were in the early days of the web, before developers started tinkering with CGI scripts or Personal HomePage. Indeed, my website has always served pre-rendered HTML; first with the aid of Movable Type and more recently using Jekyll, which Anna wrote about in 2013.

By combining three approachable languages Markdown for content, YAML for data and Liquid for templating the ergonomics of Jekyll found broad appeal, influencing the design of the many static site generators that followed. But Jekyll is not without its faults. Aside from notoriously slow build times, its also built using Ruby. While this is an elegant programming language, it is yet another ecosystem to understand and manage, and often alongside one we already use: JavaScript. For all my time using Jekyll, I would think to myself this, but in Node. Thankfully, one of Santas elves (Zach Leatherman) granted my Atwoodian wish and placed such a static site generator under my tree.

Introducing Eleventy

Eleventy is a more flexible alternative Jekyll. Besides being written in Node, its less strict about how to organise files and, in addition to Liquid, supports other templating languages like EJS, Pug, Handlebars and Nunjucks. Best of all, its build times are significantly faster (with future optimisations promising further gains).

As content is saved using the familiar combination of YAML front matter and Markdown, transitioning from Jekyll to Eleventy may seem like a reasonable idea. Yet as Ive discovered, there are a few gotchas. If youve been considering making the switch, here are a few tips and tricks to help you on your way1.

Note: Throughout this article, Ill be converting Matt Cones Markdown Guide site as an example. If you want to follow along, start by cloning the git repository, and then change into the project directory:

git clone https://github.com/mattcone/markdown-guide.gitcd markdown-guide

Before you start

If youve used tools like Grunt, Gulp or Webpack, youll be familiar with Node.js but, if youve been exclusively using Jekyll to compile your assets as well as generate your HTML, nows the time to install Node.js and set up your project to work with its package manager, NPM:

  1. Install Node.js:
  2. Initiate NPM: Ensure you are in the directory of your project and then type npm init. This command will ask you a few questions before creating a file called package.json. Like RubyGemss Gemfile, this file contains a list of your projects third-party dependencies.

If youre managing your site with Git, make sure to add node_modules to your .gitignore file too. Unlike RubyGems, NPM stores its dependencies alongside your project files. This folder can get quite large, and as it contains binaries compiled to work with the host computer, it shouldnt be version controlled. Eleventy will also honour the contents of this file, meaning anything you want Git to ignore, Eleventy will ignore too.

Installing Eleventy

With Node.js installed and your project setup to work with NPM, we can now install Eleventy as a dependency:

npm install --save-dev @11ty/eleventy

If you open package.json you should see the following:

"devDependencies": {  "@11ty/eleventy": "^0.6.0"}

We can now run Eleventy from the command line using NPMs npx command. For example, to covert the README.md file to HTML, we can run the following:

npx eleventy --input=README.md --formats=md

This command will generate a rendered HTML file at _site/README/index.html. Like Jekyll, Eleventy shares the same default name for its output directory (_site), a pattern we will see repeatedly during the transition.

Configuration

Whereas Jekyll uses the declarative YAML syntax for its configuration file, Eleventy uses JavaScript. This allows its options to be scripted, enabling some powerful possibilities as well see later on.

Well start by creating our configuration file (.eleventy.js), copying the relevant settings in _config.yml over to their equivalent options:

module.exports = function(eleventyConfig) {  return {    dir: {      input: "./",      // Equivalent to Jekyll's source property      output: "./_site" // Equivalent to Jekyll's destination property    }  };};

A few other things to bear in mind:

Layouts

One area Eleventy currently lacks flexibility is the location of layouts, which must reside within the _includes directory (see this issue on GitHub).

Wanting to keep our layouts together, well move them from _layouts to _includes/layouts, and then update references to incorporate the layouts sub-folder. We could update the layout: frontmatter property in each of our content files, but another option is to create aliases in Eleventys config:

module.exports = function(eleventyConfig) {  // Aliases are in relation to the _includes folder  eleventyConfig.addLayoutAlias('about', 'layouts/about.html');  eleventyConfig.addLayoutAlias('book', 'layouts/book.html');  eleventyConfig.addLayoutAlias('default', 'layouts/default.html');  return {    dir: {      input: "./",      output: "./_site"    }  };}

Determining which template language to use

Eleventy will transform Markdown (.md) files using Liquid by default, but well need to tell Eleventy how to process other files that are using Liquid templates. There are a few ways to achieve this, but the easiest is to use file extensions. In our case, we have some files in our api folder that we want to process with Liquid and output as JSON. By appending the .liquid file extension (i.e. basic-syntax.json becomes basic-syntax.json.liquid), Eleventy will know what to do.

Variables

On the surface, Jekyll and Eleventy appear broadly similar, but as each models its content and data a little differently, some template variables will need updating.

Site variables

Alongside build settings, Jekyll lets you store common values in its configuration file which can be accessed in our templates via the site.* namespace. For example, in our Markdown Guide, we have the following values:

title: "Markdown Guide"url: https://www.markdownguide.orgbaseurl: ""repo: http://github.com/mattcone/markdown-guidecomments: falseauthor:  name: "Matt Cone"og_locale: "en_US"

Eleventys configuration uses JavaScript which is not suited to storing values like this. However, like Jekyll, we can use data files to store common values. If we add our site-wide values to a JSON file inside a folder called _data and name this file site.json, we can keep the site.* namespace and leave our variables unchanged.

{  "title": "Markdown Guide",  "url": "https://www.markdownguide.org",  "baseurl": "",  "repo": "http://github.com/mattcone/markdown-guide",  "comments": false,  "author": {    "name": "Matt Cone"  },  "og_locale": "en_US"}

Page variables

The table below shows a mapping of common page variables. As a rule, frontmatter properties are accessed directly, whereas derived metadata values (things like URLs, dates etc.) get prefixed with the page.* namespace:

JekyllEleventy
page.urlpage.url
page.datepage.date
page.pathpage.inputPath
page.idpage.outputPath
page.namepage.fileSlug
page.contentcontent
page.titletitle
page.foobarfoobar

When iterating through pages, frontmatter values are available via the data object while content is available via templateContent:

JekyllEleventy
item.urlitem.url
item.dateitem.date
item.pathitem.inputPath
item.nameitem.fileSlug
item.iditem.outputPath
item.contentitem.templateContent
item.titleitem.data.title
item.foobaritem.data.foobar

Ideally the discrepancy between page and item variables will change in a future version (see this GitHub issue), making it easier to understand the way Eleventy structures its data.

Pagination variables

Whereas Jekylls pagination feature is limited to paginating posts on one page, Eleventy allows you to paginate any collection of documents or data. Given this disparity, the changes to pagination are more significant, but this table shows a mapping of equivalent variables:

JekyllEleventy
paginator.pagepagination.pageNumber
paginator.per_pagepagination.size
paginator.postspagination.items
paginator.previous_page_pathpagination.previousPageHref
paginator.next_page_pathpagination.nextPageHref

Filters

Although Jekyll uses Liquid, it provides a set of filters that are not part of the core Liquid library. There are quite a few more than can be covered by this article but you can replicate them by using Eleventys addFilter configuration option. Lets convert two used by our Markdown Guide: jsonify and where.

The jsonify filter outputs an object or string as valid JSON. As JavaScript provides a native JSON method, we can use this in our replacement filter. addFilter takes two arguments; the first is the name of the filter and the second is the function to which we will pass the content we want to transform:

// {{ variable | jsonify }}eleventyConfig.addFilter('jsonify', function (variable) {  return JSON.stringify(variable);});

Jekylls where filter is a little more complicated in that it takes two additional arguments: the key to look for, and the value it should match:

{{ site.members | where: "graduation_year","2014" }}

To account for this, instead of passing one value to the second argument of addFilter, we can instead pass three: the array we want to examine, the key we want to look for and the value it should match:

// {{ array | where: key,value }}eleventyConfig.addFilter('where', function (array, key, value) {  return array.filter(item => {    const keys = key.split('.');    const reducedKey = keys.reduce((object, key) => {      return object[key];    }, item);    return (reducedKey === value ? item : false);  });});

Theres quite a bit going on within this filter, but Ill try to explain. Essentially were examining each item in our array, reducing key (passed as a string using dot notation) so that it can be parsed correctly (as an object reference) before comparing its value to value. If it matches, item remains in the returned array, else its removed. Phew!

Includes

As with filters, Jekyll provides a set of tags that arent strictly part of Liquid either. This includes one of the most useful, the include tag. LiquidJS, the library Eleventy uses, does provide an include tag, but one using the slightly different syntax defined by Shopify. If youre not passing variables to your includes, everything should work without modification. Otherwise, note that whereas with Jekyll you would do this:

<!-- page.html -->{% include include.html value="key" %}<!-- include.html -->{{ include.value }}

in Eleventy, you would do this:

<!-- page.html -->{% include "include.html", value: "key" %}<!-- include.html -->{{ value }}

A downside of Shopifys syntax is that variable assignments are no longer scoped to the include and can therefore leak; keep this in mind when converting your templates as you may need to make further adjustments.

Tweaking Liquid

You may have noticed in the above example that LiquidJS expects the names of included files to be quoted (else it treats them as variables). We could update our templates to add quotes around file names (the recommended approach), but we could also disable this behaviour by setting LiquidJSs dynamicPartials option to false. Additionally, Eleventy doesnt support the include_relative tag, meaning you cant include files relative to the current document. However, LiquidJS does let us define multiple paths to look for included files via its root option.

Thankfully, Eleventy allows us to pass options to LiquidJS:

eleventyConfig.setLiquidOptions({  dynamicPartials: false,  root: [    '_includes',    '.'  ]});

Collections

Jekylls collections feature lets authors create arbitrary collections of documents beyond pages and posts. Eleventy provides a similar feature, but in a far more powerful way.

Collections in Jekyll

In Jekyll, creating collections requires you to add the name of your collections to _config.yml and create corresponding folders in your project. Our Markdown Guide has two collections:

collections:  - basic-syntax  - extended-syntax

These correspond to the folders _basic-syntax and _extended-syntax whose content we can iterate over like so:

{% for syntax in site.extended-syntax %}  {{ syntax.title }}{% endfor %}

Collections in Eleventy

There are two ways you can set up collections in 11ty. The first, and most straightforward, is to use the tag property in content files:

---title: Strikethroughsyntax-id: strikethroughsyntax-summary: "~~The world is flat.~~"tag: extended-syntax---

We can then iterate over tagged content like this:

{% for syntax in collections.extended-syntax %}  {{ syntax.data.title }}{% endfor %}

Eleventy also allows us to configure collections programmatically. For example, instead of using tags, we can search for files using a glob pattern (a way of specifying a set of filenames to search for using wildcard characters):

eleventyConfig.addCollection('basic-syntax', collection => {  return collection.getFilteredByGlob('_basic-syntax/*.md');});eleventyConfig.addCollection('extended-syntax', collection => {  return collection.getFilteredByGlob('_extended-syntax/*.md');});

We can extend this further. For example, say we wanted to sort a collection by the display_order property in our documents frontmatter. We could take the results of collection.getFilteredByGlob and then use JavaScripts sort method to sort the result:

eleventyConfig.addCollection('example', collection => {  return collection.getFilteredByGlob('_examples/*.md').sort((a, b) => {    return a.data.display_order - b.data.display_order;  });});

Hopefully, this gives you just a hint of whats possible using this approach.

Using directory data to manage defaults

By default, Eleventy will maintain the structure of your content files when generating your site. In our case, that means /_basic-syntax/lists.md is generated as /_basic-syntax/lists/index.html. Like Jekyll, we can change where files are saved using the permalink property. For example, if we want the URL for this page to be /basic-syntax/lists.html we can add the following:

---title: Listssyntax-id: listsapi: "no"permalink: /basic-syntax/lists.html---

Again, this is probably not something we want to manage on a file-by-file basis but again, Eleventy has features that can help: directory data and permalink variables.

For example, to achieve the above for all content stored in the _basic-syntax folder, we can create a JSON file that shares the name of that folder and sits inside it, i.e. _basic-syntax/_basic-syntax.json and set our default values. For permalinks, we can use Liquid templating to construct our desired path:

{  "layout": "syntax",  "tag": "basic-syntax",  "permalink": "basic-syntax/{{ title | slug }}.html"}

However, Markdown Guide doesnt publish syntax examples at individual permanent URLs, it merely uses content files to store data. So lets change things around a little. No longer tied to Jekylls rules about where collection folders should be saved and how they should be labelled, well move them into a folder called _content:

markdown-guide _content     basic-syntax     extended-syntax     getting-started     _content.json

We will also add a directory data file (_content.json) inside this folder. As directory data is applied recursively, setting permalink to false will mean all content in this folder and its children will no longer be published:

{  "permalink": false}

Static files

Eleventy only transforms files whose template language its familiar with. But often we may have static assets that dont need converting, but do need copying to the destination directory. For this, we can use pass-through file copy. In our configuration file, we tell Eleventy what folders/files to copy with the addPassthroughCopy option. Then in the return statement, we enable this feature by setting passthroughFileCopy to true:

module.exports = function(eleventyConfig) {    // Copy the `assets` directory to the compiled site folder  eleventyConfig.addPassthroughCopy('assets');  return {    dir: {      input: "./",      output: "./_site"    },    passthroughFileCopy: true  };}

Final considerations

Assets

Unlike Jekyll, Eleventy provides no support for asset compilation or bundling scripts we have plenty of choices in that department already. If youve been using Jekyll to compile Sass files into CSS, or CoffeeScript into Javascript, you will need to research alternative options, options which are beyond the scope of this article, sadly.

Publishing to GitHub Pages

One of the benefits of Jekyll is its deep integration with GitHub Pages. To publish an Eleventy generated site or any site not built with Jekyll to GitHub Pages can be quite involved, but typically involves copying the generated site to the gh-pages branch or including that branch as a submodule. Alternatively, you could use a continuous integration service like Travis or CircleCI and push the generated site to your web server. Its enough to make your head spin! Perhaps for this reason, a number of specialised static site hosts have emerged such as Netlify and Google Firebase. But remember; you can publish a static site almost anywhere!


Going one louder

If youve been considering making the switch, I hope this brief overview has been helpful. But it also serves as a reminder why it can be prudent to avoid jumping aboard bandwagons.

While its fun to try new software and emerging technologies, doing so can require a lot of work and compromise. For all of Eleventys appeal, its only a year old so has little in the way of an ecosystem of plugins or themes. It also only has one maintainer. Jekyll on the other hand is a mature project with a large community of maintainers and contributors supporting it.

I moved my site to Eleventy because the slowness and inflexibility of Jekyll was preventing me from doing the things I wanted to do. But I also had time to invest in the transition. After reading this guide, and considering the specific requirements of your project, you may decide to stick with Jekyll, especially if the output will essentially stay the same. And thats perfectly fine!

But these go to 11.


  1. Information provided is correct as of Eleventy v0.6.0 and Jekyll v3.8.5 


About the author

Paul Robert Lloyd is an independent designer, writer and speaker who helps organisations like the Guardian, UNICEF and Mozilla create purposeful digital products.

If not indulging in his love of train travel, Paul can be found in a coffee shop, either writing for his blog, or blathering on Twitter.

More articles by Paul


Original Link: http://feedproxy.google.com/~r/24ways/~3/fVOpw-53TBw/

Share this article:    Share on Facebook
View Full Article

24 Ways

# 24 ways is an edgeofmyseat.com production. # Edited by Drew McLellan and Brian Suda. # Assisted by Anna Debenham and Owen Gregory.

More About this Source Visit 24 Ways