Getting started with Eleventy
Eleventy has “Get Started” documentation that shows you how to get from a single markdown file to a built site. That is a nice “proof of idea”, but I haven’t found it to be a helpful way to actually get started with Eleventy. This garden aims to be a better guide for building a simple Eleventy site from scratch.
Setup
- Create a new directory for your project:
mkdir getting-started-eleventy
- In that directory, initialize a new project:
npm init -y
- Install Eleventy:
npm install @11ty/eleventy@canary --save-exact
1 - Add
dev
andbuild
scripts to yourpackage.json
:{ "scripts": { "dev": "eleventy --serve", "build": "eleventy" } }
At this point you’re probably tempted to run the dev
script, but hold off for
a little bit. We need to add some configuration to keep the project organized.
Configuration
- Create a new
src
directory:mkdir src
- Create your first markdown file:
echo "# Hello, world!" > src/index.md
- Create a
.eleventy.js
file in the root directory:touch .eleventy.js
- Add the following configuration to
.eleventy.js
:export default function (eleventyConfig) { return { dir: { input: "src", output: "dist", // Or whatever build directory you prefer }, }; }
This configuration will tell Eleventy to look for source files in the src/
directory, and skip generating webpages for your project README.md
. You can
stick with the default _site/
output directory, but I like explicitly setting
the output directory so that you know where they’re going.
- Add a
.gitignore
file to the root directory:node_modules/ dist/ # Or whatever build directory you chose in .eleventy.js
At this point, you can run npm run build
to generate your site. You should see
a single index.html
file in your build directory. But your site is probably
going to need more than HTML, so we’ll configure Eleventy to handle assets.
Assets
-
Create a new
public/
directory in the root of your project:mkdir public
-
Add a line to your
.eleventy.js
configuration to copy thepublic/
directory to the build directory:export default function (eleventyConfig) { eleventyConfig.addPassthroughCopy({ public: "/" }); return { /* ... */ }; }
This will copy all of the files within your
public/
directory to the root of the build directory. You can test this by adding a CSS files to thepublic/
directory and runningnpm run build
:
echo "body { font-family: system-ui }" > public/styles.css
npm run build
ls dist
You should see styles.css
in the build directory, but the styles won’t apply
because the CSS files isn’t linked to the HTML. To do that, we’ll need to create
a layout.
Layouts
Eleventy supports a bunch of different templating languages for layouts. I don’t like any of them2, but JavaScript is good enough.
- Create a new
_includes/
directory insrc/
:mkdir src/_includes
- Create a new
base.11ty.js
file there:touch src/_includes/base.11ty.js
This will serve as our base layout that includes all the HTML boilerplate. In that file, add the following:
export default class Base {
render(data) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${data.title}</title>
<meta name="description" content="${
data.metaDescription || "Generic site description"
}">
<link rel="stylesheet" href="/styles.css">
</head>
<body>
${data.content}
</body>
</html>
`;
}
}
This layout will render an HTML document with title
, metaDescription
, and
content
properties. Noticed that we’ve now linked the CSS file that we copied
in the “Assets” sections. Now we need to configure our markdown file to use this
layout.
- Update your
index.md
file to use the layout:
---
layout: base.11ty.js
title: Home
metaDescription: The homepage of my site
---
The "body" of markdown files becomes `content` in layouts.
Now when you run your build again, you should see your index.html
file with
the additional markup including applied styles.
When you want to chain a layout in JavaScript, you need to refer to the parent
layout in the class
’s data
method:
export default class Page {
data() {
return {
layout: "base.11ty.js",
};
}
render(data) {
return `
<main>
<h1>${data.title}</h1>
${data.content}
</main>
`;
}
}
This new Page
layout will render within the Base
layout, giving you the
power of composition when building pages. I typically have a base layout and
then 2-3 other layouts that I use for different types of pages.
The next thing you’ll probably want are UI “components” that you can reuse across your site, and for that we’ll turn to Eleventy’s “shortcodes”.
Shortcodes
You could organize this section however you want. I’m going to show you one way that works well for smaller projects.
-
Create a directory for shortcodes in
_includes/
:mkdir src/_includes/shortcodes
-
Create your first shortcode file:
touch src/_includes/shortcodes/emoji.js
-
Add the following to
emoji.js
:/** An accessible emoji shortcode */ export default function emojiShortcode(emoji, label) { let attributes = [ "role=img", label ? `aria-label=${label}` : "aria-hidden=true", ]; return `<span ${attributes.join(" ")}>${emoji}</span>`; }
-
Add the shortcode in your
.eleventy.js
config file:import emojiShortcode from "./src/_includes/shortcodes/emoji"; export default function (eleventyConfig) { eleventyConfig.addShortcode("emoji", emojiShortcode); return { /* ... */ }; }
-
Use the new shortcode in your markdown file:
--- layout: page.11ty.js title: Home --- {% emoji "👋" "Waving hand" %} Hi there!
-
Use the new shortcode in your layout file:
export default class Page { data() { return { layout: "base.11ty.js", }; } render(data) { return ` <main> <h1>${data.title}</h1> ${data.content} ${this.emoji("👋", "Waving hand")} Thanks for visiting! </main> `; } }
Build your site and you should see the emoji rendering with the appropriate markup.
Conclusion
There is a lot more that we could do, but at this point you are definitely started. With this little bit of organization and configuration, you’re now on your way to building real sites with Eleventy.
Footnotes
-
I’m recommending the canary release here because it includes ECMAScript module support. This is the future of JavaScript and Eleventy, so might as well get on board now. ↩
-
I’ve been spoiled by composition patterns in JSX, Svelte, and Astro. I find it difficult to build UI in the way that my mind wants to think using templating languages like Nunjucks or Liquid. ↩