<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sia Karamalegos</title>
    <description>The latest articles on DEV Community by Sia Karamalegos (@thegreengreek).</description>
    <link>https://dev.to/thegreengreek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F253984%2F29e0b0cd-a006-42f2-982e-53fc91d3c375.jpg</url>
      <title>DEV Community: Sia Karamalegos</title>
      <link>https://dev.to/thegreengreek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thegreengreek"/>
    <language>en</language>
    <item>
      <title>Itsiest, Bitsiest Eleventy Tutorial</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Thu, 08 Jul 2021 20:10:54 +0000</pubDate>
      <link>https://dev.to/thegreengreek/itsiest-bitsiest-eleventy-tutorial-1llc</link>
      <guid>https://dev.to/thegreengreek/itsiest-bitsiest-eleventy-tutorial-1llc</guid>
      <description>&lt;p&gt;Want to get started with Eleventy but feel overwhelmed? Try out this pared-down tutorial.&lt;/p&gt;

&lt;p&gt;I like to talk and write about Eleventy a LOT. I always run into this problem of having to introduce Eleventy to people not familiar with it in a short way. So, I wrote up this miniature demo to give people a flavor of Eleventy without overwhelming them with all the details. If you like it as much as I do, maybe it will inspire you to learn more!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you prefer learning by video?&lt;/strong&gt; I included a walkthrough of this demo in my &lt;a href="https://sia.codes/posts/webmentions-eleventy-talk/#magnolia-js-(includes-short-eleventy-tutorial)"&gt;talk on Webmentions + Eleventy at Magnolia JS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code for this repo can be found on &lt;a href="https://github.com/siakaramalegos/eleventy-demo"&gt;Github&lt;/a&gt;. This article is meant for people new to Eleventy and will show you how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start up the most minimal Eleventy project with one page (the &lt;code&gt;main&lt;/code&gt; branch)&lt;/li&gt;
&lt;li&gt;Add a layout and styles (the &lt;code&gt;2-layout-styles&lt;/code&gt; branch)&lt;/li&gt;
&lt;li&gt;Add a blog and a list of all blog posts (the &lt;code&gt;3-blog&lt;/code&gt; branch)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To get started, clone the &lt;a href="https://github.com/siakaramalegos/eleventy-demo"&gt;repo&lt;/a&gt;, cd into it, and run &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking a step back
&lt;/h2&gt;

&lt;p&gt;The steps to get it to this point ("step 1") were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make a new directory&lt;/li&gt;
&lt;li&gt;cd into it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm init -y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install Eleventy with &lt;code&gt;npm install @11ty/eleventy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Edit the package.json to add a &lt;code&gt;start&lt;/code&gt; script of &lt;code&gt;npx @11ty/eleventy --serve&lt;/code&gt; and a build script of &lt;code&gt;npx @11ty/eleventy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create index.md&lt;/li&gt;
&lt;li&gt;Run the start script. Eleventy processes index.md into the default output folder &lt;code&gt;/_site/&lt;/code&gt; with the filename &lt;code&gt;index.html&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Add a layout and styles
&lt;/h2&gt;

&lt;p&gt;Checkout branch &lt;code&gt;2-layout-styles&lt;/code&gt; to see this next step. In this step, I move our source code to a &lt;code&gt;/src/&lt;/code&gt; folder, add a layout file, and add a CSS styles file.&lt;/p&gt;

&lt;p&gt;To build it on your own:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, we move our source code to &lt;code&gt;/src/&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;/src/&lt;/code&gt; and move &lt;code&gt;index.md&lt;/code&gt; into it.&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.eleventy.js&lt;/code&gt; file in the root of the project with the following content:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Set custom directories for input, output, includes, and data&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_includes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_site&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of those are defaults - change their name in this file if you'd like to use a different name. You'll need to restart your dev server for any changes in this file to take effect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next, add a layout:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;/src/_includes/layout.njk&lt;/code&gt;. This is a &lt;a href="https://mozilla.github.io/nunjucks/"&gt;Nunjucks&lt;/a&gt; template, but you can use &lt;a href="https://www.11ty.dev/docs/"&gt;many others&lt;/a&gt;. The stuff in curly brackets are things that we will fill in at build time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Grab title from the page data and dump it here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ title }}&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Grab the content from the page data, dump it here, and mark it as safe --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Safe docs: https://mozilla.github.io/nunjucks/templating.html#safe --&amp;gt;&lt;/span&gt;
    {{ content | safe }}
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;a href="https://www.11ty.dev/docs/data-frontmatter/"&gt;YAML frontmatter&lt;/a&gt; to the top of our &lt;code&gt;/src/index.md&lt;/code&gt; file to tell it which layout to use and to set the &lt;code&gt;title&lt;/code&gt; data attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
layout: layout.njk
title: "The Best Eleventy Demo TM"
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finally, add some CSS:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;/src/style.css&lt;/code&gt;. Add some CSS to that file.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;&amp;lt;link rel="stylesheet" href="/style.css"&amp;gt;&lt;/code&gt; to the head of &lt;code&gt;/src/_includes/layout.njk&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Now we need to tell Eleventy to &lt;a href="https://www.11ty.dev/docs/copy/#manual-passthrough-file-copy-(faster)"&gt;"pass through"&lt;/a&gt; any CSS files. We do this in &lt;code&gt;.eleventy.js&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Copy `src/style.css` to `_site/style.css`&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addPassthroughCopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/style.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// When a passthrough file is modified, rebuild the pages:&lt;/span&gt;
    &lt;span class="na"&gt;passthroughFileCopy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_includes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_site&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Add a blog
&lt;/h2&gt;

&lt;p&gt;Checkout branch &lt;code&gt;3-blog&lt;/code&gt; to see this next step. In this step, I create blog posts and an index of those posts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;/src/blog/&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Add our first post in that folder &lt;code&gt;welcome-to-my-blog.md&lt;/code&gt;, remembering to set the layout and title:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--------
layout: layout.njk
title: Welcome to my blog
--------

# Welcome

These are profound thoughts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now access it at &lt;a href="http://localhost:8080/blog/welcome-to-my-blog/"&gt;http://localhost:8080/blog/welcome-to-my-blog/&lt;/a&gt;, but it would be nice to get some links on our home page for all our posts. For that, we should make a &lt;a href="https://www.11ty.dev/docs/collections/"&gt;collection&lt;/a&gt; for our blog posts. We will do this using tags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: You can log data to your terminal using the &lt;code&gt;log&lt;/code&gt; filter which is included in Eleventy for free! For example, &lt;code&gt;{{ collections | log }}&lt;/code&gt; to see all your collections. Right now, we only have the &lt;code&gt;all&lt;/code&gt; collection which contains all our pages (home and first blog post).&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;blog&lt;/code&gt; tag to our blog post's frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ---
  layout: layout.njk
  title: Welcome to my blog
  tags: blog
  ---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change our &lt;code&gt;/src/index.md&lt;/code&gt; file to use Nunjucks instead by changing &lt;code&gt;.md&lt;/code&gt; to &lt;code&gt;.njk&lt;/code&gt; and changing the current content to html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  ---
  layout: layout.njk
  title: The Best Eleventy Demo TM
  ---

  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Yo Eleventy&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This site rocks.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render a list of blogs on our index/home page (&lt;code&gt;/src/index.njk&lt;/code&gt;) usink a &lt;a href="https://mozilla.github.io/nunjucks/templating.html#for"&gt;Nunjucks for loop&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  {% for post in collections.blog %}
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ post.url }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ post.data.title }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  {% endfor %}
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add another post and see it magically appear!&lt;/p&gt;

