feb 19, 2023
🔗 Setup a blog with Eleventy 2.0, Tailwind and Alpine.js
Hello world! My current job is front-end developer and I wanted to have a new home for my own ideas and tinkering.
This didn't took place on a whim of a boring sunday afternoon, but took a few weeks, and it started with looking into very nice Next.js starter templates. They looked amazing but I still decided to trying to develop it with the absolute minimum setup.
As Eleventy just released the new 2.0 version, it's the perfect occasion to test this new software. It is a highly-praised static-site generator and this new version comes with even better DX experience. It only takes forking their official starter template from their website, 11ty/eleventy-base-blog to get started building.
The starting point
# Installing Tailwind and Alpine.js
One great thing of doing front-end dev today is using libraries like Tailwind and Alpine.js because they allow for speedy development and iteration, letting you focus on the blog content. This is the stack this blog will use, you just need to install them with npm to get started.
npm install tailwindcss alpinejs --save-dev
I created index.css
and index.js
files in the src
folder and added the following to the index.js
file:
import Alpine from "alpinejs";
Alpine.start();
And as the usual Tailwind setup, I created a tailwind.config.js
file and a postcss.config.js
file in the root of my project.
// tailwind.config.js
module.exports = {
content: ["./_includes/**/*.njk"],
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
The content
property is used by Tailwind to know which files to scan for tailwind classes, in my case I am using Nunjucks templates, so I added the path to my njk
files.
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
and then I added to my index.css
file the following:
@tailwind base;
@tailwind components;
@tailwind utilities;
# Eleventy and its new features
Eleventy 2.0 comes with a lot of new features, from reading their official announcement, they worked hard to improve performances: dependencies are smaller, build times are faster, and the DX is better.
One improvement in this new version is that some really useful plugins are included out-of-the-box or are very easy to install. I am using the following plugins:
- eleventy-plugin-rss to generate an RSS feed
⚠️ Warning:
The Rss plugin only works with the Nunjucks template engine.
- eleventy-plugin-syntaxhighlight to add syntax highlighting to code blocks
- eleventy-img to perform build-time image transformations, it can output multiple sizes, in multiple formats, cache remote images locally
- eleventy-navigation to easily generate navigation menus
- eleventy-plugin-bundle, it lets you create small bundles where you need them, even on a per-page basis, more on this later
- eleventy-plugin-vite which lets you use Vite to bundle your assets
This sounds like a lot, but once they are installed and configured, they are really easy to use and it's difficult to bump into any issues.
It was nice to to use the eleventy-plugin-bundle
plugin to create small bundles only where it made sense.
For example, since only the blog posts rely on markdown, I needed the css that styles the content only in my post template, to do so I added the following to my post.njk
file:
{% css %}
{% include "src/css/markdown.css" %}
{% include "src/css/prism-one-dark.css" %}
{%- endcss %}
Which will be loaded inline only in the posts pages for better performance. In the <head>
of my base.njk
template file I have this:
{%- css %}
{% include "src/css/index.css" %}
{% include "src/css/utility.css" %}
{% endcss %}
<style>{% getBundle "css" %}</style>
You can also do the same to load javascript files, and use the getBundle
tag to inline the script files, but for this specific use case I noticed that the loading was smoother by using the other plugin feature, which loads the scripts in a single file.
At the beginning of this project I was trying to set a specific --pathprefix
option but I got some issue with the inlined javascript so I ended up doing this instead:
{%- js %}
{% include "public/js/index.js" %}
{% include "public/js/gradient.js" %}
{% endjs %}
<script type="module" src="{% getBundleFileUrl "js" %}"></script>
Anyways those are quite small performance optimizations. I will write next a post about the choices I made to ensure this blog is fast to modify and maintain.