From 341014a47e8eff11c1215449420aa0a44acd8a4f Mon Sep 17 00:00:00 2001 From: Garrett Mills Date: Sun, 1 Mar 2026 15:39:03 -0600 Subject: [PATCH] Readme + Eleventy blog post and note --- README.md | 9 + src/blog/posts/2026-03-01-eleventy.md | 180 ++++++++++++++++++ .../posts/2026-03-01-migrating-to-eleventy.md | 14 ++ 3 files changed, 203 insertions(+) create mode 100644 README.md create mode 100644 src/blog/posts/2026-03-01-eleventy.md create mode 100644 src/feed/posts/2026-03-01-migrating-to-eleventy.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..07e3db9 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# `garrettmills.dev` + +This is my website, hosted at https://garrettmills.dev. + +It is implemented using the excellent [Eleventy](https://www.11ty.dev/) SSG. + +![](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png) + +This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/). diff --git a/src/blog/posts/2026-03-01-eleventy.md b/src/blog/posts/2026-03-01-eleventy.md new file mode 100644 index 0000000..4f19f11 --- /dev/null +++ b/src/blog/posts/2026-03-01-eleventy.md @@ -0,0 +1,180 @@ +--- +layout: blog_post +tags: blog +title: Migrating to the Eleventy (11ty) Static-Site Generator +permalink: /blog/2026/03/01/Migrating-to-Eleventy-SSG/ +slug: Migrating-to-Eleventy-SSG +date: 2026-03-01 20:48:06 +templateEngineOverride: md +blogtags: +- hosting +- meta +- webdev +--- + +![](https://static.garrettmills.dev/assets/blog-images/ssg/ssg-pagespeed.png) + +For the last [4 years](https://code.garrettmills.dev/garrettmills/www/commit/0c0171234163ae7559a92d93802b76fca9ec65d8), my website has been run as a monolithic MVC web app built using my homegrown Typescript framework. This allowed me to do some cool server-side stuff like an admin-portal where I could add snippets and tiny URLs without a code change. But, it also introduced the complexity of having to run a database and app server with a build+deploy pipeline. + +Around a year ago, I started trying to optimize my site for speed. For all the flexibility the backend server provided, it meant that serving what was essentially a static site with some HTML/CSS/JS and images had to run though an entire interactive web app framework, introducing hundreds of milliseconds of latency. + +At the time, I read [Ethan Marcotte's post](https://ethanmarcotte.com/wrote/eleventy/) about the [Eleventy](https://www.11ty.dev/) static-site generator (SSG) and started playing around with porting this website over to it. As of March 1, 2026, this site has now been fully migrated over to Eleventy. This post documents the parts I found interesting. + +### Template Language Mix-and-Match + +All the [templates for this site](https://code.garrettmills.dev/garrettmills/www/src/branch/master/src/app/resources/views/welcome.pug) were originally written in [Pug](https://pugjs.org/api/getting-started.html), my HTML templating language of choice. I really like Pug and wasn't interested in switching to a different language. Eleventy natively supports/prefers Nunjucks as its template engine, but has a first-party plugin adding support for Pug. This meant I was able to directly copy over all my existing templates with very minimal changes. + +One of Eleventy's biggest strengths is that it allows you to basically mix-and-match template/content formats on the fly. One page could be written in Pug, another in Nunjucks, and another in plain Markdown, and they can all use any of your configured layout templates. This means I can write my theme templates in Pug, but author the actual [day-to-day content](https://code.garrettmills.dev/garrettmills/www-ssg/src/branch/master/src/blog/posts) in Markdown, my preference. + +The [`Render` plugin](https://www.11ty.dev/docs/plugins/render/) makes this even better. Using the `renderFile` directive, you can have Eleventy fully render a piece of content (for example, a Markdown file) and embed its contents as HTML within a different template. For example, here's the template for the [Feeds page](/blog/feeds) on this blog: + +```html +--- +layout: blog +--- + +{% renderFile "src/blog/feeds-stub.md" %} + +

Garrett's RSS List

+ +
+This list is also available in the standard OPML format. +
+ +{% for cat in collections.opmlByCategory %} +

{{ cat.title }}