&lt;p&gt;Add a "nav" to your home page so people can get back to it from the blog page. In &lt;code&gt;/src/_includes/layout.njk&lt;/code&gt; inside the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is when I'd probably make another layout for a blog post so that the title is automatically rendered in its &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, but then this baby demo would be longer. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving Forward
&lt;/h2&gt;

&lt;p&gt;Once you've had a chance to play with collections and other forms of data in Eleventy, I recommend you check out my article &lt;a href="https://sia.codes/posts/architecting-data-in-eleventy/"&gt;Architecting data in Eleventy&lt;/a&gt; to learn more. It might be a bit much if this is your first time.&lt;/p&gt;

&lt;p&gt;What else can Eleventy do? So much! Here's a list of some of my favorite features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating &lt;a href="https://www.11ty.dev/docs/pages-from-data/"&gt;pages based on a data&lt;/a&gt; set (JavaScript, JSON), like my individual &lt;a href="https://games.sia.codes/terraforming-mars/"&gt;game pages&lt;/a&gt; in my &lt;a href="https://games.sia.codes/"&gt;boardgame shelf site&lt;/a&gt;. &lt;a href="https://github.com/siakaramalegos/games"&gt;Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Creating &lt;a href="https://www.11ty.dev/docs/layout-chaining/"&gt;layouts&lt;/a&gt; within layouts and template &lt;a href="https://mozilla.github.io/nunjucks/templating.html#include"&gt;partials&lt;/a&gt; (like creating components)&lt;/li&gt;
&lt;li&gt;Using &lt;a href="https://www.11ty.dev/docs/filters/"&gt;filters&lt;/a&gt; and &lt;a href="https://www.11ty.dev/docs/shortcodes/"&gt;shortcodes&lt;/a&gt; to make reusable functions and code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/itsiest-bitsiest-eleventy-tutorial/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Adding Prettier to a Project</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Thu, 01 Jul 2021 20:28:02 +0000</pubDate>
      <link>https://dev.to/thegreengreek/adding-prettier-to-a-project-13f6</link>
      <guid>https://dev.to/thegreengreek/adding-prettier-to-a-project-13f6</guid>
      <description>&lt;p&gt;While working at a smaller dev shop, our team hit the point at which the inconsistent code formats between and within projects was becoming a pain. Our needs included:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A consistent linter/formatter for all projects in a particular language&lt;/li&gt;
&lt;li&gt;An autoformatter so developers didn't spend time "fixing" linter errors&lt;/li&gt;
&lt;li&gt;A tool readily available in tools like VS Code which could apply changes on save&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We decided to go with &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt;. We also added a pre-commit hook to ensure that all code changes complied with the new authoritarianism.&lt;/p&gt;

&lt;p&gt;I initially published this as a &lt;a href="https://gist.github.com/siakaramalegos/4a5cdab1f44ffb217a48d5260043f8ae"&gt;gist&lt;/a&gt; to help when setting up new projects at that company. Today, it was useful for a client I was working with, so I'm sharing it now in an article in case the same use case fits for you, and you'd like a handy reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Steps
&lt;/h2&gt;

&lt;p&gt;Most of these steps can be found in the &lt;a href="https://prettier.io/docs/en/install.html"&gt;docs&lt;/a&gt; and through other links in the docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A key step here is to run Prettier on all the files in a separate commit. You don't want to pollute all your future pull request diffs with formatting changes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(1) Install prettier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(2) Create an empty config file to let tools know you're using Prettier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&amp;gt;&lt;/span&gt; .prettierrc.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(3) Create a &lt;code&gt;.prettierignore&lt;/code&gt; file to let tools know which files NOT to format. &lt;code&gt;node_modules&lt;/code&gt; are ignored by default. Some suggestions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;build
coverage
.package-lock.json
&lt;span class="k"&gt;*&lt;/span&gt;.min.&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(4) Manually run Prettier to re-format all the files in the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx prettier &lt;span class="nt"&gt;--write&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(5) Set up your code editor to auto-format on save for ease of use. See &lt;a href="https://prettier.io/docs/en/editors.html"&gt;instructions&lt;/a&gt; for various editors.&lt;/p&gt;

&lt;p&gt;(6) Set up commit hooks with &lt;a href="https://github.com/azz/pretty-quick"&gt;pretty-quick&lt;/a&gt; and &lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt;. First, install them as dev dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; pretty-quick husky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(7) Finally, add the pre-commit instructions to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pretty-quick --staged"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you commit your changes, files in the commit will automatically be formatted!&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/how-to-add-prettier-to-a-project/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tooling</category>
      <category>prettier</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Faster YouTube embeds in Eleventy</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Wed, 07 Apr 2021 17:54:23 +0000</pubDate>
      <link>https://dev.to/thegreengreek/faster-youtube-embeds-in-eleventy-23ln</link>
      <guid>https://dev.to/thegreengreek/faster-youtube-embeds-in-eleventy-23ln</guid>
      <description>&lt;p&gt;Video is great, but the default YouTube embed share is both bloated and not privacy-minded. I finally switched my YouTube embeds to &lt;a href="https://github.com/paulirish/lite-youtube-embed" rel="noopener noreferrer"&gt;lite-youtube-embed&lt;/a&gt; by &lt;a href="https://twitter.com/paul_irish" rel="noopener noreferrer"&gt;Paul Irish&lt;/a&gt;, and it's fantastic. It loads "faster than a sneeze" and uses the no-cookie version by default.&lt;/p&gt;

&lt;p&gt;This post will explain how to set up a reusable lite-youtube-embed "component" using Nunjucks partials in an Eleventy project.&lt;/p&gt;

&lt;p&gt;Before implementing lite-youtube-embed, one of my pages using the default YouTube embed had a Lighthouse score of 71:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kv5uuthpb2xcjh43m3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kv5uuthpb2xcjh43m3j.png" alt="Lighthouse screenshot showing a score of 71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After implementing lite-youtube-embed, my performance score popped up to 97:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4u1rdpdr1gasi7v0yj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff4u1rdpdr1gasi7v0yj6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get the source code
&lt;/h2&gt;

&lt;p&gt;This step will vary depending on how you currently load JavaScript in your Eleventy application. I try to keep my blog as minimal as possible, so I have no significant client-side JS. Thus, I chose to download the JavaScript file instead of adding the npm package and a bundle step. If you already have a bundler set up, then add the npm package instead.&lt;/p&gt;

&lt;p&gt;These steps describe how to add it to an Eleventy project with no JavaScript files yet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the source code &lt;a href="https://github.com/paulirish/lite-youtube-embed/blob/master/src/lite-yt-embed.js" rel="noopener noreferrer"&gt;JavaScript file&lt;/a&gt; to a /javascript/ folder in your project.&lt;/li&gt;
&lt;li&gt;Update the Eleventy config to pass the /javascript/ folder through to our build:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eleventy.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Copy all files in the JavaScript folder to our output directory.&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addPassthroughCopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// more config stuff...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I choose to organize my source code in an &lt;strong&gt;/src/&lt;/strong&gt; folder (my input directory). If your code is in the root of your project, then ignore mentions of &lt;strong&gt;/src/&lt;/strong&gt;  in this post.&lt;/p&gt;

&lt;p&gt;Additionally, we need to grab the &lt;a href="https://github.com/paulirish/lite-youtube-embed/blob/master/src/lite-yt-embed.css" rel="noopener noreferrer"&gt;CSS from the source code&lt;/a&gt;. For simplicity, I copied it into my existing CSS file since the content wasn't that long. If your video looks weird after implementing, your project's existing styles are probably impacting it. For example, I had some iframe styles that caused the video to shift down inside its container.&lt;/p&gt;

&lt;h2&gt;
  
  
  YouTube partial
&lt;/h2&gt;

