feat: 💬 update blog post

Update post with instructions for Tailwind v4, update footnotes syntax to current style, fix spelling errors
This commit is contained in:
Sebin Nyshkim 2025-02-17 02:30:58 +01:00
parent 9f26f6dc6c
commit 6897a3050c

View file

@ -1,9 +1,19 @@
---
title: Building a Blog with Eleventy (blind, any%)
description: I recently felt like getting back into blogging. But setting up and maintaining WordPress felt like more than I was looking for. I was looking for something much simpler. Preferably file-based and with Markdown support. That was my introduction to Eleventy.
image:
src: https://cdn.sebin-nyshkim.net/-QMvyHZfXru
alt: Close-up of SVG code on a computer screen
credit: Photo by Paico Oficial on Unsplash
width: 1200
height: 630
type: 'image/png'
tags: ["coding", "eleventy"]
---
> [!info] Update 2025-02-17
> Updated Tailwind instructions for Tailwind v4
{{ description }}
Starting an Eleventy project is fairly straight-forward if you've ever worked with any Node.js package:
@ -143,9 +153,9 @@ This applies the `blogpost.njk` layout to every file. But we can take this even
}
```
The `date` tells Eleventy how to resolve the date associated with a blog post, in this instance the date of when the file was created[^1]. The `permalink` variable allows me control where a post will be saved to, with the `slugify` filter taking the value of the `title` variable and making it URL friendly. And as you can see, you can add anything you want.
The `date` tells Eleventy how to resolve the date associated with a blog post, in this instance the date of when the file was created[^eleventydates]. The `permalink` variable allows me control where a post will be saved to, with the `slugify` filter taking the value of the `title` variable and making it URL friendly. And as you can see, you can add anything you want.
[^1]: Specifically, the file system creation date. This can get a little tricky if you care about the accuracy of the post date, because if you were to create an empty file in the `posts` directory, Eleventy will take the exact date the file was written to disk, not the date the post was *actually published* to the site. You could get around that with `git Created` to instruct Eleventy to take the date the file was pushed to the Git repo instead, but this has [caveats](https://www.11ty.dev/docs/dates/).
[^eleventydates]: Specifically, the file system creation date. This can get a little tricky if you care about the accuracy of the post date, because if you were to create an empty file in the `posts` directory, Eleventy will take the exact date the file was written to disk, not the date the post was *actually published* to the site. You could get around that with `git Created` to instruct Eleventy to take the date the file was pushed to the Git repo instead, but this has [caveats](https://www.11ty.dev/docs/dates/).
## Data cascade
@ -191,9 +201,9 @@ Eleventy does not process CSS files, however, so we need to tell it to do someth
Up until this point a config was entirely optional, but since we're bound to do something more mildly complex with Eleventy down the line, we might as well just add it.
Eleventy's config file is named `eleventy.config.js` and the format should be immediately familiar to anybody having worked with Webpack, Vite, NextJS and the like[^2]:
Eleventy's config file is named `eleventy.config.js` and the format should be immediately familiar to anybody having worked with Webpack, Vite, NextJS and the like[^eleventyconfig]:
[^2]: Eleventy supports both CommonJS and ESM syntax. I'm using ESM syntax because it's widely adopted in the Node.js development world and is supported by Eleventy since v3 (which just so happens to have released shortly before I started this blog, fancy that)
[^eleventyconfig]: Eleventy supports both CommonJS and ESM syntax. I'm using ESM syntax because it's widely adopted in the Node.js development world and is supported by Eleventy since v3 (which just so happens to have released shortly before I started this blog, fancy that)
```js
export default async function(eleventyConfig) {
@ -273,9 +283,9 @@ export default async function (eleventyConfig) {
};
```
With this, I can now do things like {% raw %}`{{ date | readableDate }}`{% endraw %} to format a JavaScript date object instance as a nicely readable string. These are also chainable, so doing something like {% raw %}`{{ '2024-10-13' | toDateObj | readableDate }}`{% endraw %} gives me *Oct 13, 2024* from a date string the `Date()` constructor accepts[^3].
With this, I can now do things like {% raw %}`{{ date | readableDate }}`{% endraw %} to format a JavaScript date object instance as a nicely readable string. These are also chainable, so doing something like {% raw %}`{{ '2024-10-13' | toDateObj | readableDate }}`{% endraw %} gives me *Oct 13, 2024* from a date string the `Date()` constructor accepts[^jsdateobject].
[^3]: The core JavaScript `Date` object is perfectly capable of formatting date and time strings. A library such as `luxon`, like it's mentioned in the Eleventy docs, is better suited when needing to do more complex things with dates like calculating durations and intervals, e.g. I wanted the post date to say something like "3 days ago" or something.
[^jsdateobject]: The core JavaScript `Date` object is perfectly capable of formatting date and time strings. A library such as `luxon`, like it's mentioned in the Eleventy docs, is better suited when needing to do more complex things with dates like calculating durations and intervals, e.g. I wanted the post date to say something like "3 days ago" or something.
### Adding collections
@ -289,9 +299,9 @@ export default async function (eleventyConfig) {
};
```
Adding collections via the config also has other benefits like being able to pre-filter and sort them. That way they're already the way they need to be at the time of consumption in templates and layouts[^4].
Adding collections via the config also has other benefits like being able to pre-filter and sort them. That way they're already the way they need to be at the time of consumption in templates and layouts[^jsarraymutate].
[^4]: In fact, the [docs](https://www.11ty.dev/docs/collections/#do-not-use-array-reverse()) sepcifically tell you to avoid callling array methods on collections that mutate arrays *in place* which can have undesireable side-effects and cause you a lot of headaches. So, yeah, don't do that!
[^jsarraymutate]: In fact, the [docs](https://www.11ty.dev/docs/collections/#do-not-use-array-reverse()) specifically tell you to avoid calling array methods on collections that mutate arrays *in place* which can have undesirable side-effects and cause you a lot of headaches. So, yeah, don't do that!
## Turning it up to 11ty
@ -550,7 +560,7 @@ We can take this even further: If the visitor is viewing the first page in the p
{% endif %}{% endraw %}
```
This might seem a bit excessive, but the aditional if-statements allow for some clear visual cues for when a visitor has reached the beginning/end of the list and prevents clicking on navigation elements that shouldn't be clickable.
This might seem a bit excessive, but the additional if-statements allow for some clear visual cues for when a visitor has reached the beginning/end of the list and prevents clicking on navigation elements that shouldn't be clickable.
### Extending bundled libraries
@ -586,35 +596,27 @@ The `mdLib` parameter makes the library interface of the chosen file type (`'md'
### Adding Tailwind
Tailwind is a popular CSS framework that gets you quick results very easily without ever writing a single line of CSS yourself. I've been using it since this year and after some initial learning curve I've gotten some good use out of it[^5].
Tailwind is a popular CSS framework that gets you quick results very easily without ever writing a single line of CSS yourself. I've been using it since this year and after some initial learning curve I've gotten some good use out of it[^sebinontailwind].
[^5]: I've gone [on record](https://meow.social/@SebinNyshkim/111771456618970816) in the past that I'm not particularly fond of the "CSS class barf" that Tailwind makes you write in your markup. I still think it looks awful, but the design clearly targets re-usable components written in frameworks like React and Vue, and the speed at which it allows you to get good looking results is undeniable.
[^sebinontailwind]: I've gone [on record](https://meow.social/@SebinNyshkim/111771456618970816) in the past that I'm not particularly fond of the "CSS class barf" that Tailwind makes you write in your markup. I still think it looks awful, but the design clearly targets re-usable components written in frameworks like React and Vue, and the speed at which it allows you to get good looking results is undeniable.
Adding Tailwind to an Eleventy project is pretty straight-forward:
```bash
npm install tailwindcss
npx tailwindcss init
npm install tailwindcss @tailwindcss/cli
```
With the default `tailwind.config.js` added to the project, I just have to tell it which files to monitor in the `content` array:
Starting with v4, integrating Tailwind is as easy as creating a CSS file and adding a single line to it:
```js
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{html,md,njk,ejs,pug}'],
theme: {
extend: {}
},
plugins: []
};
```css
@import "tailwindcss";
```
In order for Tailwind and Eleventy to run next to each other the entries in the `script` section of `package.json` need to be adjusted a bit:
```json
"scripts": {
"start": "eleventy --serve & npx tailwindcss -i ./src/css/style.css -o ./public/css/style.css --watch",
"start": "eleventy --serve & npx @tailwindcss/cli -i ./src/css/style.css -o ./public/css/style.css --watch",
"build": "ELEVENTY_PRODUCTION=true eleventy && NODE_ENV=production npx tailwindcss -i ./src/css/style.css -o ./public/css/style.css --minify"
}
```
@ -627,9 +629,20 @@ There's just one problem: I can't add Tailwind classes to my Markdown files!
Not to worry, though! Tailwind offers a 1st party typography plugin that is specifically made for this use case.
After a quick install and adding it to the `tailwind.config.js`, there's now a whole new set of utility classes available.
It's a quick install with `npm`:
For the most basic use, just adding the `prose` CSS class to the blog post layout does the trick:
```bash
npm install @tailwindcss/typography
```
And just one additional line of CSS:
```css
@import "tailwindcss";
@plugin '@tailwindcss/typography';
```
Now there's a whole set of new utility classes available. Tailwind Typography comes with sensible default styles for prose content. Just adding the `prose` CSS class to the blog post layout is enough:
```twig
<article class="prose">
@ -637,7 +650,7 @@ For the most basic use, just adding the `prose` CSS class to the blog post layou
</article>
```
Yes, that's really all there is to it! Tailwind Typography makes heavy use of the CSS [`:where()` pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) for styling decendents of the element with the `prose` class. If something in the styling of decendants is not to my liking, Tailwind Typography comes with its own set of modifiers to adjust the formatting of the most common content tags (`<h1>` - `<h6>`, `<p>`, `<a>`, `<strong>`, `<em>`, `<ul>`, `<ol>`, `<li>`, `<img>`, `<table>`, `<tr>`, `<th>`, `<td>`, and so on). And if something should absolutely not be formatted like prose the `not-prose` class prevents that.
Yes, that's really all there is to it! Tailwind Typography makes heavy use of the CSS [`:where()` pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) for styling descendants of the element with the `prose` class. If something in the styling of descendants is not to my liking, Tailwind Typography comes with its own set of modifiers to adjust the formatting of the most common content tags (`<h1>` - `<h6>`, `<p>`, `<a>`, `<strong>`, `<em>`, `<ul>`, `<ol>`, `<li>`, `<img>`, `<table>`, `<tr>`, `<th>`, `<td>`, `<blockquote>`, and so on). And if something should absolutely not be formatted like prose the `not-prose` class prevents that.
See the Tailwind Typography [GitHub](https://github.com/tailwindlabs/tailwindcss-typography#basic-usage) page for a primer on how to get the most out of it.