By now, we should have a working site – the trouble is that much of it will use standard options by default, which means we will miss out on a host of features!
Of course, we may not need to use them in every Eleventy-driven project, but it’s still helpful to learn about them. In this chapter, I’ll take you through a whistle-stop tour of the tools available in Eleventy, such as filters, shortcodes, and custom tags, so we can fine-tune how Eleventy works in our project. We’ll then add a few of these features to complement our site – let’s start with understanding what options are available within Eleventy.
Exploring What Is Available
One of the great features of Eleventy is that it can easily be customized using standard JavaScript. You can use one of several tools available within Eleventy itself; you can equally use an NPM package, as the framework runs on Node.
Three of the more popular configuration features in Eleventy
Name of feature | Purpose |
---|---|
Tags | These are the same as for any blog – we tag content to identify specific themes, such as JavaScript or PHP. |
Shortcodes | Shortcodes allow us to create reusable code blocks that Eleventy can insert during the compilation process; when it comes across a word, it recognizes as a shortcode. |
Filters | Filters work in the same way as shortcodes but modify existing values – for example, changing a date value of 11-21-21 to“21st November, 2021.” |
There is a catch, though, when using shortcodes or filters – at first glance, they look to work in the same way, so it can be challenging to decide which format to use and when!
The trick here to determine which to use is twofold: shortcodes are more useful when passing multiple values, such as first name and last name. A shortcode could combine these and create a greeting using the result. For a filter, these replace existing values with a reformatted alternative – dates being a good example. Otherwise, you might want to use a filter to ensure proper names (such as JavaScript) are formatted consistently.
Okay – with that in mind, let’s start with adding a shortcode to our site. We’ll use one to set up YouTube videos, a perfect addition for our blog, but the principle will be the same for any shortcode we want to add to an Eleventy-driven site.
Creating Shortcodes
For this first project, we will add something that I am sure you will have seen on numerous blogs – videos! We could use all manner of formats, but the simplest is to incorporate a YouTube video. After all, why worry about issues like bandwidth when you can give the headache to someone else to manage, right?
Leaving aside who deals with that headache, let’s dive in and look at how to add a shortcode – they come in two parts, beginning with the code we run when Eleventy compiles a shortcode request in our code.
- 1.
First, go ahead and stop your Eleventy development server if it is running – switch to the Node.js terminal session, then hit Ctrl (or Cmd)+C to stop the server.
- 2.
Create a new folder called shortcodes under the _includes folder.
- 3.
Next, fire up your editor, then crack open a new file and add this code – we’ll do it section by section, starting with an import and setting some basic styles:
- 4.
Next comes the markup for our video – immediately below the closing </style> tag, add this:
- 5.
Now save the file as youtube-shortcode.js in the shortcodes folder – you can close it as we no longer need it open for this exercise.
- 6.
Next, switch to your .eleventy.js config file in your editor, then scroll down to just before the line that starts with this code:
- 7.
Leave a line blank, then add in this method:
- 8.
We have one more change to make, which is to add in the shortcode. Open post2.md (where we have made most of our changes), then add this somewhere in the main text. Make sure you leave a line blank before and after it so that Eleventy can compile it correctly:
- 9.
We have almost completed the required changes – all that is left is to recompile our code. Revert to the Node.js terminal session that you had open from step 1. Then, enter npm run serve at the prompt and hit Enter to recompile the code.
- 10.
Switch to your browser – go ahead and browse to http://localhost:8080. If all is well, we should see something akin to that shown in Figure 5-1 when clicking through to the “This is my second post” page.
Yikes – that was indeed a big video! Don’t worry – this is just the first part of setting up the media; we need to apply styles, which we will do in Chapter 6. For now, though, it’s worth exploring the code changes in more detail; we’ve covered some essential concepts that are worth learning when it comes to creating shortcodes in Eleventy.
Breaking Apart the Code
Hands up – how many times have you implemented code to display video media on a page? I’m sure you’ve done it so many times that you could do it in your sleep – after all, sites like YouTube already provide most of the code for you!
Eleventy makes it very easy to add content such as videos – we could do it manually, but this is repetitive if we have a lot of examples to add to our site. Instead, we can use simple functions or shortcodes, which Eleventy uses to insert repeatable code blocks during the compilation process.
In this instance, we used one to add a YouTube video; we first set up a function to create a simple block of styling that frames and sizes the video on screen. Notice the use of the outdent NPM package – this is purely to remove any leading indentation from template strings, which we have used in this function.
Next up came the second part of this function, where we use standard YouTube markup but replace the ID value with ${id}. When using the shortcode, we pass two values into it – one is the ID used in the import markup, and the other is a label I’ve added to act as a caption.
The caption is not a standard part of the YT video markup but shows we can easily add extra elements in the shortcode.
With the function created, we moved to add a shortcode call in .eleventy.js – this tells Eleventy to treat our new function as a shortcode and where to locate the function in our code. So – if we insert a phrase starting with {% youtube... %}, then any parameter passed in will be considered to be a YouTube ID, and Eleventy will use the shortcode to build the video.
For the last step, we switched to post2.md (which has now become our default “testbed”) and added a call to the new shortcode. We then compiled the code and previewed the results in our browser.
Perfect – this is an easy way to add in repeatable pieces of functionality such as videos. We could equally build something to insert images (such as those styled with the Polaroid effect – remember those?), or even components that we want to embed in our markup!
Okay – let’s crack on. Next up is something more complex for us to get stuck into adding an essential feature for any blog: tags. Adding them is something we will do over a two-part exercise, so let’s start with the back-end configuration changes.
Tagging Content
Over the years, I’ve visited hundreds of blog sites on all manner of different topics – mainly web development, but others might include food, travel, photography, and more.
One of the key elements you will see on any blog is, of course, the tag – we need these to help classify the subject type for each blog post to make it easier to find posts on a subject. Eleventy has excellent support for tags – this feature is based on the core concept of collections, which we covered earlier in the book. Let’s use this to build collections of tags for each post and display them on the page as part of the next exercise.
- 1.
First, go ahead and stop your Eleventy development server if it is running – switch to the Node.js terminal session, then hit Ctrl (or Cmd)+C to stop the server.
- 2.
Next, fire up your editor, then crack open your .eleventy.js file, and scroll down to this line:
- 3.
Miss a line, then add this code – we have a nice chunk to add, so we’ll do it section by section, starting with a filterTagList function:
- 4.
Next up, we need to add a filter call to this function – skip a line, then add this line of code:
- 5.
Add a blank line, then add in this code – this takes care of creating an Eleventy collection that contains all of the tags in each post:
- 6.
Save and close the files.
At this point, we’re done with the configuration changes – it’s time to switch to adding the new features! We have a few changes left to do, so when you’re ready, let’s crack on with the next one, which is in the post2.MD file.
- 1.
Go ahead and open post2.md, then scroll down a little to the front matter. Add in this entry before the closing ---:
As this is Markdown, it’s crucial to add the correct number of spaces for the indent (in this case, 2) – if we don’t set it properly, then Eleventy may fail to compile correctly.
- 2.
The following change we need to make is in the tags.njk component, which is at the root of our project folder. This component will create a list of all posts tagged with a specific term. Go ahead and open the placeholder file we created in an earlier exercise, then add this code, which we will do in two blocks, starting with replacing the front matter with this:
- 3.
This second part is the markup for our tag list – add this immediately below the code from the previous step:
- 4.
At this point, go ahead and save any files you have open, so we don’t lose our changes.
- 5.
Next, we need to add a Tags list component, which will display all of the tags at the foot of each post. Crack open tags-list.njk, then add in this code:
- 6.
Save and close the tags-list.njk file. Next, go ahead and open post.njk, then add this code under {{ content | safe }}:
- 7.
For the next change, we need to update auxpostslist.njk – go ahead and extract a copy of this file from the code download and save it to the partials folder under the _includes folder.
- 8.
We have one more change to make – crack open archive.njk in your editor, then update it to match this code:
- 9.
Save and close any file you have opened, then switch to a Node.js terminal session.
- 10.
We now need to recompile our code – at the prompt, enter npm run serve and hit Enter to recompile the code.
- 11.
Switch to your browser – go ahead and browse to http://localhost:8080. If all is well, we should see something akin to that shown in Figure 5-2 when clicking through to the “This is my second post” page:
- 12.
Try clicking on one of the tags shown previously (yes, it looks like one, but I promise you there are two in that last image!) – you should see something akin to the screenshot in Figure 5-3.
It’s worth noting that if you click on Archive in the navigation at the top, you will see something similar appear, but with all of the posts, not just the filtered ones.
Phew – that was certainly a lengthy exercise: we did have a lot to cover! It was nonetheless a useful exercise, as we implemented a series of changes to help create filtered views of posts on our site, making it easier to navigate for our readers. The changes we’ve made highlight some essential features in Eleventy, so let’s pause for a moment to review the code changes in more detail.
Exploring the Code Changes
In this last set of exercises, we started with adding a filterTagList function, which we use to return a list of all of the tags present in the site; it filters out those tagged with selected words, namely, all, nav, post, and posts, as we don’t want these to appear in the final list. We then added an addFilter method to trigger the building of this list.
Next up, we implemented an addCollection method to iterate through all posts and create an array of all of the (filtered) tags present, so we can display a list of posts filtered by tags when clicking on a specific tag on our site.
We have completed the back-end changes, so we moved on to updating the UI – as before, we used post2.md as our example to test that tagging works. We first added a tags: entry to this post before creating a tags component to display all posts with a specific tag.
For the remainder of the exercise, we created a tags-list component that iterates through tags in each post. It then creates a listing at the bottom of each post page. At the same time, we updated the main post template to call this method and display the tags. We also updated the Archive placeholder page created earlier – we added a call to auxpostslist.njk to show details about each post (such as date, title, and tags). We then finished by recompiling the code and previewing the results in our browser.
Right – what’s next? We’ve focused on adding several filters over the last few pages, but we have one more that adds a nice touch to the site. We have only created a handful of posts, but what if we had a lot? A helpful addition would be to tell the reader how many pages of posts we have on the site – we could use this as a basis for navigating through pages later. For now, let’s focus on setting up the initial count as part of our next exercise.
Counting Pages
Over the last few pages, we’ve created filters for various tasks – they all serve a purpose but are a little mundane! No problem, though, as we can change that: let’s add a page count for our blog index.
As mentioned, it’s a great way to tell people how many pages they have to navigate through; we’ll start with setting up that count as a point for developing further in the future.
- 1.
First, go ahead and open .eleventy.js, then scroll down to just below the last addFilter() method.
- 2.
Leave a line blank, then add this method:
- 3.
Save the file and close it. Next, crack open index.njk, and add this code below the function that starts with this line: {% for item in cms.allBooks %}
- 4.
Save the file and close it. We now need to recompile the code – switch to a Node.js terminal session, and set the working folder to our project area.
- 5.
At the prompt, enter npm run serve and hit Enter to recompile the code.
- 6.
Switch to your browser – go ahead and browse to http://localhost:8080. If all is well, we should see something akin to that shown in Figure 5-4, where we can see the number of pages of posts present on the site.
It’s a simple change but a great one for giving a visual cue to readers – particularly if you happen to be a a writer! This little trick relies on getting the size of the collection of posts on the site – let’s dive in and look at the code in more detail.
Exploring the Code in Detail
Setting up the page count in this exercise relies on a valuable feature of Eleventy – the collection object. To make it work, let’s first jump to step 3; here, we set a totalPage variable that calculates the number of pages divided by the number of posts per page.
We could end up in scenarios where the result is not a whole integer; to solve that, we created a pageCount filter that takes the pageSize value we pass in and extracts the integer part.
So, for example, if we had 16 posts, with 3 per page, we would end up with 5.1 for pageSize. The filter uses Math.floor to remove the .1, leaving 5 as a result. The critical check here is that we only return a value for the result if it is not equal to zero – after all, we don’t want to render something that says page X of 0 on screen! To ensure that we always return a page count, we add 1 to pageSize before formatting it as a whole integer value.
Once we have worked out the page count, we return the value on screen and format it as part of the message to our readers to know which page they are on and how many post pages are present on the site.
Okay – let’s move on: next up is the subject of events. I know, you’re probably thinking of typical events that customers might generate, such as onOpen, onClose, and so on, right? Well, Eleventy likes to be different, and events are no exception – let’s dive in and take a look.
Responding to Events
Events in Eleventy take on a different context than other frameworks – we usually associate events with responding to something that happens. Well, in Eleventy, we do that, but the key difference is that these events do not come from customers but ones we generate during the build process.
At first, this might not seem useful, but we can control what happens during that process with a bit of work. As an example, and one we will work through shortly, we can produce a list of all changed files – it’s perfect for confirming that a file we change has indeed been recompiled!
The events available in Eleventy
Name of event | Purpose |
---|---|
beforeBuild | Runs each time a build is started – either as part of a stand-alone build or as part of running –watch or –serve. |
afterBuild | Runs when the build is finished – either as a stand-alone or if –watch or –serve triggered the build. |
beforeWatch | This function runs only if a build is rerun using –watch or –serve, not for an initial build. |
The best way to see how to use these events is to put them to use in a demo. With that in mind, let’s update our demo to see how we can trigger each, during the build process.
- 1.
First, go ahead and stop the Eleventy development server if it is running; to do this, switch to the Node.js terminal session that has the server running and hit Ctrl (or Cmd)+C to stop it.
- 2.
Next, open .eleventy.js in your editor and scroll down to this line:
- 3.
Leave a line blank, then add in these methods:
- 4.
Save the file and close it. Switch to the Node.js terminal (or fire up one if you don’t have one open), then make sure the working folder is our project area.
- 5.
At the prompt, enter npm run serve and press Enter.
- 6.
In previous exercises, we would browse to the site in a browser. Instead, take a look at the contents of Node displays in the terminal session. It should resemble something like the following output, where we highlight the new messages in bold:
- 7.
Go and change a file – it doesn’t matter which; you can add a space in the .eleventy.js file, which will be sufficient.
- 8.
Eleventy will automatically recompile – if all is well, you should see lines similar to this in the output:
This update might be a simple change, but one that is useful to implement. We can check that changed files have indeed been recompiled during the build process. We’ve covered some valuable points in this demo, so let’s review the changes we made in this last exercise before moving on to the next demo.
Understanding What Happened
So – what did we change? In this demo, we kicked off by adding a new beforeBuild function into the .eleventy.js file, which we use to advise when we start the build process.
We then moved on to the afterBuild function; this performs a similar role, but this time kicks in after the build process has completed. We also added an extra function to show which files were changed; we use the changedFiles parameter passed into the beforeWatch function, which exposes those files we change in the latest build.
It’s important to note, though, that beforeWatch does not kick in on the initial build – it will only show any changes when we rerun the build process, not on the initial run.
Okay – let’s crack on: for our next topic, we will change tack and explore an important change to help with styling our site. Styling isn’t something we will cover until Chapter 6, but this part involves changing how we watch for… well, changes!
That was probably a little confusing, so to see what I mean, let’s dive into the world of configuring the scripts part of our package.json file and how this can help with watching for updates to our site.
Watching the Changes
If you’ve spent any time with frameworks such as React, then you may have used the watch facility that comes with the framework – after all, who wants to spend time refreshing the screen, when we can get the framework or browser to do it for us!
Eleventy is no different – it comes with its in-built watcher, ready to recompile when we make a change. In many cases, this works seamlessly in the background, often with little or no need to change the default setup.
However, this means we could be missing out on a significant opportunity – what about processing styles, for example? In this case, we can leave Eleventy to compile our markup as usual but add in a step to compile styles created using tools such as Sass and PostCSS. Let’s add support for compiling styles created using the Sass processor into our demo to see what I mean.
- 1.
First, we need to stop the Eleventy server if it is already running to ensure the changes we make take effect. Switch to the Node.js terminal that has the server running, then hit Ctrl (or Cmd)+C to stop the server.
- 2.
At the prompt, enter this command and press Enter – this will install two packages required to run Sass in our environment:
- 3.
Once done, switch to your editor – go ahead and crack open your package.json file. Scroll down to the scripts block, and replace it with this:
- 4.
Save the file and close it. Switch to the .eleventy.js file, and scroll down to the line starting with this: eleventyConfig.setBrowserConfig(...). Go ahead and add these two methods in just before it – leave a line blank after the second and before the setBrowserConfig call, as shown:
- 5.
Save and close the file. Next, create a new folder called styles at the root of our project, then add a new folder inside it called sass.
- 6.
Crack open a new file, then add in these styles, saving it as layout.scss in the stylessass folder:
- 7.
Save the file and close it. Switch to the Node.js terminal (or fire up one if you don’t have one open), then make sure the working folder is our project area.
- 8.
At the prompt, enter npm run build and press Enter.
- 9.
We can now preview the results of our work – this time, crack open your file manager. Navigate to the _site folder within our project area: if all is well, we should see a new css folder appear in the styles folder, as shown in Figure 5-5.
It’s important to note that this won’t show any styles on our site – that will come in Chapter 6, when we revisit this as part of styling the blog. Oh – and yes, it won’t contain the styles we’ve used here: it will look a little more decent!
Perfect – we now have the means to compile styles, should we be a fan of using tools such as Sass, Less, or PostCSS! This is one of those exercises where we’re not looking to make direct changes to the UI but make it easier to integrate tools such as Sass into our workflow. We’ve covered some critical points in this demo, so with that in mind, let’s take a moment to explore what we set up in more detail.
Understanding What Happened
While we ran through that last exercise, you may have noticed something – we set up a means to compile styles but created something that doesn’t bear any relationship to the markup we’ve already created! There is a good reason for this, so let me explain.
To create this exercise, we explored something we won’t technically cover until the next chapter, which is styling our site. However, to prove things work as expected, we need to create a couple of styles – don’t worry, we will remove them when we start to style our site for real!
Leaving that mini test aside, let’s take a closer look at the technical setup.
We kicked off by first stopping the Eleventy development server – while this isn’t always necessary, it’s a good habit to ensure that we compile the latest changes and do not use content from the cache.
We then installed the npm-run-all package from NPM – this we use to compile both the code and watch for changes simultaneously. We updated the scripts block in package.json to add new commands to trigger both the compilation and watch processes when required.
Next up came a critical change – when compiling Eleventy markup, we don’t want Eleventy to touch the styles, either in the Sass source file or the compiled version. To do this, we add two commands: addWatchTarget(...) to tell Eleventy to trigger the Sass compilation process and .addPassthroughCopy() to push the compiled CSS file into the destination folder without modifying it.
We then rounded out the exercise by creating a test Sass file with some dummy styles before compiling both the site and Sass commands and previewing the result in a browser.
A Small Thought
Before moving on to the last part of this chapter, we should cover one more point: Do we need a task runner such as Gulp or Grunt?
It’s an essential consideration for instances like the last exercise, where we might typically have used such a task runner to compile our code. However, some may argue that this isn’t necessary; a lot of it will depend on your requirements and the packages you may need to run. In our case, we ran npm-run-all, but this is not an essential part of Sass; its use is purely to allow the running of multiple packages simultaneously. Just something for us to consider!
Okay – let’s move on: Eleventy supports a package called BrowserSync, which helps cut down (or remove) repetitive manual tasks. When building an Eleventy site, we can use a default setup – there should be little need to change it. However, there are two changes we can make, one of which favors those of you who use the VS Code editor – let’s take a look at them in more detail.
Overriding BrowserSync
I don’t know about you, but I will take any opportunity to automate a menial task – life is too short to spend doing manual jobs, particularly if they have little value!
I suspect this is one of the reasons why the developers included this next facility in Eleventy – BrowserSync. This tool has a host of options available, which we can see on the BrowserSync website at https://browsersync.io/docs/options; in our case, we used it to override the default settings and allow it to render a custom 404 page.
We’re going to make one more change, though, to help with reducing those manual tasks and get it to open the browser automatically as soon as we compile the content. As I said before – it’s one less thing we need to do, and it will quickly add up! With that in mind, let’s look at how to update the configuration to support this change.
- 1.
First, we need to stop the Eleventy server if it is already running to ensure the changes we make take effect. Switch to the Node.js terminal that has the server running, then hit Ctrl (or Cmd)+C to stop the server.
- 2.
Next, go ahead and open .eleventy.js from the root of your project folder. Scroll down until the closing }) and then enter open: true before it, as indicated:
- 3.
Save the file and close it. Switch to the Node.js terminal (or fire up one if you don’t have one open), then make sure the working folder is our project area.
- 4.
At the prompt, enter npm run watch:eleventy and press Enter.
- 5.
Eleventy will recompile the code as usual, but this time will automatically fire up your browser and display our site under the by-now-familiar localhost URL.
It’s a quick and dirty change, but a useful one – just think of the number of times you’ve had to fire up a browser or refreshed a session. Eleventy can do all of that for you – it may be one of many options supported in the framework, but certainly (at least for me), one of the most valuable options to consider when using Eleventy.
Okay – let’s move on: we’ve touched on how BrowserSync can open the browser automatically on compilation; what if we could take it a step further and get our editor to do both compiling and opening for us?
Launching a Script Automatically
Okay – I must admit that the last question might sound a bit odd, given that we are technically already doing both from within the editor. But – and here’s the rub: we have to do it manually by entering a command. What if we could get the editor to do it as a point and click instead?
The trick here lies in using a feature found in many editors, either built-in or which comes as a separate plugin. I use VS Code, a reasonably popular editor; I’m sure the same feature will be available in editors like Sublime Text and Atom.
In VS Code, we have a Run Task feature that we can use to automate the compiling and launching in one go – I know that some of you may prefer to use the command line, and that is perfectly fine. For those who want a more visual “click and go” approach, this next exercise will be perfect for you!
It’s important to note that this is not obligatory for running either process in Eleventy; Eleventy will run fine without this automation.
- 1.
First, we need to stop the Eleventy server if it is already running to ensure the changes we make take effect. Switch to the Node.js terminal that has the server running, then hit Ctrl (or Cmd)+C to stop the server.
- 2.
Go ahead and create a new folder called .vscode – inside it, crack open a new file and add this code:
- 3.
Save the file as task.json.
- 4.
Next, we need to add an exclusion to the .gitignore file so this doesn’t get pushed up to Git. For this, open .gitignore, and add the following highlighted code:
- 5.
Save and close both files.
- 6.
Next, click on Terminal ➤ Run Task ➤ Show All Tasks in your editor.
- 7.
Click on npm: eleventy:watch.
- 8.
If all is well, you will see the task run in your browser console, and the site automatically loads in your browser.
Although I know this last exercise was targeted at those using Visual Code, I am sure there will be other options available for other editors. It shows that there is benefit in having a look to see if we can automate tasks such as this from within your browser. There are two key reasons to do so – it saves time and resources, and… well, why do something when you can get your PC to do it for you?
That said, it’s worth looking at how we implemented this change in more detail – it might only be a relatively small change, but it will save you time in the long run!
Breaking Apart the Code
To implement a new task in VS Code for this exercise, we made two fundamental changes: a new configuration file called task.json. We specified a few settings inside this file, such as runOptions (to open the project folder) and script to determine which script to trigger on launching the task.
Next, we had to update the .gitignore file to prevent pushing up task.json to a public repository; this file should remain on the local PC. We then tested the task by running the Run Task option before watching compile the code and show the results in our browser.
If you would like to learn more about creating tasks for VS Code, then head over to the documentation on the Visual Studio Code website at https://code.visualstudio.com/docs/editor/tasks.
Summary
Over the years, I’ve come across or worked with various frameworks to differing levels – some are complex (React), while others (such as Eleventy) are significantly easier to use!
One of the things I love about Eleventy is the balance of simplicity against customizability – the framework can be extensively customized, but at the same time, remain relatively simple to use. This chapter covered several tools and techniques we can use to customize Eleventy – we might have only scratched the surface, but that doesn’t matter! The tools we’ve used still perform a valid role; let’s take a moment to review what we have learned in this chapter.
We started with a quick look at some of the tools we can use, such as shortcodes, filters, and tags – we explored their purpose and noted that the first two could work similarly so it can be hard to choose which we should use.
We then moved on to creating some shortcodes and filters for our site, such as adding a YouTube video (shortcode) or displaying a “Page X of Y” message to our readers (filter).
Next up came a quick look at the world of tagging – this works in the same way as other blogging platforms. We explored the changes required to implement tags for each post and tag lists for the index and archive pages.
We then switched gears to explore some of the back-end options – first up, we examined some of the events we can use to monitor compilation. We then explored how to modify the watch process to perform additional tasks such as compiling preprocessed CSS styles before diving into overriding the settings in the BrowserSync tool supported in Eleventy.
Phew – a real whistle-stop tour, but hopefully a useful one! We still have plenty more to cover – our next task will be more enjoyable. We’ve put together the basics of our site, along with some example content, but I’m sure you’ll agree that it looks very plain. It’s time to sort that out – let’s get to styling our site, which we will do in the next chapter.