&lt;p&gt;Now, we need to create a new template for a YouTube video. I'm using Nunjucks to create a video "component". In the &lt;strong&gt;/_includes/&lt;/strong&gt; folder, create a youtube.njk file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- src/_includes/youtube.njk --&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Load the JS only when the component is needed --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/javascript/lite-yt-embed.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Web component for lite-youtube-embed --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;lite-youtube&lt;/span&gt; &lt;span class="na"&gt;videoid=&lt;/span&gt;&lt;span class="s"&gt;"{{ videoId }}"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image: url('https://i.ytimg.com/vi/{{ videoId }}/hqdefault.jpg');"&lt;/span&gt; &lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt; &lt;span class="na"&gt;params=&lt;/span&gt;&lt;span class="s"&gt;"{{ params }}"&lt;/span&gt;&lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;endif&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lty-playbtn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lyt-visually-hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Play Video: {{ videoTitle }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/lite-youtube&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The web component will use up to 3 parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;videoId&lt;/code&gt; - the id of the YouTube video which you can grab from its URL. For example, "XecoxR1ckbc" is the id of the video in this URL: &lt;a href="https://www.youtube.com/embed/XecoxR1ckbc" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/XecoxR1ckbc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;videoTitle&lt;/code&gt; - the video title&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;params&lt;/code&gt; - optional params like &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose to defer the YouTube script loading for progressive enhancement. Our tiny bit of JavaScript from lite-youtube-embed will always load. But, the larger code from YouTube will only load if a user clicks on the video to play it. See the &lt;a href="https://github.com/paulirish/lite-youtube-embed/blob/master/readme.md" rel="noopener noreferrer"&gt;readme&lt;/a&gt; if you'd like to always load the YouTube scripts regardless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the new YouTube partial
&lt;/h2&gt;

