{"slug": "build-a-blogroll-with-eleventy", "title": "Build a Blogroll with Eleventy", "summary": "The article describes how the author built a blogroll for their Eleventy-based website, featuring each blog's favicon and latest post. They chose to schedule daily site rebuilds to keep the \"latest posts\" section reasonably up-to-date, prioritizing performance and simplicity over real-time accuracy. The blog data is stored in a JSON directory data file, allowing the Eleventy template to access and display the list of blogs.", "body_md": "Recently, inspired in part by a conversation Claudia Snell was having with folks in the Frontend Horse Discord server, I set up my blogroll, a list of some blogs I read regularly that I would recommend folks check out.\nAt its heart, all a blogroll needs to be is a static list of links to other blogs. No further complexity is required beyond that point. You could absolutely hardcode such a thing directly in HTML. However, I wanted to try my hand at a more complicated design, featuring each site’s favicon and a link to their latest post.\nWhat follows is how I built the finished product. My site is built with Eleventy, so this approach will definitely be Eleventy-flavored, but I’m sure bits and pieces of this approach could be adapted to any build tool or framework.\nEnsuring the Latest Posts Stay Somewhat Up to Date\nEventually, we’ll be fetching RSS feeds and displaying each blog’s latest posts, but well before that point, we’ll need an approach to ensure those posts stay roughly up to date.\nWe have a few possible approaches we could take to ensure we’re showing the latest, greatest, up-to-datest posts:\n- Do nothing special; let each rebuild update the posts. If you rebuild your site frequently, this will work well enough. If your site rebuilds less frequently, the “latest” posts will remain very stale for a long time.\n- Schedule regular rebuilds. The blogroll page is still static and pregenerated, but automatically updating it, say, every day or so will make sure the latest posts never fall too far behind.\n- Build the blogroll on each request. For an Eleventy site, this would entail using either Eleventy Serverless or Eleventy Edge to fetch each blog’s RSS feed and build the blogroll page anew whenever a user hits the page.\n- Fetch RSS feeds with client-side scripts. This involves pushing a bunch of scripts to users, delays the latest-post information rendering, and will likely introduce the need to handle loading and error states.\nIn my case, my site was already set up to rebuild daily, something I’d put together in my Some Antics days to auto-update the YouTube thumbnail on the homepage without serving up YouTube’s heavyweight scripts to every user. I use a GitHub Action to schedule my daily Netlify builds; your stack may have a different approach for scheduling regular rebuilds.\nThe regular-rebuilds technique won’t be truly, immediately up-to-date, but for my needs, it’s up-to-date enough — especially given that this is the most robust and performant experience for the end user, who as far as their browser is concerned, is just pulling a standard-issue, prebuilt HTML file living on a server.\nSetting Up the Basic Blog Data\nNext up, I opted to store a list of the blogs in Eleventy data. If I were going for a simple list of links to blogs with nothing added, I’d push for just hardcoding the markup directly, but since I planned to use this information to orchestrate fetching further information, I needed the blog list stored in data.\nThis data is only used on one page, the blogroll page, which means the blog list could sit pretty much anywhere in Eleventy’s data cascade. I opted to set it up as directory data so I could colocate the data with the upcoming template file, but there’s no reason I couldn’t have set it up as global data instead.\nI created a src/blogroll/\ndirectory in my project, and in there, I created a JSON file called blogroll.11tydata.json\n. The fact that the blogroll\nin the filename matches the directory name establishes this file within Eleventy as a directory data file.\nThen I populated that JSON file:\nNow, any template within src/blogroll/\nwill be able to access this list using the blogs\ndata variable.\nThe details I’ve provided about each blog here are minimal, only the stuff I’m fine hardcoding. For your blogroll, you might opt to hardcode more details into this list — maybe a short description of each blog?\nFetching the Latest Posts\nNow that we have the basic scaffold of information for each blog in our blogroll, we want to fetch each blog’s latest post and surface it within our Eleventy data.\nAnytime we want to take some data that already exists (like our raw blog list) and act on it to expose some new data (like latest posts), Eleventy’s computed data feature comes in handy.\nHere, I needed two libraries: rss-parser\n, which does what it says on the tin, and Eleventy Fetch, which handles caching fetched results for us whenever we run the dev server locally.\nThen in src/blogroll/\n, I created a JavaScript directory data file called blogroll.11tydata.js\n. That data file looked like this:\nWhew. There’s a lot here. The long and short of this is that in addition to our scaffoldlike blogs\ndata array, we now also have a blogData\ndata array which looks similar, but wherein each blog object might also have a latestPost\nproperty. Additionally, each fetch response is stored in a cache (via Eleventy Fetch’s AssetCache\n) that persists for one day, which will ensure that our local development server doesn’t fire off spurious requests to each of these feeds every time we make a change to our site, so that our dev server isn’t bogged down and we’re not flooding our favorite blogs with swarms of unnecessary requests.\nWe’ll add more to our augmented blog data objects shortly, but first, let’s put some contents on an HTML page, just to make sure everything’s working so far.\nThe Blogroll Page Template\nNext up, I created a template file for the blogroll page. In practice, this template made use of some base layouts I already had, but I’ll omit that setup for the purpose of this blog.\nThis template iterates through our augmented blogData\ndata array, and outputs an <article>\nfor each entry. Each <article>\ncontains a link to the blog and, if a latest post was found successfully, a link to that post.\nIf you run your project, you should now see this new template at /blogroll/\n. Each blog should be listed out alongside its latest post.\nAt this point, you can begin styling the page, but I had a few more enhancements I wanted to make.\nShowing Each Blog’s Favicon\nFavicons are a lovely expression of each site’s personality, and showing them would go a long way towards giving each blog entry its own flair.\nI explored a few options for getting a site’s favicons, but at the end of the day, the simplest option by far came from URL-based favicon fetching API services, including one from Eleventy project itself: Zach’s IndieWeb Avatar service. Given any site URL, you can get its favicon as a valid <img>\nsrc\nwith just a quick transformation:\nEasy enough!\nThis transformation from blog URL to its IndieWeb Avatar service URL could be achieved perfectly fine with Eleventy filters in your templates, but since I already had the computed data infrastructure, I opted to keep adding to it instead:\nThen in our templates:\nNow, our blogroll shows some handy favicons, adding a pop of color and variety to each blog in the list!\nIt’s worth mentioning that if the IndieWeb Avatar service fails to get the blog’s avatar, it’ll use a fallback image of the Eleventy logo. This may or may not be your speed.\nThere are a number of other similar avatar services you could use instead, if you like, including those made by Google and DuckDuckGo. These all follow similar URL-based approaches. For more info, I recommend Jim Nielsen’s post on displaying favicons.\nDisplaying Pretty URLs\nFor my blogroll design, I wanted to show a cleaned up version of each blog’s URL. I did this with the normalize-url\npackage, which I’d previously used on the Some Antics site to format guests’ personal sites.\nWe’ll first install normalize-url\n. In v7 of normalize-url\n, the package went ESM-only. Since, at time of writing, Eleventy doesn’t yet support ESM, we’ll need to install version 6 or lower. Other frameworks or build tools likely won’t have that stipulation.\nLike the avatar, we could probably set up a filter to handle this transformation for us, but since I already had the computed data approach set up to augment the data for each blog in the list, I just kept using that.\nAnd then we add this new data to the page in our template:\nVoilà\nWith that, you have the setup for a blogroll that updates daily for any Eleventy site. If you haven’t already, now’s the time to add your styles.\nOther enhancements could absolutely be added to the blogroll — showing the blogs’ latest posts’ dates or their total post counts comes to mind, as does adding brief descriptions of each blog — but I was pretty happy with this state so far.\nWhat does your blogroll look like?\nHave you added anything exciting to yours? Let me know on Mastodon!", "url": "https://wpnews.pro/news/build-a-blogroll-with-eleventy", "canonical_source": "https://benmyers.dev/blog/eleventy-blogroll/", "published_at": "2023-09-21 00:00:00+00:00", "updated_at": "2026-05-23 14:12:29.848686+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["Claudia Snell", "Frontend Horse", "Eleventy"], "alternates": {"html": "https://wpnews.pro/news/build-a-blogroll-with-eleventy", "markdown": "https://wpnews.pro/news/build-a-blogroll-with-eleventy.md", "text": "https://wpnews.pro/news/build-a-blogroll-with-eleventy.txt", "jsonld": "https://wpnews.pro/news/build-a-blogroll-with-eleventy.jsonld"}}