+ +{% endfor %} +``` + +I was able to embed my RSS Manifesto (written in Markdown) in a template written in Nunjucks, rather than having to rewrite the manifesto natively in HTML. + +> Unfortunately, the Render plugin is only supported by the 3 built-in template engines, so I wasn't able to use it in a Pug template. Maybe a future PR when I have a rainy day... + +It feels like being able to author content in one preferred format, then compose it together to form a website with rich layouts / tagging / collection features has unlocked a whole new understanding in my brain for what can be done "at compile-time" for the website, rather than needing a backend. + +### Feeds + +Part of the transition meant porting over my existing RSS, Atom, and JSON feeds. Eleventy has a first-party [RSS plugin](https://www.11ty.dev/docs/plugins/rss/) that can automatically generate RSS and Atom feeds for your collections. + +However, I had an additional goal of wanting to match the format of my old feed files as exactly as possible, primarily so that any existing RSS clients wouldn't re-mark my entire feed as "unread" after the change. + +Luckily, since Nunjucks isn't specifically an _HTML_ template engine, but rather a _general purpose_ template engine, it was pretty easy to roll my own feeds matching the existing format exactly: + +```xml +--- +permalink: /blog/atom.xml +eleventyExcludeFromCollections: true +metadata: + title: "Garrett's Blog" + description: "Write-ups and musings by Garrett Mills, often technical, sometimes not." + language: en + base: "https://garrettmills.dev" + author: + name: "Garrett Mills" + email: "shout@garrettmills.dev" +--- + + + + {{ metadata.base }}/#about + {{ metadata.title }} + {{ collections.blog | getNewestCollectionItemDate | dateToRfc3339 }} + + {{ metadata.author.name }} + {{ metadata.author.email }} + {{ metadata.base }}/#about + + + + {{ metadata.description }} + {{ metadata.base }}/assets/favicon/apple-touch-icon.png + {{ metadata.base }}/assets/favicon/favicon.ico + Copyright (c) 2026 Garrett Mills. See website for licensing details. + + + {%- for post in collections.blog %} + {%- set absolutePostUrl = post.url | htmlBaseUrl(metadata.base) %} + + <![CDATA[{{ post.data.title }}]]> + {{ absolutePostUrl }} + + {{ post.date | dateToRfc3339 }} + + {{ metadata.author.name }} + {{ metadata.author.email }} + {{ metadata.base }}/#about + + {{ post.content | renderTransforms(post.data.page, metadata.base) }} + + {%- endfor %} + +``` + +### Custom Collections + +Out of the box, Eleventy will group your content into "collections" based on tags in the front-matter. Tagging a file with the "blogpost" tag will add it to the "blogpost" collection along with all other files using that tag. + +Collections are made available in template files, so you can -- for example -- loop over them to link the most recent 10, or group them by year and get a count, etc: + +```pug +extends /blog + +block blog_content + p Write-ups and musings, often technical, sometimes not. + + h2 Recent(ish) Posts + + .recent-posts + ul.plain + each post in collections.blog.reverse().slice(0, 10) + li + a.title(href=post.url) #{post.data.title} +``` + +One cool feature of Eleventy is the ability to add your own custom collections using Javascript when the site is generated. These collections are available to use in templates like everything else. + +This unlocks a host of possibilities. I used it, e.g., to automatically parse my RSS OPML file and make a collection of my RSS subscriptions: + +```javascript +eleventyConfig.addCollection("opmlByCategory", async api => { + const xml = fs.readFileSync("./src/assets/rss_opml.xml") + const parsed = await new Promise((res, rej) => { + opml.parse(xml, (err, doc) => err ? rej(err) : res(doc)) + }) + + return parsed.opml.body.subs +}) +``` + +This collection is what powers my RSS list on the [feeds page](/blog/feeds#garretts-rss-list). + +### Deployment & Performance + +Since this is now a fully-static site, my Dockerfile is a glorious 3 lines: + +```dockerfile +FROM nginx +COPY _site /usr/share/nginx/html +COPY nginx /etc/nginx/conf.d +``` + +I did make a few [Nginx optimizations](https://code.garrettmills.dev/garrettmills/www-ssg/src/branch/master/nginx/default.conf), but the end result is that this site is _fast_. Loading the homepage for my blog takes around 250ms before any of the assets are cached: + +![](https://static.garrettmills.dev/assets/blog-images/ssg/ssg-latency.png) + +### Future Work + +All in all, I'm very happy with how the migration turned out, and with the performance post-static-ification. + +In no particular order, here's a list of things I still want to figure out, some of which will require an API-backend of some persuasion: + +1. Find some kind of self-hosted privacy-respecting comment server and integrate it into the blog and notes pages. +2. Implement support for WebMentions. Some [cool people I follow](https://shkspr.mobi/blog/2024/03/caboom-comment-anywhere-bring-onto-own-media/) support WebMentions on their blogs, and I love the POSSE approach to web presence. +3. I'd like some kind of really basic analytics -- even just a "number of unique views per page" is sufficient, which I might try to set up via Nginx access logs. This is one piece of feedback I didn't have a direct replacement ready for. + +You can find the source code for this website, as well as information on licensing and reuse on the [Technical page](/technical/#source-code-and-licensing). diff --git a/src/feed/posts/2026-03-01-migrating-to-eleventy.md b/src/feed/posts/2026-03-01-migrating-to-eleventy.md new file mode 100644 index 0000000..3def0ce --- /dev/null +++ b/src/feed/posts/2026-03-01-migrating-to-eleventy.md @@ -0,0 +1,14 @@ +--- +layout: feed_post +title: "Migrating to Eleventy SSG" +slug: fc3ced28-18db-43ae-8883-ad823c7af655 +date: 2026-03-01 11:00:00 +tags: feed +permalink: /feed/2026-03-01-migrating-to-eleventy/ +feedtags: + - Site Update +--- + +I've reached a milestone in my months-long project to convert this website over to the Eleventy static-site generator: the new site is now live! Hopefully you didn't notice. ;) + +You're reading this via the new static site. I wrote up some notes on the parts of the process I found interesting, which you can read about [here](/blog/2026/03/01/Migrating-to-Eleventy-SSG/).