&lt;p&gt;Now that our set up is complete, we can use our new "component" in any file. First, we set the variables that pass through to the component, then we include the partial. This example also illustrates how to add a start and end time to the optional params:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- In any other file (e.g., a blog post): --&amp;gt;&lt;/span&gt;
{% set videoTitle = "Vintage Bundles by Sia Karamalegos [ Magnolia JS ]" %}
{% set videoId = "Qkc8p4D6JM0" %}
{% set params = "start=10260&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;end=11280" %}
{% include 'youtube.njk' %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see it in action in the &lt;a href="https://sia.codes/posts/lite-youtube-embed-eleventy/#using-the-new-youtube-partial" rel="noopener noreferrer"&gt;original article&lt;/a&gt; on my blog.&lt;/p&gt;

&lt;p&gt;What my source code looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;+{% set videoTitle = "Webmentions + Eleventy by Sia Karamalegos [ Jamstack Toronto ]" %}
+{% set videoId = "zjHb4xtnTvU" %}
+{% include 'youtube.njk' %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the compiled HTML looks like (Eleventy output):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"videoWrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Webmentions + Eleventy by Sia Karamalegos [ Jamstack Toronto ]"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"560"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"315"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://www.youtube.com/embed/zjHb4xtnTvU"&lt;/span&gt; &lt;span class="na"&gt;frameborder=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;allow=&lt;/span&gt;&lt;span class="s"&gt;"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"&lt;/span&gt; &lt;span class="na"&gt;allowfullscreen&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Switching to &lt;a href="https://github.com/paulirish/lite-youtube-embed" rel="noopener noreferrer"&gt;lite-youtube-embed&lt;/a&gt; can greatly improve our load performance. It also better protects the privacy of our users. We can use HTML templates in Eleventy to create a YouTube video component, making reuse a breeze.&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/lite-youtube-embed-eleventy/" rel="noopener noreferrer"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>webperf</category>
      <category>youtube</category>
      <category>video</category>
    </item>
    <item>
      <title>Eleventy and Cloudinary images</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Sat, 12 Dec 2020 04:32:25 +0000</pubDate>
      <link>https://dev.to/thegreengreek/eleventy-and-cloudinary-images-1pdj</link>
      <guid>https://dev.to/thegreengreek/eleventy-and-cloudinary-images-1pdj</guid>
      <description>&lt;p&gt;I'm a huge fan of &lt;a href="https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/oq6yrskcixnvxvj1ofc0"&gt;Cloudinary&lt;/a&gt; for media, and this was the first time I set it up on a site using &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt;. In typical fashion, I wasn't satisfied with the existing solutions I found, so I decided to write my own.&lt;/p&gt;

&lt;p&gt;Originally, I did not set up Cloudinary on my blog because I used to have just a handful of images, and I would create srcsets and formats manually &lt;a href="https://github.com/siakaramalegos/images-on-the-command-line"&gt;using ImageMagick and cwebp&lt;/a&gt;. But then I got excited about using &lt;a href="https://developers.google.com/search/docs/guides/search-gallery"&gt;structured data&lt;/a&gt; for SEO, and the image generation job got a lot more complicated with more sizes and cropping.&lt;/p&gt;

&lt;p&gt;In this post, first I'll go over how I think about serving responsive, performant images. Then, I'll show you how I implemented Cloudinary image hosting in Eleventy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Let's take a look at a "fully-loaded" image tag in HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"pug_life.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"pug_life_600.jpg 600w, pug_life_300.jpg 300w,"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(min-width: 760px) 600px, 300px"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Pug wearing a striped shirt"&lt;/span&gt;
    &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;
    &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why did I include all those attributes? Let's take a look at each...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src&lt;/code&gt; - the image to display (required!)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;srcset&lt;/code&gt; - for modern browsers, a set of candidate images and their widths in pixels&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sizes&lt;/code&gt; - for modern browsers, how wide the image will be displayed at various screen widths&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alt&lt;/code&gt; - description of the image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;width&lt;/code&gt; - the image width&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;height&lt;/code&gt; - the image height&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;loading&lt;/code&gt; - optionally lazy-load images and iframes, &lt;a href="https://caniuse.com/loading-lazy-attr"&gt;caniuse&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For modern browsers, we can give a set of images and instructions for how wide they will be displayed using &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;. This allows the browser to make the best decision on which image to load based on the user's screen width and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio"&gt;device pixel ratio (DPR)&lt;/a&gt;. For example, those nice Retina screens (DPR of 2) need images twice as wide as the slot we're putting them in if we still want them to look good.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sizes&lt;/code&gt; attribute can be tricky to write correctly by hand. My favorite way of getting it (a.k.a, the lazy way), is to first give the image a &lt;code&gt;srcset&lt;/code&gt;, then run the page through &lt;a href="https://ausi.github.io/respimagelint/"&gt;RespImageLint&lt;/a&gt;. RespImageLint is a nifty bookmarklet that will let you know how far off your images are in their size, and will also give us suggestions for the &lt;code&gt;sizes&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JX9epHAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/90eta8dn9bb025p6bj18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JX9epHAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/90eta8dn9bb025p6bj18.png" alt="Feedback, code, and image preview in a RespImageLint result"&gt;&lt;/a&gt;&lt;br&gt;RespImageLint will suggest a sizes attribute if you provide a srcset
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Layout Shift
&lt;/h2&gt;

&lt;p&gt;To prevent layout shift once the image loads, we need to provide the browser with an aspect ratio. Currently, the way to do that is to set a height and width on the image in HTML. Use the original image's dimensions since the actual size doesn't matter, just the aspect ratio. Your CSS will control the actual height and width.&lt;/p&gt;

&lt;p&gt;To prevent weird stretching, set an auto height in your CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jen Simmons recorded a great &lt;a href="https://www.youtube.com/watch?v=4-d_SoCHeWE&amp;amp;feature=youtu.be"&gt;short video&lt;/a&gt; on this trick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy loading
&lt;/h2&gt;

&lt;p&gt;We now have &lt;a href="https://caniuse.com/loading-lazy-attr"&gt;partial support&lt;/a&gt; for lazy loading images and iframes! If you set the &lt;code&gt;loading&lt;/code&gt; attribute to &lt;code&gt;lazy&lt;/code&gt;, the browser will use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API"&gt;IntersectionObserver&lt;/a&gt; to detect if a user scrolls near the image or iframe and only load it at that time.&lt;/p&gt;

&lt;p&gt;At the time of writing, 78% of my blog's visitors are supported for images, so I'm implementing it now. Note that you should not lazy-load images that are in the viewport on initial load ("above the fold"), as this can negatively impact your &lt;a href="https://web.dev/vitals/"&gt;performance scores&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Now that you know how I think about images, I can explain my rational behind my solution. Some of the existing alternatives were &lt;a href="https://www.11ty.dev/docs/shortcodes/"&gt;Eleventy shortcodes&lt;/a&gt; that provided the full image tag based on the filename, alt, and a few other attributes. I wanted the ability to also provide all the attributes previously mentioned plus others like &lt;code&gt;class&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The shortcode quickly became unwieldy with this many parameters, and I realized that the HTML itself was only marginally longer. Why not just use HTML? The onerous part of building responsive images, especially when hosting through Cloudinary, is setting the image urls and generating the srcsets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why not just use HTML?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hence, I created shortcodes that do only that - generate the &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;srcset&lt;/code&gt;, and everything else can be set as needed in the HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{% src "&lt;/span&gt;&lt;span class="na"&gt;possum_film_director.jpg&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;%}"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"{% srcset "&lt;/span&gt;&lt;span class="na"&gt;possum_film_director.jpg&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;%}"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(min-width: 760px) 680px, 93.64vw"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Possum directing a movie"&lt;/span&gt;
    &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"2953"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"2178"&lt;/span&gt;
    &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"super-great-style-class"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't need a &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; tag because Cloudinary can automatically serve the best image format based on the user's browser through the &lt;a href="https://cloudinary.com/documentation/image_transformations#automatic_format_selection_f_auto"&gt;f_auto transformation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you found this article helpful, you can &lt;a href="https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/oq6yrskcixnvxvj1ofc0"&gt;sign up for a free Cloudinary account&lt;/a&gt; with this link, and I'll get a few extra Cloudinary credits per month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Shortcodes
&lt;/h3&gt;

&lt;p&gt;For the shortcodes, I gave them smart default widths based on the styles for my site, but I allow an optional parameter to set them when I invoke the shortcode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// _11ty/shortcodes.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CLOUDNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[your Cloudinary cloud name]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FOLDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[optional asset folder in Cloudinary]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://res.cloudinary.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CLOUDNAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/image/upload/`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FALLBACK_WIDTHS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;680&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1360&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FALLBACK_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;680&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSrcset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widthSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FALLBACK_WIDTHS&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;widthSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;getSrc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;w`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSrc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;q_auto,f_auto,w_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FALLBACK_WIDTH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;FOLDER&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;srcset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getSrcset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;widths&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getSrc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is to add the shortcodes to our Eleventy config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eleventy.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;srcset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./_11ty/shortcodes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addShortcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addShortcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;srcset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;srcset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà!&lt;/p&gt;

&lt;p&gt;How do you use Eleventy with Cloudinary? I haven't turned this into a plugin yet. Should I?&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/eleventy-and-cloudinary-images/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>javascript</category>
      <category>cloudinary</category>
      <category>images</category>
    </item>
    <item>
      <title>Architecting data in Eleventy</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Thu, 11 Jun 2020 15:20:27 +0000</pubDate>
      <link>https://dev.to/thegreengreek/architecting-data-in-eleventy-ek5</link>
      <guid>https://dev.to/thegreengreek/architecting-data-in-eleventy-ek5</guid>
      <description>&lt;p&gt;&lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt; is a static site generator that makes building static, performant websites a breeze. It uses JavaScript to build pages at build time, but does not require any JavaScript in the client to render them.&lt;/p&gt;

&lt;p&gt;Eleventy's magic comes with powerful tools for data, but the data model can be a lot to conceptualize when you're new to Eleventy. In this post, I'll explain the hierarchy of the data that we can work with and how to access it. I'll use real-world examples for learners like me who understand concepts better when they see them applied in practice.&lt;/p&gt;

&lt;p&gt;Disclaimer: opinions ahead! I'm going to focus more on the concepts that will help you in decision making. Links are provided if you want to dive into the details of any one concept. I hope to make a second post in this series that talks about manipulating data, so stay tuned!&lt;/p&gt;

&lt;p&gt;The examples here will use HTML, Markdown, JavaScript, JSON, and &lt;a href="https://mozilla.github.io/nunjucks/templating.html"&gt;Nunjucks&lt;/a&gt;. For reference, I'm using &lt;a href="https://github.com/11ty/eleventy/releases/tag/v0.11.0"&gt;Eleventy version 0.11.0&lt;/a&gt; as it has a few cool new tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.11ty.dev/docs/"&gt;Eleventy docs&lt;/a&gt; are a key place to start understanding the different features. We're going to take these a few steps further to give you an over-arching understanding of how it all works together.&lt;/p&gt;

&lt;p&gt;To follow along, you can find the code in my &lt;a href="https://github.com/siakaramalegos/eleventy-data-tutorial"&gt;eleventy-data-tutorial&lt;/a&gt; repo. The &lt;code&gt;main&lt;/code&gt; branch contains a bare-bones starting Eleventy app with an index.html and a single layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I see my data??
&lt;/h2&gt;

&lt;p&gt;As someone used to building apps with front-end frameworks or client-side JavaScript, I felt like a deer in the headlights when I first wanted to "see" my data. Eleventy is using JavaScript to build full HTML pages in Node, not render them in a browser. This means we don't have access to browser dev tools like the debugger or the browser console.&lt;/p&gt;

&lt;p&gt;We do have access to the terminal/command line console and the rendered pages. New in version 0.11.0, we have access to a &lt;a href="https://www.11ty.dev/docs/filters/log/"&gt;&lt;code&gt;log&lt;/code&gt;&lt;/a&gt; "universal filter" which performs a &lt;code&gt;console.log()&lt;/code&gt; accessible in our terminal (remember, we're in Node land!). &lt;a href="https://mozilla.github.io/nunjucks/templating.html#filters"&gt;Filters&lt;/a&gt; are functions, and we write them in our templates by first listing the first parameter, then the filter name. If the filter accepts more than one parameter, we add them in parentheses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- _includes/layout.njk --&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- console.log the page data --&amp;gt;&lt;/span&gt;
{{ page | log }}

&lt;span class="c"&gt;&amp;lt;!-- run myCustomFilter on 2 params, the title data and anotherParam --&amp;gt;&lt;/span&gt;
{{ title | myCustomFilter(anotherParam) }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I make heavy use of the &lt;code&gt;log&lt;/code&gt; filter to debug my builds (since most of my bugs are from not handling the data correctly), and it's great to have this built in now. Another option is to output the data to the rendered page, but that doesn't work with complex objects.&lt;/p&gt;

&lt;p&gt;Note that you can also run Eleventy in &lt;a href="https://www.11ty.dev/docs/debugging/"&gt;debugging mode&lt;/a&gt; for other information. I'm still learning how to best use this tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Page data
&lt;/h2&gt;

&lt;p&gt;Every page has a &lt;a href="https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable-contents"&gt;&lt;code&gt;page&lt;/code&gt;&lt;/a&gt; object available in the template which includes data like input and output file paths, the file slug, and URL. See it in your command line by logging it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- _includes/layout.njk --&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- console.log the page data --&amp;gt;&lt;/span&gt;
{{ page | log }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your output will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="nx"&gt;T19&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;02.218&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the file slug is an empty string for the index file. If I add a new folder called &lt;code&gt;/posts&lt;/code&gt; with a file called &lt;code&gt;my-first-post.md&lt;/code&gt;, I get this page data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="nx"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;20.649&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/posts/my-first-post.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-first-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-first-post/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/posts/my-first-post/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Eleventy builds pages based on your file and directory structure. In the &lt;a href="https://github.com/siakaramalegos/eleventy-data-tutorial/tree/1-page-data"&gt;&lt;code&gt;1-page-data&lt;/code&gt; branch&lt;/a&gt; of the repo, you can see the pages logged to the console if you run &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before we move on to custom data, note that Eleventy also provides &lt;code&gt;pagination&lt;/code&gt; data to a page. Pagination is a very specific use case, so I won't cover it here. Read more about &lt;a href="https://www.11ty.dev/docs/pagination/"&gt;pagination in the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection data
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://www.11ty.dev/docs/collections/"&gt;collections&lt;/a&gt;, we are upping the magicalness of Eleventy. Collections are groups of pages that are grouped by &lt;a href="https://www.11ty.dev/docs/collections/#tag-syntax"&gt;tags&lt;/a&gt;*. To conceptualize this, think of a traditional blog with posts on multiple topics. One post might be tagged &lt;code&gt;JavaScript&lt;/code&gt; while another might be tagged both &lt;code&gt;JavaScript&lt;/code&gt; and &lt;code&gt;HTML&lt;/code&gt;. If you like relational databases, think of tags and pages as having a many-to-many relationship.&lt;/p&gt;

&lt;p&gt;Collections are useful for rendering lists of pages that include the ability to navigate to those pages. For example, an index page for your blog posts or a list of pages with the same content tag.&lt;/p&gt;

&lt;p&gt;Collections are JavaScript objects, and each key is the tag name. The value for each key is an array of pages. Tags are set using the data hierarchy which I'll get to in a bit, and this is what the &lt;code&gt;collections&lt;/code&gt; object looks like if we &lt;code&gt;log&lt;/code&gt; it from our home page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// By default, the `all` key is created and includes all pages.&lt;/span&gt;
  &lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="na"&gt;T19&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;02.218&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Getter&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Setter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...rest of all pages&lt;/span&gt;
  &lt;span class="c1"&gt;// Pages tagged as "posts"&lt;/span&gt;
  &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/posts/my-first-post.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-first-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="na"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;20.649&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/posts/my-first-post/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-first-post/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Getter&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Setter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...rest of posts&lt;/span&gt;
  &lt;span class="nx"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/podcasts/my-first-podcast.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-podcast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/podcasts/my-first-podcast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="na"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.665&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/podcasts/my-first-podcast/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/podcasts/my-first-podcast/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Getter&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Setter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;JavaScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/podcasts/my-first-podcast.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-podcast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/podcasts/my-first-podcast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="na"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;43.665&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/podcasts/my-first-podcast/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/podcasts/my-first-podcast/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Getter&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Setter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/posts/my-second-post.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-second-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-second-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="na"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;27.709&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/posts/my-second-post/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-second-post/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Getter&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Setter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The collections object by default includes an &lt;code&gt;all&lt;/code&gt; key which includes all pages.&lt;/li&gt;
&lt;li&gt;I have tagged by both content type (posts vs podcasts) which matches my routing, and by topic (JavaScript).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are not limited by how you want to use tags and collections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The benefit collections give you is grouping pages by a string key which gives you access to all group members' urls and other data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A new feature in version 0.11.0 is a universal filter for giving you &lt;a href="https://www.11ty.dev/docs/filters/collection-items/"&gt;previous and next items in a collection&lt;/a&gt;. By default, these are &lt;a href="https://www.11ty.dev/docs/collections/#sorting"&gt;sorted&lt;/a&gt; by file creation date which can be overridden.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/siakaramalegos/eleventy-data-tutorial/tree/2-collections"&gt;&lt;code&gt;2-collections&lt;/code&gt; branch&lt;/a&gt; of the repo, I created index pages for both the podcasts and posts, and added those index pages to the site's navbar, all using collections.&lt;/p&gt;

&lt;h3&gt;
  
  
  * Custom collections
&lt;/h3&gt;

&lt;p&gt;Tags are the most common way of creating collections, but you can actually create &lt;a href="https://www.11ty.dev/docs/collections/#advanced-custom-filtering-and-sorting"&gt;custom collections&lt;/a&gt; using JavaScript in your Eleventy config. &lt;a href="https://twitter.com/philhawksworth"&gt;Phil Hawksworth&lt;/a&gt; uses this feature in &lt;a href="https://www.hawksworx.com/"&gt;his blog&lt;/a&gt; to create a collection of the tags themselves as well as create a collection of all items in the blog folder, among other things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eleventy.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Assemble some collections&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tagList&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/site/_filters/getTagList.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getFilteredByGlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/site/blog/*.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cards&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See Phil's &lt;a href="https://github.com/philhawksworth/hawksworx.com/blob/fe1cfc2dfecea0b141b035f019cb315aaaeb02ef/.eleventy.js#L22-L31"&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template data
&lt;/h2&gt;

&lt;p&gt;So far, we've only been using the data supplied by Eleventy with only a few custom data elements that I snuck in while you weren't looking. 👀 Let's take a look at those now.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;/src/posts/my-first-post.md&lt;/code&gt;, I use &lt;a href="https://learnxinyminutes.com/docs/yaml/"&gt;YAML&lt;/a&gt; front matter to set a few data attributes for my page - the &lt;code&gt;title&lt;/code&gt;, which &lt;code&gt;layout&lt;/code&gt; to use, and which &lt;code&gt;tags&lt;/code&gt; should be applied to add this page to those collections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /src/posts/my-first-post.md&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;first&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;blog&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;post"&lt;/span&gt;
&lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;post.njk&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;posts'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="s"&gt;Bootcamp .NET npm branch Agile grep native senior. Database webpack&lt;/span&gt;
&lt;span class="s"&gt;pairing build tool pull request imagemagick. AWS injection OOP&lt;/span&gt;
&lt;span class="s"&gt;stack Dijkstra looks good to me Firefox bike-shedding scrum master.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We learned about &lt;code&gt;tags&lt;/code&gt; already; &lt;code&gt;layout&lt;/code&gt; is a similar special template data key in Eleventy which tells it which &lt;a href="https://www.11ty.dev/docs/layouts/"&gt;layout file&lt;/a&gt; to use for your page (found in a &lt;code&gt;/_includes/&lt;/code&gt; folder). Other &lt;a href="https://www.11ty.dev/docs/data-configuration/"&gt;special template data keys for templates&lt;/a&gt; include &lt;code&gt;permalink&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom data and the data hierarchy
&lt;/h2&gt;

&lt;p&gt;Finally, we come to custom data. In the example above, I set a &lt;code&gt;title&lt;/code&gt; attribute in my front matter. This is not data automatically supplied nor used by Eleventy. It is completely custom. In this case, I use it to populate both my webpage's &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; element and the primary heading, or &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;. Custom data you set in this manner is available directly in a template using the name you gave it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- /src/_includes/post.njk --&amp;gt;&lt;/span&gt;
--------
layout: layout.njk
--------

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{ title }}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
{{ content | safe }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eleventy uses a &lt;a href="https://www.11ty.dev/docs/data/#sources-of-data"&gt;data hierarchy&lt;/a&gt; so that you can set defaults or inheritance and then override them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Computed Data&lt;/li&gt;
&lt;li&gt;Front Matter Data in a Template&lt;/li&gt;
&lt;li&gt;Front Matter Data in Layouts&lt;/li&gt;
&lt;li&gt;Template Data Files&lt;/li&gt;
&lt;li&gt;Directory Data Files (and ascending Parent Directories)&lt;/li&gt;
&lt;li&gt;Global Data Files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In my example, we're using #2 in the hierarchy... and also #3 - you have to go to my highest-level layout to find it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- /src/_includes/layout.njk --&amp;gt;&lt;/span&gt;
--------
title: My default layout title
--------
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ title }}&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ...rest of html --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; set in &lt;code&gt;my-first-post.md&lt;/code&gt; overrides the &lt;code&gt;title&lt;/code&gt; set in the layout. If a &lt;code&gt;title&lt;/code&gt; attribute is missing, then the default one set in &lt;code&gt;layout.njk&lt;/code&gt; is used. Wicked smart!&lt;/p&gt;

&lt;p&gt;Now that we know about this data hierarchy, we can clean up some of our front matter by using a directory data file. Here's where we get a little muddy in our explanation since you can use the data hierarchy for template data too, not just custom data. In my &lt;code&gt;/posts/&lt;/code&gt; folder, I can create a file with the same name as the folder and with either a &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.11tydata.json&lt;/code&gt; or &lt;code&gt;.11tydata.js&lt;/code&gt; extension that applies that data to all the files (i.e., templates/pages) in that folder.&lt;/p&gt;

&lt;p&gt;We can use this to set the &lt;code&gt;layout&lt;/code&gt; file and the &lt;code&gt;posts&lt;/code&gt; tag to all the files in the &lt;code&gt;/posts/&lt;/code&gt; folder, then remove those from the individual post files' front matter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/src/posts/posts.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"post.njk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"posts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /src/posts/my-first-post.md&lt;/span&gt;
&lt;span class="s"&gt;--------&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My first blog post&lt;/span&gt;
&lt;span class="s"&gt;--------&lt;/span&gt;

&lt;span class="s"&gt;Bootcamp .NET npm branch Agile grep native senior. Database webpack&lt;/span&gt;
&lt;span class="s"&gt;pairing build tool pull request imagemagick. AWS injection OOP&lt;/span&gt;
&lt;span class="s"&gt;stack Dijkstra looks good to me Firefox bike-shedding scrum master.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, we're DRYing up the files! There's only one problem - the merge messed up our content tags. Our second blog post added a &lt;code&gt;JavaScript&lt;/code&gt; content tag. That overrode the &lt;code&gt;posts&lt;/code&gt; tag. Luckily, we can use &lt;a href="https://www.11ty.dev/docs/data-deep-merge/"&gt;data deep merge&lt;/a&gt; to instead merge data that is an object or array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eleventy.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;eleventyConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setDataDeepMerge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our posts index page, &lt;code&gt;/src/posts/index.njk&lt;/code&gt;, is showing up in our posts collection list because it's inheriting the tag from the directory. We can fix this by renaming it &lt;code&gt;posts.njk&lt;/code&gt; and moving it up to the &lt;code&gt;/src/&lt;/code&gt; directory. This move preserves the original routing due to the magic of Eleventy's directory- and file-based build method.&lt;/p&gt;

&lt;p&gt;You can find the code for this section in the &lt;a href="https://github.com/siakaramalegos/eleventy-data-tutorial/tree/3-data-hierarchy"&gt;&lt;code&gt;3-data-hierarchy&lt;/code&gt; branch&lt;/a&gt;. This was just one example of using the data hierarchy - you should definitely check out the &lt;a href="https://www.11ty.dev/docs/data/#sources-of-data"&gt;data hierarchy docs&lt;/a&gt; to learn about the other options too. I could spend loads of time explaining the hierarchy, but that would make it seem like the most important concept in all of Eleventy. Just know that it gives you the ability to inherit or scope data as you please. So if you need more precision on managing inheritance or scope, dive down on that concept more.&lt;/p&gt;

&lt;h3&gt;
  
  
  What custom data is even available in a view?
&lt;/h3&gt;

&lt;p&gt;You're trying to build a page, but you can't figure out "where" your new variable that you thought you set. I haven't found a way to log everything available in a page - something akin to &lt;code&gt;self&lt;/code&gt; or &lt;code&gt;this&lt;/code&gt;. I have found a way to hack this with collections. For each item in a collection, you can &lt;code&gt;log&lt;/code&gt; the &lt;code&gt;item.data&lt;/code&gt; which will show the special Eleventy data attributes as well as your own custom ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// package.json data&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post.njk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// Look! It's our custom title attribute:&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My second blog post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="nx"&gt;T20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;27.709&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;inputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/posts/my-second-post.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;fileSlug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-second-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;filePathStem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-second-post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/my-second-post/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site/posts/my-second-post/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;podcasts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;JavaScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you know of a way to do this more easily, please share, and I'll update this post!&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Data with a capital D
&lt;/h2&gt;

&lt;p&gt;The data hierarchy and examples I gave above are great for providing smart defaults, inheritance, and merging basic page data. But what about what I like to call "Data with a capital D"? Do you need to render something that is dependent on a large data object or array? Do you need to fetch data from another URL before statically rendering it? Do you need to manipulate some data to make it easier to use?&lt;/p&gt;

&lt;p&gt;The data hierarchy technically handles that too, but we usually use either global data files, or maybe directory- or file-specific data files. Three examples I have implemented in Eleventy include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Showing my upcoming and past speaking events on &lt;a href="https://sia.codes/speaking/"&gt;sia.codes/speaking&lt;/a&gt; based on global data files &lt;code&gt;talks.js&lt;/code&gt; and &lt;code&gt;events.js&lt;/code&gt; (events can have many talks and talks can be repeated at different events).&lt;/li&gt;
&lt;li&gt;Fetching webmentions for all my blog posts on sia.codes to show them at the bottom of an article with re-builds triggered every 4 hours to pull in new ones (&lt;a href="https://sia.codes/posts/webmentions-eleventy-in-depth/"&gt;example article with webmentions&lt;/a&gt; at the bottom).&lt;/li&gt;
&lt;li&gt;Organizing courses, modules, and lessons in a new Jamstack course management system. (I hope to release an open source version soon!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll focus on the &lt;a href="https://www.11ty.dev/docs/data-global/"&gt;global data file&lt;/a&gt; method here. Data in files located in a &lt;code&gt;/_data/&lt;/code&gt; directory is globally accessible in all pages using the filename. Your files can either be JSON, or you can use &lt;code&gt;module.exports&lt;/code&gt; from a JavaScript file (actually, it can handle &lt;a href="https://www.11ty.dev/docs/data-custom/"&gt;more data types&lt;/a&gt; if you don't like JavaScript 😅). In our repo, &lt;a href="https://github.com/siakaramalegos/eleventy-data-tutorial/tree/4-big-d-data"&gt;branch &lt;code&gt;4-big-d-data&lt;/code&gt;&lt;/a&gt;, I created a dogs data file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /src/_data/dogs.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jack Russell terrier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;favoritePasttime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;finding hidey holes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stinkLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Priscilla&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Australian shepherd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;favoritePasttime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;starting farty parties&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stinkLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I then log &lt;code&gt;dogs&lt;/code&gt; from any of my template/page files, I can see that exact data in my terminal. In this case, it is an array, so I can loop over it to render my dog info:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- /src/dogs.njk --&amp;gt;&lt;/span&gt;
--------
layout: layout.njk
title: Pup party
tags: ['nav']
--------

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My doggos&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Much floof. Much fart.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  {% for dog in dogs %}
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    {{ dog.name }} is a/an {{ dog.breed }} and likes {{ dog.favoritePasttime }}.
    {{ dog.name }}'s stink level from 1-5 is a {{ dog.stinkLevel }}.
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  {% endfor %}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- TODO: delete random logs --&amp;gt;&lt;/span&gt;
{{ dogs | log }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you needed to fetch data, you could use a JavaScript file and &lt;a href="https://www.11ty.dev/docs/data-js/"&gt;return an async function&lt;/a&gt; for your &lt;code&gt;module.exports&lt;/code&gt;. It's a bit complex, but my &lt;a href="https://github.com/siakaramalegos/sia.codes-eleventy/blob/master/_data/webmentions.js"&gt;webmentions code&lt;/a&gt; is an example of this. If you're interested in the details, I wrote up a &lt;a href="https://sia.codes/posts/webmentions-eleventy-in-depth/"&gt;full tutorial&lt;/a&gt; on adding webmentions to an Eleventy site.&lt;/p&gt;

&lt;p&gt;If you want to manipulate data before using it, you could "just use JavaScript". For example, in my online course project, I import my course&amp;gt;module&amp;gt;lesson hierarchy data from &lt;code&gt;/_data/courses.js&lt;/code&gt; into another &lt;code&gt;/_data/lessonPrevNext.js&lt;/code&gt; file to manually set a previous and next lesson since the sort order is a bit more nuanced. I wanted one source of truth, but needed something easier to work with in my views. &lt;a href="https://www.11ty.dev/docs/data-computed/"&gt;Computed data&lt;/a&gt; is another new feature in 0.11.0 that you can use as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Eleventy is a powerful static site generator with a lot of flexibilty in how to handle data. It's so flexible that sometimes your options for architecting data can be overwhelming. The primary ways I use data in developing Eleventy apps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;page data&lt;/strong&gt; - includes attributes like url and file slug&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;collections&lt;/strong&gt; - groups of pages/templates often to generate a list of links&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;template data using the data hierarchy&lt;/strong&gt; - special template data like layout, permalinks, tags, and dates as well as custom "small" data like titles and whether a page should be included in a nav bar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;global "big" data (though scope can be narrowed)&lt;/strong&gt; - larger, more complex data that is easier to manage in a separate file and can also be fetched asynchronously (also technically still uses the data hieararchy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To see your data, use the &lt;a href="https://www.11ty.dev/docs/filters/log/"&gt;&lt;code&gt;log&lt;/code&gt;&lt;/a&gt; universal filter.&lt;/p&gt;

&lt;p&gt;Have you used data in a unique way in your Eleventy sites? If so, I'd love to see your examples!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Special thanks to &lt;a href="https://twitter.com/SpeakToChris"&gt;Chris Guzman&lt;/a&gt;, &lt;a href="https://twitter.com/aaronpeters"&gt;Aaron Peters&lt;/a&gt;, &lt;a href="https://twitter.com/davidrhoden"&gt;David Rhoden&lt;/a&gt;, and &lt;a href="https://twitter.com/philhawksworth"&gt;Phil Hawksworth&lt;/a&gt; for giving me their time and feedback!&lt;/p&gt;

&lt;p&gt;I apologize for the cover image abomination. It is a mash up of two great images on Unsplash by &lt;a href="https://unsplash.com/photos/Mmz_ncRz4ZQ"&gt;Mikell Darling&lt;/a&gt; and &lt;a href="https://unsplash.com/photos/TZj-urJKRao"&gt;Yingchih&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/architecting-data-in-eleventy/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Vintage Bundles talk at Magnolia JS</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Tue, 21 Apr 2020 21:03:19 +0000</pubDate>
      <link>https://dev.to/thegreengreek/vintage-bundles-talk-at-magnolia-js-136e</link>
      <guid>https://dev.to/thegreengreek/vintage-bundles-talk-at-magnolia-js-136e</guid>
      <description>&lt;p&gt;More developers are starting to understand that web performance matters. From higher mobile search rankings to bottom-line revenue impacts, performance can make or break your web app. However, fixing performance can feel like a quagmire of expert-level nuanced understanding on so many topics. What would you think if I told you you could cut your JavaScript bundle size up to 50% by doing one thing only? Nearly 90% of worldwide web traffic runs on modern browsers, but we're transpiling all of our JavaScript down to ES5. That transpilation has a cost.&lt;/p&gt;

&lt;p&gt;In this talk, we'll learn about differential serving, or serving modern bundles to modern browsers and legacy, transpiled bundles to older browsers. We'll talk about strategies, what to watch out for, and how to implement it using webpack. This talk is framework agnostic, and it's best if you have at least a basic understand of JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://magnoliajs.com/"&gt;Magnolia JS&lt;/a&gt; was my second virtual conference, and I had a blast participating. This video is the full day 1 video, and you can find my talk at 2:51:00. Check out the other talks that day too! Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Qkc8p4D6JM0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/vintage-bundles-magnolia/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Responsive, Performant Images for the Web</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Fri, 17 Apr 2020 20:55:34 +0000</pubDate>
      <link>https://dev.to/thegreengreek/responsive-performant-images-for-the-web-c00</link>
      <guid>https://dev.to/thegreengreek/responsive-performant-images-for-the-web-c00</guid>
      <description>&lt;p&gt;Want to learn how to make your images more responsive and more performant? Haven't gotten a chance to read that book/article/doc on web performance for images yet?&lt;/p&gt;

&lt;p&gt;I spoke at my first virtual conference, PerfMatters Conf, and luckily they recorded it. This talk is a great intro into all things images for the web. Enjoy!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Images account for 50% of the bytes downloaded to load a website. How can you make sure that your users only download the smallest image necessary while preserving image quality? In this talk, we'll focus on the underlying concepts in HTML and CSS for serving responsive images, which you can take with you no matter which tool you use. Which file formats suit which image types best? How can you use art direction in images to show the best image for a viewport layout? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XecoxR1ckbc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/responsive-images-perf-matters-video/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>webdev</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>How to build a website in 2020</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Tue, 11 Feb 2020 15:07:09 +0000</pubDate>
      <link>https://dev.to/thegreengreek/how-to-build-a-website-in-2020-4f0m</link>
      <guid>https://dev.to/thegreengreek/how-to-build-a-website-in-2020-4f0m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Buy a domain. You might have a problem if you already have 20 domains waiting to be used, but that's okay. Feel free to buy more domains. You never know when you might need that perfect domain name. P.S. &lt;a href="//https**://zeit.co/"&gt;zeit.co&lt;/a&gt; has a great &lt;a href="https://zeit.co/domains"&gt;domain search tool&lt;/a&gt; with hacks. Now I've just enabled your habit. You're welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2a&lt;/strong&gt;: Engage in Twitter debates about how JavaScript is ruining the web and which static site generators are best. Do this for 4 months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Take an &lt;a href="https://frontendmasters.com/courses/design-for-developers/"&gt;entire course to get better at design&lt;/a&gt;. Spend 5 hours generating an &lt;a href="https://codepen.io/nolasia/pen/PoomRqN"&gt;HSLa exploration CodePen&lt;/a&gt; to visualize something that already exists. Bemoan color systems and values. Read a shout-out tweet about best conference talks that happen to be about &lt;a href="https://www.youtube.com/watch?v=UbTZ9qSqimo&amp;amp;feature=youtu.be"&gt;React and color&lt;/a&gt;. Find &lt;a href="https://colorlab.dev/"&gt;a tool that does it way better than you&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2b&lt;/strong&gt;: Eventually some rando will tell you about &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt;, and you're like "sounds brilliant". Repeat step 2a.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Clone that &lt;a href="https://github.com/11ty/eleventy-base-blog"&gt;starter repo&lt;/a&gt; and fire it up. Waste 17 hours trying to figure out how to implement some esoteric design feature no one will notice. "Fuck, it's midnight on a Friday, why am I still doing this?" On Monday, "add a circle".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Let's do dark mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: (Six hours later) Let's not do dark mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Look at other people's sites in envy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8&lt;/strong&gt;: Write the actual content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 9&lt;/strong&gt;: Join the &lt;a href="https://www.youtube.com/watch?v=ZDjIFGfrQKw"&gt;Learn with Jason livestream on variable fonts&lt;/a&gt;. "Oh that's cool, must add."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10&lt;/strong&gt;: Edit the color scheme 20 more times. Play with the design and variable fonts. Open Firefox because the font dev tools are 🔥. Go blind because Firefox oversaturated the colors. Recover from blindness, and edit the colors again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11&lt;/strong&gt;: Sees how CSS Tricks implemented dark mode and admire how well they did it. Silently close the tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 12&lt;/strong&gt;: Launch! Ugh, non-responsive iframes and bad break points. Run &lt;a href="https://www.deque.com/axe/"&gt;Axe&lt;/a&gt;. Feel like a terrible person. Fix issues (and edit colors again).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 13&lt;/strong&gt;: 5 months later, write a blog post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note to self: next time, just hire a designer.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/posts/how-to-build-a-website/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>design</category>
    </item>
    <item>
      <title>Day 26 of⚡️ #30DaysOfWebPerf ⚡️: Tasks</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Wed, 18 Dec 2019 15:21:06 +0000</pubDate>
      <link>https://dev.to/thegreengreek/day-26-of-30daysofwebperf-tasks-5e9b</link>
      <guid>https://dev.to/thegreengreek/day-26-of-30daysofwebperf-tasks-5e9b</guid>
      <description>&lt;p&gt;Liquid error: internal&lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      So what are the tasks?&lt;br&gt;&lt;br&gt;- Minify/uglify JS, CSS, and HTML (build)&lt;br&gt;- Compress using gzip or brotli (build or deploy, it depends)&lt;br&gt;- Set caching headers (deploy)&lt;br&gt;- Code splitting (build)&lt;br&gt;- Lazy and/or dynamic loading (codebase)&lt;br&gt;- Tree shaking (codebase and build)&lt;br&gt;- etc.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:17 PM - 18 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1207319008820760577" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1207319008820760577" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1207319008820760577" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__video-wrapper"&gt;
        &lt;div class="ltag__twitter-tweet__media--video-preview"&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9fwPdao5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/tweet_video_thumb/EMFCPkwWoAIKzIC.jpg" alt="unknown tweet media content"&gt;
          &lt;img src="/assets/play-butt.svg" class="ltag__twitter-tweet__play-butt" alt="Play butt"&gt;
        &lt;/div&gt;
        &lt;div class="ltag__twitter-tweet__video"&gt;
          
            
          
        &lt;/div&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      It's a lot to learn - too much for one tweet thread. &lt;br&gt;&lt;br&gt;Start with your measurement tools (Day 1) to see what your worst offenders are, and prioritize setting up those tasks first. &lt;br&gt;&lt;br&gt;Breaking down the problem this way makes it much more manageable. 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:17 PM - 18 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1207319020913012739" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1207319020913012739" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1207319020913012739" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      [gif alt: small child throwing adult in martial arts class]
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:17 PM - 18 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1207319023303741447" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1207319023303741447" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1207319023303741447" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;





&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Day 25 of⚡️ #30DaysOfWebPerf ⚡️: Jank</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Tue, 17 Dec 2019 15:35:14 +0000</pubDate>
      <link>https://dev.to/thegreengreek/day-25-of-30daysofwebperf-jank-35p6</link>
      <guid>https://dev.to/thegreengreek/day-25-of-30daysofwebperf-jank-35p6</guid>
      <description>&lt;p&gt;Liquid error: internal&lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      JavaScript can cause jank when we have long running scripts on the main thread. We theoretically have about 16 ms to process an event, but in reality the browser needs some of that time, so we only have about 10 ms.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:29 PM - 17 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206959708701184000" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206959708701184000" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206959708701184000" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Styles &amp;amp; animations also cause jank. The render pipeline is more expensive the further upstream you affect something:&lt;br&gt;&lt;br&gt;JS &amp;gt; Calculate &amp;gt; Layout &amp;gt; Paint &amp;gt; Composite&lt;br&gt;&lt;br&gt;opacity &amp;amp; transform affect Composite, so they are cheap to use vs width which affects Layout &lt;a href="https://t.co/A49pVhSMD7"&gt;csstriggers.com&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:29 PM - 17 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206959709485518849" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206959709485518849" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206959709485518849" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      More resources: &lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/DJ1xKLee0H"&gt;afasterweb.com/2015/08/29/wha…&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/JslAVDbFTe"&gt;developers.google.com/web/fundamenta…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:29 PM - 17 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206959710890549248" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206959710890549248" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206959710890549248" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;





&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>webdev</category>
      <category>performance</category>
      <category>css</category>
    </item>
    <item>
      <title>Day 24 of⚡️ #30DaysOfWebPerf ⚡️: Timing APIs</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Mon, 16 Dec 2019 21:10:57 +0000</pubDate>
      <link>https://dev.to/thegreengreek/day-24-of-30daysofwebperf-timing-apis-4986</link>
      <guid>https://dev.to/thegreengreek/day-24-of-30daysofwebperf-timing-apis-4986</guid>
      <description>&lt;p&gt;Liquid error: internal&lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;
    &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__two-pics"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u-QwXnBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EL7-4eLX0AIwLJy.jpg" alt="unknown tweet media content"&gt;
    &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Luckily, the User Timing API exists just for this purpose!&lt;br&gt;&lt;br&gt;You set "marks" as points in time to reference, then you can measure the difference between various "marks" with a "measure" to get a duration.&lt;br&gt;&lt;br&gt;This API is available for 95% of users globally today. 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      21:06 PM - 16 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206682003736813568" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206682003736813568" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206682003736813568" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      The Navigation and Resource Timing APIs are similar and give you detailed data on the document and its assets.&lt;br&gt;&lt;br&gt;To preview the data, load a page and in the console type, for example:&lt;br&gt;&lt;br&gt;performance.getEntries()&lt;br&gt;performance.getEntriesByType('resource')&lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/pobEP8frHW"&gt;youtube.com/watch?v=BAeghS…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      21:06 PM - 16 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206682005762646016" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206682005762646016" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206682005762646016" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BAeghSziuxQ"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_0bh_OP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1057362975332290560/vsMsx9u4_normal.jpg" alt="Sia Karamalegos profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Sia Karamalegos
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/thegreengreek"&gt;@thegreengreek&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Here are some of my favorite resources for learning both: &lt;br&gt;&lt;a href="https://t.co/lfA76qtFQ1"&gt;developers.google.com/web/fundamenta…&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;a href="https://t.co/6naWJLbNpX"&gt;keycdn.com/blog/user-timi…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      21:06 PM - 16 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1206682006731575297" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1206682006731575297" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1206682006731575297" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;





&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Day 23 of⚡️ #30DaysOfWebPerf ⚡️: Culture of Performance</title>
      <dc:creator>Sia Karamalegos</dc:creator>
      <pubDate>Fri, 13 Dec 2019 17:47:59 +0000</pubDate>
      <link>https://dev.to/thegreengreek/day-23-of-30daysofwebperf-culture-of-performance-5g31</link>
      <guid>https://dev.to/thegreengreek/day-23-of-30daysofwebperf-culture-of-performance-5g31</guid>
      <description>&lt;p&gt;For Day 23:&lt;/p&gt;

&lt;p&gt;Liquid error: internal&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://sia.codes/"&gt;sia.codes&lt;/a&gt;. Head over there if you like this post and want to read others like it, or sign up for my &lt;a href="https://buttondown.email/sia.codes"&gt;newsletter&lt;/a&gt; to be notified of new posts!&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>webdev</category>
      <category>performance</category>
      <category>culture</category>
    </item>
  </channel>
</rss>
