{
  "version": "https://jsonfeed.org/version/1.1",
  "user_comment": "This is a blog feed. You can add this to your feed reader using the following URL: https://virga.frontendweekly.tokyo/feed.json",
  "title": "Virga",
  "home_page_url": "https://virga.frontendweekly.tokyo",
  "feed_url": "https://virga.frontendweekly.tokyo/feed.json",
  "description": "Virga is a minimum Eleventy starter kit for those who love to customize for your own needs. It is based on Hylia Starter Kit created by Andy Bell. And I'm also using it as my blog about Eleventy.",
  "favicon": "https://virga.frontendweekly.tokyo/favicon.ico",
  "authors": [
    {
      "name": "Yuya Saito",
      "url": "https://virga.frontendweekly.tokyo"
    }
  ],
  "items": [
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2021-01-28-lighthouse-score-is-in/",
      "url": "https://virga.frontendweekly.tokyo/posts/2021-01-28-lighthouse-score-is-in/",
      "title": "Lighthouse score is in",
      "summary": "A short story about displaying Lighthouse scores using Speedlify",
      "content_html": "<p>I regrettably forgot who actually said this: “Performance optimization is not an event, it’s process.” This always stuck in my mind when it comes to perf.</p>\n<p>When it comes to process, it’s important to monitor. Seeing the change reminds us.</p>\n<p>There are lots of ways to do this, but I like lightweight solution of <a href=\"https://www.zachleat.com/web/speedlify/\">Speedlify</a> which is created by Zach Leatherman.</p>\n<p>And he explains how to use it at “<a href=\"https://www.zachleat.com/web/lighthouse-in-footer/\">I added Lighthouse Scores to my Site’s Footer and You Can Too</a>”</p>\n<p>I did follow his instruction, and it went as smoothly as expected.<br />\nI now have Lighthouse scores on my footer.</p>\n<p>One thing I derailed from his instruction is that I didn’t use his web components. I went with server-side way.<br />\nI borrowed a bit of code from his web components.</p>\n<p>I spend some time on CSS. This is the second most complicated style in Virga, next to typography(which I’m thinking about simplify).<br />\nI’m not sure how long I’m going to keep this style, but I like how it looks. I don’t like the code…</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2021-01-28T14:27:40Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2021-01-14-optimizing-images-with-eleventy/",
      "url": "https://virga.frontendweekly.tokyo/posts/2021-01-14-optimizing-images-with-eleventy/",
      "title": "Optimizing Images with Eleventy and GitHub Actions",
      "summary": "A story about optimizing image with Transforms and GitHub Actions",
      "content_html": "<figure class=\"o-blockquote\">\n<blockquote cite=\"https://blog.codinghorror.com/performance-is-a-feature/\">\n<p>To me, performance is a feature, and I simply like using fast websites more than slow websites, so naturally I’m going to build a site that I would want to use.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Jeff Atwood, <a href=\"https://blog.codinghorror.com/performance-is-a-feature/\">“Performance is a Feature”</a></figcaption>\n</figure>\n<p>This statement from Jeff Atwood had gotten me into the <strong>#perfmatters</strong> initiative which was started by many Googlers. I still love faster web.</p>\n<p>Often, JavaScript gets blame on this performance, and I do think it is the one of the biggest hurdle.<br />\nI don’t have any client side JavaScript working on Virga, so what’s next on the list for the change of the slowness?</p>\n<p>Images.</p>\n<p>I don’t have those too many on Virga, but I sometime do. And I haven’t done anything to images for performance optimization.</p>\n<p><code>&lt;img&gt;</code> element is a veteran of HTML. It’s been in HTML since I had started to write HTML, but it has gone through many changes.<br />\nIt had introduced <code>srcset</code> attribute and image format like <code>png</code>, <code>webp</code> and the latest one <code>avif</code>. Moreover, <code>&lt;img&gt;</code> even has a new sibling <code>&lt;picture&gt;</code>.</p>\n<p>What a journey it must’ve been.</p>\n<p>And this is where my journey begins.<br />\nThis is a story about implementing performance optimization for images using Eleventy and GitHub Actions.</p>\n<h2 id=\"the-mighty-picture-element\">The mighty <code>&lt;picture&gt;</code> element <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-14-optimizing-images-with-eleventy/#the-mighty-picture-element\">#</a></h2>\n<p>Some may think <code>&lt;div&gt;</code> has special power, and it is only element you’d use from HTML.<br />\nThose who resonated with that sentence, meet <code>&lt;picture&gt;</code>.</p>\n<p>Now that <code>webp</code> and the more recently <code>avif</code> support on the way, it may not be performant enough using <code>jpeg</code>, <code>png</code> and <code>gif</code> anymore.</p>\n<p>How would I use those newish image formats while keeping backward compatibility?<br />\nI’m pretty sure JavaScript can do it, but why would I need to have JavaScript to do it, when I can do it using HTML?</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>picture</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- load avif if supported --></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>this-image-is.avif<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/avif<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- load webp if supported --></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>this-image-is.webp<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/webp<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- fallback for `source` and use attributes for presentation --></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>this-image-is.jpg<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>You<span class=\"token punctuation\">'</span>d better not omit alt<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>picture</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>When it compares with <code>&lt;div&gt;</code> or <code>&lt;span&gt;</code>, <code>&lt;picture&gt;</code> looks complicated, but above snippet isn’t a complete “picture”.</p>\n<p>Well, <code>&lt;picture&gt;</code> doesn’t do much, actually. The true power resides with <code>srcset</code> and <code>sizes</code>.</p>\n<p>The above snippet demonstrates the power of <code>srcset</code>, let’s look at what <code>sizes</code> has in its sleeve.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-480w.jpg 480w,<br />             elva-fairy-800w.jpg 800w<span class=\"token punctuation\">\"</span></span><br />     <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 600px) 480px,<br />            800px<span class=\"token punctuation\">\"</span></span><br />     <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-800w.jpg<span class=\"token punctuation\">\"</span></span><br />     <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Elva dressed as a fairy<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This snippet comes from <a href=\"https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images\">“Responsive images” at MDN</a>.</p>\n<p><code>sizes</code> looks complicated and even though MDN says it’s not that complicated, it is.</p>\n<p><code>(max-width: 600px)</code> part is called a media condition and “describes a possible state that the screen can be in. In this case, we are saying ‘when the viewport width is 600 pixels or less’.”, according to MDN.</p>\n<p><code>480px</code> which is right after a <em>space</em> is “The width of the slot the image will fill when the media condition is true.”</p>\n<p>And I guess that <code>800px</code>, one that never mentioned and right after a comma, is the width of the slot the image will fill when the media condition is FALSE.</p>\n<p><code>sizes</code> attribute determines which size of images should be used with in the viewport.</p>\n<p>Let’s invert this, so it should make it a bit more understandable…</p>\n<p>When we don’t want to use over-sized images for a small screen, use <code>sizes</code> to choose the appropriate image size.</p>\n<p>So that means, I need to use <code>sizes</code> for every image formats.</p>\n<p>Let’s combine both of snippets to unveil the true power.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>picture</span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- load avif if supported --></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-480w.avif 480w,<br />                  elva-fairy-800w.avif 800w<span class=\"token punctuation\">\"</span></span><br />          <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 600px) 480px,<br />                 800px<span class=\"token punctuation\">\"</span></span> <br />          <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/avif<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- load webp if supported --></span><br />  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-480w.webp 480w,<br />                  elva-fairy-800w.webp 800w<span class=\"token punctuation\">\"</span></span><br />          <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 600px) 480px,<br />                 800px<span class=\"token punctuation\">\"</span></span> <br />          <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/webp<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />  <span class=\"token comment\">&lt;!-- fallback for `source` and use attributes for presentation --></span><br />\t<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-480w.jpg 480w,<br />\t             elva-fairy-800w.jpg 800w<span class=\"token punctuation\">\"</span></span><br />\t     <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 600px) 480px,<br />\t            800px<span class=\"token punctuation\">\"</span></span><br />\t     <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>elva-fairy-800w.jpg<span class=\"token punctuation\">\"</span></span><br />\t     <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Elva dressed as a fairy<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>picture</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This is powerful but surely a big chunk of codes.<br />\nLet’s not write this by hand.</p>\n<hr />\n<p>I love markdown syntax for its simplicity.</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token url\"><span class=\"token operator\">!</span>[<span class=\"token content\">Elva dressed as a fairy</span>](<span class=\"token url\">elva-fairy.jpg</span>)</span></code></pre>\n<p>Let’s turn this into the monstrously huge chunk of <code>&lt;picture&gt;</code>.</p>\n<h2 id=\"using-11tyeleventy-img-with-eleventy-transforms\">Using <code>@11ty/eleventy-img</code> with Eleventy Transforms <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-14-optimizing-images-with-eleventy/#using-11tyeleventy-img-with-eleventy-transforms\">#</a></h2>\n<p><a href=\"https://www.npmjs.com/package/@11ty/eleventy-img\"><code>@11ty/eleventy-img</code></a> is a plugin for Eleventy which uses the <a href=\"https://sharp.pixelplumbing.com/\">sharp</a> image processor and outputs multiple sizes, save multiple formats, cache remote images locally.</p>\n<p>Examples at <a href=\"https://www.11ty.dev/docs/plugins/image/\">Eleventy Doc</a> shows using it with Shortcodes, but I only use images in one layout and want to keep using Markdown syntax, I’ll use the plugin at <a href=\"https://www.11ty.dev/docs/config/#transforms\">Transforms</a>.</p>\n<p><code>@11ty/eleventy-img</code> is a simple yet very powerful plugin.<br />\nAfter about an hour of trial and error, I’ve settled with this:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> metadata <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">Image</span><span class=\"token punctuation\">(</span>imagePath<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><br />\twidths<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token number\">1500</span><span class=\"token punctuation\">,</span> <span class=\"token number\">750</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />\tformats<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'avif'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'webp'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'png'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />\turlPath<span class=\"token operator\">:</span> <span class=\"token string\">'/images/'</span><span class=\"token punctuation\">,</span><br />\toutputDir<span class=\"token operator\">:</span> <span class=\"token string\">'./11ty/images/generated'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p><code>metadata</code> will yield:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br />  avif<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br />    <span class=\"token punctuation\">{</span><br />      format<span class=\"token operator\">:</span> 'avif'<span class=\"token punctuation\">,</span><br />      width<span class=\"token operator\">:</span> <span class=\"token number\">750</span><span class=\"token punctuation\">,</span><br />      height<span class=\"token operator\">:</span> <span class=\"token number\">1168</span><span class=\"token punctuation\">,</span><br />      filename<span class=\"token operator\">:</span> 'ce28e207<span class=\"token number\">-750</span>.avif'<span class=\"token punctuation\">,</span><br />      outputPath<span class=\"token operator\">:</span> '11ty/images/generated/ce28e207<span class=\"token number\">-750</span>.avif'<span class=\"token punctuation\">,</span><br />      url<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.avif'<span class=\"token punctuation\">,</span><br />      sourceType<span class=\"token operator\">:</span> 'image/avif'<span class=\"token punctuation\">,</span><br />      srcset<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.avif 750w'<span class=\"token punctuation\">,</span><br />      size<span class=\"token operator\">:</span> <span class=\"token number\">23321</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  webp<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br />    <span class=\"token punctuation\">{</span><br />      format<span class=\"token operator\">:</span> 'webp'<span class=\"token punctuation\">,</span><br />      width<span class=\"token operator\">:</span> <span class=\"token number\">750</span><span class=\"token punctuation\">,</span><br />      height<span class=\"token operator\">:</span> <span class=\"token number\">1168</span><span class=\"token punctuation\">,</span><br />      filename<span class=\"token operator\">:</span> 'ce28e207<span class=\"token number\">-750</span>.webp'<span class=\"token punctuation\">,</span><br />      outputPath<span class=\"token operator\">:</span> '11ty/images/generated/ce28e207<span class=\"token number\">-750</span>.webp'<span class=\"token punctuation\">,</span><br />      url<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.webp'<span class=\"token punctuation\">,</span><br />      sourceType<span class=\"token operator\">:</span> 'image/webp'<span class=\"token punctuation\">,</span><br />      srcset<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.webp 750w'<span class=\"token punctuation\">,</span><br />      size<span class=\"token operator\">:</span> <span class=\"token number\">37634</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  png<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br />    <span class=\"token punctuation\">{</span><br />      format<span class=\"token operator\">:</span> 'png'<span class=\"token punctuation\">,</span><br />      width<span class=\"token operator\">:</span> <span class=\"token number\">750</span><span class=\"token punctuation\">,</span><br />      height<span class=\"token operator\">:</span> <span class=\"token number\">1168</span><span class=\"token punctuation\">,</span><br />      filename<span class=\"token operator\">:</span> 'ce28e207<span class=\"token number\">-750</span>.png'<span class=\"token punctuation\">,</span><br />      outputPath<span class=\"token operator\">:</span> '11ty/images/generated/ce28e207<span class=\"token number\">-750</span>.png'<span class=\"token punctuation\">,</span><br />      url<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.png'<span class=\"token punctuation\">,</span><br />      sourceType<span class=\"token operator\">:</span> 'image/png'<span class=\"token punctuation\">,</span><br />      srcset<span class=\"token operator\">:</span> '/images/ce28e207<span class=\"token number\">-750</span>.png 750w'<span class=\"token punctuation\">,</span><br />      size<span class=\"token operator\">:</span> <span class=\"token number\">175924</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">]</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>By looking at this output from the plugin, I can see what I’d need to construct <code>&lt;picture&gt;</code> and its siblings.<br />\nSince I’ve already had an Eleventy Transform for enhancing an article, I’m going to use it.</p>\n<p>Transforms can modify a template’s output. I’d like to think of it as a post-processing tool in Eleventy.<br />\nSo for an article, a markdown file is used to build an HTML file, Transforms will take that output(the HTML file) and modify it.</p>\n<p>By using this, I can “transform” this:</p>\n<pre class=\"language-markdown\"><code class=\"language-markdown\"><span class=\"token url\"><span class=\"token operator\">!</span>[<span class=\"token content\">Site flow for Virga</span>](<span class=\"token url\">elva-fairy.jpg</span>)</span></code></pre>\n<p>into</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>picture</span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/avif<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/images/ddf2e4b9-558.avif 558w<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 768px) 100vw, 768px<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/webp<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/images/ddf2e4b9-558.webp 558w<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 768px) 100vw, 768px<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>source</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>image/png<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/images/ddf2e4b9-558.png 558w<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">sizes</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>(max-width: 768px) 100vw, 768px<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br />    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>/images/ddf2e4b9-558.png<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Site flow for Virga<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">title</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>This is a site flow for Varga<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">loading</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>lazy<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">decoding</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>async<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">width</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>558<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">height</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>678<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>picture</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>If I needed more granular control how the final HTML turns out to be, I should use Shortcodes.</p>\n<p>Now that I’m satisfied with my initial attempt for this Transform, I’ll move it to <a href=\"https://github.com/frontendweekly/molle\">MOLLE</a> for finalizing it.</p>\n<h2 id=\"automatic-optimization-for-images-by-github-action\">Automatic optimization for images by GitHub Action <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-14-optimizing-images-with-eleventy/#automatic-optimization-for-images-by-github-action\">#</a></h2>\n<p>I can always compress images at local using trusty ImageAlpha and ImageOptim. Or <a href=\"https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli\">Squoosh CLI</a> which can “optimize” webp.</p>\n<p>If I have an image on every article, then I would remember doing the optimization on local, but I don’t. So let’s automate it using <a href=\"https://calibreapp.com/\">calibreapp/image-actions</a>.</p>\n<p>I have previously worked with GitHub Action. Let’s say I did not have a good time back then.<br />\nLong story short, it is pretty difficult to test the action. For example, when I trigger GitHub Action by a pull request or push to the repository, I have to do it.<br />\nMy last attempt was scheduling deploy, so it was particularly difficult.</p>\n<p>And there is always smart folk on Internet, <a href=\"https://github.com/nektos/act\">nektos/act</a> can “[r]un your GitHub Actions locally 🚀”.<br />\nThis tool seems like a godsend for me.</p>\n<p>After installing Act via Homebrew, I run <code>act -g</code> which draws workflows:</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">act -g<br />╭──────────────────────────╮<br />│ calibreapp/image-actions                  │<br />╰──────────────────────────╯</code></pre>\n<p>Oh, for the workflow, I did copy and paste from <a href=\"https://github.com/calibreapp/image-actions/blob/main/README.md#combined-workflow\">README</a>.</p>\n<p>So I think it looks good so far, then I run <code>act -n</code> which is dry run.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span> 🚀  Start <span class=\"token assign-left variable\">image</span><span class=\"token operator\">=</span>node:12.6-buster-slim<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   🐳  docker run <span class=\"token assign-left variable\">image</span><span class=\"token operator\">=</span>node:12.6-buster-slim <span class=\"token assign-left variable\">entrypoint</span><span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"/usr/bin/tail\"</span> <span class=\"token string\">\"-f\"</span> <span class=\"token string\">\"/dev/null\"</span><span class=\"token punctuation\">]</span> <span class=\"token assign-left variable\">cmd</span><span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span> ⭐  Run Checkout Branch<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   ✅  Success - Checkout Branch<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span> ⭐  Run Compress Images<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   ☁  <span class=\"token function\">git</span> clone <span class=\"token string\">'https://github.com/calibreapp/image-actions'</span> <span class=\"token comment\"># ref=main</span><br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   🐳  docker run <span class=\"token assign-left variable\">image</span><span class=\"token operator\">=</span>ghcr.io/calibreapp/image-actions/image-actions:main <span class=\"token assign-left variable\">entrypoint</span><span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token assign-left variable\">cmd</span><span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   ✅  Success - Compress Images<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span> ⭐  Run Create Pull Request<br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   ☁  <span class=\"token function\">git</span> clone <span class=\"token string\">'https://github.com/peter-evans/create-pull-request'</span> <span class=\"token comment\"># ref=v3</span><br />*DRYRUN* <span class=\"token punctuation\">[</span>Compress images/calibreapp/image-actions<span class=\"token punctuation\">]</span>   ✅  Success - Create Pull Request</code></pre>\n<p>If I run <code>act</code>, it defaults to do <code>push</code> event, so I guess this is dry-running <code>push</code>.</p>\n<p><code>act pull_request -n</code> would mean run <code>pull_request</code> in dry-run mode.</p>\n<p>I’ve got nothing. <code>act pull_request</code> gave me nothing as well.</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># Only run on main repo on and PRs that match the main repo.</span><br /><span class=\"token key atrule\">if</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">|</span><span class=\"token scalar string\"><br />  github.repository == 'frontendweekly/virga' &amp;&amp;<br />  (github.event_name != 'pull_request' ||<br />   github.event.pull_request.head.repo.full_name == github.repository)</span></code></pre>\n<p>This was the culprit, more specifically <code>github.event.pull_request.head.repo.full_name == github.repository</code> line was the cause.</p>\n<p>Remove entire <code>if</code>, then did <code>act pull_request -n</code>. It looks good.</p>\n<p>Act is intended to work as a local task runner so, if I run it without <code>-n</code> it should actually compress images, but since I want to see, what actually happens when real <code>push</code> or <code>pull_request</code> have triggered.</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2021-01-18-n80ugn4M@2x.png\" alt=\"GitHub's pull request screen capture displaying GitHub Action result\" title=\"It worked 🎉\" /></p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2021-01-14T12:44:31Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/",
      "url": "https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/",
      "title": "Indieweb: POSSE using Eleventy and Netlify Functions",
      "summary": "A story about testing and writing Netlify function",
      "content_html": "<h2 id=\"posse-publish-on-your-own-site-syndicate-elsewhere\"><abbr>“POSSE”</abbr>: Publish on your Own Site, Syndicate Elsewhere <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#posse-publish-on-your-own-site-syndicate-elsewhere\">#</a></h2>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://indieweb.org/POSSE\">\n<p>POSSE is an abbreviation for Publish (on your) Own Site, Syndicate Elsewhere, the practice of posting content on your own site first, then publishing copies or sharing links to third parties (like social media silos) with original post links to provide viewers a path to directly interacting with your content.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://indieweb.org/POSSE\">https://indieweb.org/POSSE</a></figcaption>\n</figure>\n<p>I’ve briefly mentioned POSSE at <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/\">How Would I Extend Virga?</a> and I’ve implemented “auto tweet posing when I deploy new article” by following <a href=\"https://mxb.dev/blog/syndicating-content-to-twitter-with-netlify-functions/\">Max Böck’s tutorial</a>.</p>\n<p>While Max Böck’s tutorial is great, I’ve been thinking about changing and exploring a few details.</p>\n<p>What details I want to explore that comes to my mind right now:</p>\n<ul>\n<li>Add unit tests to the implementation</li>\n<li>What can <a href=\"https://docs.netlify.com/cli/get-started/#get-started-with-netlify-dev\">Netlify Dev</a> do for helping develop “Functions”?</li>\n<li>Try new package for Twitter library</li>\n</ul>\n<p>And this is where my journey begins.<br />\nThis is a story about achieving POSSE practice using Eleventy and Netlify Functions and along its way, I want to visit unit testing, Netlify Dev and new (hopefully better maintained) Twitter library for API.</p>\n<p>Again, I really appreciate for Max Böck for sharing a tutorial on this.</p>\n<h2 id=\"if-new-article-was-deployed-then-tweet-title-and-url-of-the-article\">IF new article was deployed THEN tweet title and URL of the article <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#if-new-article-was-deployed-then-tweet-title-and-url-of-the-article\">#</a></h2>\n<p>In an essence, this is what I’m trying to do and everything can be done using Netlify Functions.<br />\nIn order to accomplish this, I would need to get the title and URL of the article.</p>\n<p>This shouldn’t be difficult since Eleventy gives me many ways to access contents data.</p>\n<p>However…</p>\n<h2 id=\"netlify-functions-arent-part-of-eleventy-so-where-and-how-do-i-get-contents\">Netlify Functions aren’t part of Eleventy, so where and how do I get contents? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#netlify-functions-arent-part-of-eleventy-so-where-and-how-do-i-get-contents\">#</a></h2>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token builtin class-name\">.</span><br />├── 11ty <span class=\"token comment\"># ⇒ This is input dir for Eleventy</span><br />├── dist <span class=\"token comment\"># ⇒ This is output dir for Eleventy</span><br />├── functions <span class=\"token comment\"># ⇒ This is for Netlify Functions</span><br />├── .eleventy.js<br />└── README.md</code></pre>\n<p>I suppose I could move <code>functions/</code> directory into <code>11ty/</code> so I can use contents data for tweets from Eleventy.</p>\n<p>But I’ve decided to use the <a href=\"https://jsonfeed.org/\">JSON Feed</a> as the input for Netlify Functions.<br />\nThe JSON Feed is a syndication format, like RSS and Atom, but with one exception: it’s JSON instead of XML.</p>\n<p>This is my <a href=\"https://virga.frontendweekly.tokyo/feed.json\">JSON Feed</a>(You can subscribe it with <a href=\"https://feedbin.com/\">Feedbin</a> or <a href=\"https://feedly.com/\">Feedly</a> and I’m sure other RSS services support it.)</p>\n<p>The JSON Feed has all the data I need for a tweet, I don’t see why not using it.</p>\n<h2 id=\"trigger-a-synchronous-serverless-function-on-deploy-succeeded-events\">Trigger a synchronous serverless function on <code>deploy-succeeded</code> events <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#trigger-a-synchronous-serverless-function-on-deploy-succeeded-events\">#</a></h2>\n<p>I need trigger serverless function calls when certain Netlify events happen. Netlify does allow me doing this.</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://docs.netlify.com/functions/trigger-on-events/\">\n<p>to trigger a synchronous serverless function on deploy-succeeded events, name the function file <code>deploy-succeeded.js</code> or <code>deploy-succeeded.go</code>.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://docs.netlify.com/functions/trigger-on-events/\">https://docs.netlify.com/functions/trigger-on-events/</a></figcaption>\n</figure>\n<p>This is exactly what I’m looking for. This means that I need to save a <code>deploy-succeeded.js</code> at <code>functions/</code> directory.</p>\n<p>According to <a href=\"https://docs.netlify.com/functions/build-with-javascript/#synchronous-function-format\">“Synchronous function format” from Netlify Doc</a> I need to export a <code>handler</code> method with <code>async</code>.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">handler</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />\t<span class=\"token comment\">// 1. Fetch the JSON Feed</span><br />\t<span class=\"token comment\">// 2. Process that info so that I can tweet </span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"test-driven-developing-deploy-succeededjs\">Test Driven Developing <code>deploy-succeeded.js</code> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#test-driven-developing-deploy-succeededjs\">#</a></h2>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://medium.com/javascript-scene/tdd-changed-my-life-5af0ce099f80\">\n<p>For me, TDD is far more than a safety net. It’s also constant, fast, realtime feedback. Instant gratification when I get it right. Instant, descriptive bug report when I get it wrong.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Eric Elliott, <a href=\"https://medium.com/javascript-scene/tdd-changed-my-life-5af0ce099f80\">“TDD Changed My Life”</a></figcaption>\n</figure>\n<p>I did implement <code>deploy-succeeded.js</code> already, I’ll delete it and try <abbr>TDD</abbr>(Test Driven Development).</p>\n<p>A couple of questions I have before start doing TDD:</p>\n<ul>\n<li>I don’t want to actually send out a tweet every time I run test. I need to mock it</li>\n<li>How I’m going to test functions that would go inside the <code>handler</code> method?</li>\n</ul>\n<p>For mocking, I’ll use <a href=\"https://mswjs.io/\">Mock Service Worker</a> which “is an API mocking library that uses Service Worker API to intercept actual requests.” It sounds like for client-side only, but it actually works in Node.js too.</p>\n<p>For testing non-export functions, I’ve decided to use <a href=\"https://github.com/jhnns/rewire\">jhnns /rewire</a>. This looks like very black magic. I could export functions that I’m going to write for test, but that’s not what I intended to do with <code>deploy-succeeded.js</code> so I’ll take the black magic this time.</p>\n<p>Experimenting is fun.</p>\n<h2 id=\"lets-cdd-before-tdd\">Let’s CDD before TDD <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#lets-cdd-before-tdd\">#</a></h2>\n<p>I like Comment Driven Development(<abbr>CDD</abbr>).</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://perell.com/essay/why-you-should-write/\">\n<p>An empty white page is a mirror into your mind. When the ideas in your mind are clouded, so are the words on the page in front of you. Re-writing is re-thinking. It’s the single best way to sharpen your ideas.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— David Perell, <a href=\"https://perell.com/essay/why-you-should-write/\">“Why You Should Write”</a>.</figcaption>\n</figure>\n<p>I’m not smart. I don’t have CS degree. But I love writing. I just don’t pick and choose what language I write. Just like on this blog, I write in English (pardon me writing poorly), I usually write things in Japanese. I’m fluent in HTML and CSS, but not so much in JavaScript.</p>\n<p>But an important thing which still keep me working on Web development is: I love writing.</p>\n<p>So whenever I work on programming stuff, I write comment first.</p>\n<p>It’s frightening for me to looking a blank empty white page. This is why I like the dark theme. The dark theme makes me feel a little safer.</p>\n<p>I write comments because it takes time to clarify what I want my code to do.<br />\nI want to my ideas to be as clear as a Neiman Marcus mirror as David Perell said before writing any codes.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// Require libraries</span><br /><br /><span class=\"token comment\">// Configure libraries</span><br /><br /><span class=\"token comment\">// Fetch JSON Feed</span><br /><br /><span class=\"token comment\">// Test if the most recent item in feed should be tweeted</span><br /><br /><span class=\"token comment\">// Create a text for a tweet. Remember there is 280 characters limit on Twitter</span><br /><br /><span class=\"token comment\">// Post a tweet</span><br /><br /><span class=\"token comment\">// Lambda Function Handler</span><br />exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">handler</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>My first rough draft would look like this. Even though Jeff Bezos might not approve, I like writing in bullet lists.</p>\n<p>Let’s dig a bit deeper using an example.</p>\n<p>How should I go about addressing this idea?: “Test if the most recent item in feed should be tweeted”</p>\n<p>Finding the most recent item in feed is easy since JSON Feed has an “items” as an array so <code>items[0]</code> should be the most recent item.<br />\nHowever, what is the criteria for deciding an item “should be tweeted”?</p>\n<p>I can tell by reading the comment that I’d need more research for that part. It’s too vague.<br />\nJust like writing an essay, I need find out something to rely on.</p>\n<p>For this case, I think the Inversion Principle would help me.<br />\nWhat don’t I want to tweet? How can I avoid the same tweet appearing on my Twitter stream? How can I tell that I’ve already tweeted for the article which I just fixed typos?</p>\n<p>The answers for those questions are in Twitter API document because I need to find out how the search in Twitter works.</p>\n<p>I write comments like this. My rough draft becomes an outline, and an outline will become headings then questions and answers thrive in that headings.</p>\n<p>I don’t commit them so nobody gets to read it but this is what I meant for writing helps me clarify my ideas.</p>\n<h2 id=\"tdd-is-a-validator-of-my-expression\">TDD is a validator of my expression <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#tdd-is-a-validator-of-my-expression\">#</a></h2>\n<p>Unfortunately, I don’t yet to know how GPT-3 works, but I don’t think even GPT-3 cannot generate JavaScript expressing my idea. (Well, maybe it does, but I don’t know)</p>\n<p>Therefore, I need a validator to ensure that I expressed what I want correctly for now.</p>\n<p>After researching Tweeter API Doc, I did find out about the search feature. In short, “the Twitter Search API searches against a sampling of recent Tweets published in the past 7 days.”</p>\n<p>If I were simply used the Search API to find out I tweeted the article or now by searching article URL which I think it’s unique enough for this kind of search, then there would be a couple of issues.</p>\n<p>The issues I can see now would be situation like this: if I did tweet the most recent article but after 7 days, I’ve noticed typos, so I fix them and deploy it, then that article is still the most recent article, and it’ll be after 7 days, so the article will get tweeted again.</p>\n<p>I can’t speak for the others but for me, Twitter is already noisy, so it would be great if I can avoid being the noise…</p>\n<p>Again, the Inversion Principle works here.<br />\nWhich will lead me: How can I prevent hitting Search API if the article is more than 7 days old?</p>\n<p>Let’s invert again, so it would sound more natural: If the most recent article is less than 7 days old, let’s hit Search API to make sure it’s not in Twitter yet.</p>\n<p>Doesn’t this sound like a function?<br />\nIt does to me, so I write a test for it.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'The most recent post is LESS than 7 days old'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  <span class=\"token comment\">// Arrange</span><br />  <span class=\"token function\">advanceTo</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token number\">2021</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">const</span> now <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <br />  <span class=\"token keyword\">const</span> morethan7days <span class=\"token operator\">=</span> <span class=\"token string\">'2021-01-10T12:15:31.627Z'</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">const</span> lessthan7days <span class=\"token operator\">=</span> <span class=\"token string\">'2021-01-06T12:15:31.627Z'</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token comment\">// Assert</span><br />  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span><span class=\"token function\">isLessThan7DaysOld</span><span class=\"token punctuation\">(</span>now<span class=\"token punctuation\">,</span> morethan7days<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toBe</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span><span class=\"token function\">isLessThan7DaysOld</span><span class=\"token punctuation\">(</span>now<span class=\"token punctuation\">,</span> lessthan7days<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toBe</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And write the function.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">isLessThan7DaysOld</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">now<span class=\"token punctuation\">,</span> compare</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">return</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">ceil</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>now <span class=\"token operator\">-</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span>compare<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">1000</span> <span class=\"token operator\">/</span> <span class=\"token number\">60</span> <span class=\"token operator\">/</span> <span class=\"token number\">60</span> <span class=\"token operator\">/</span> <span class=\"token number\">24</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> <span class=\"token operator\">-</span><span class=\"token number\">7</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"does-mock-service-worker-live-up-my-expectation\">Does Mock Service Worker live up my expectation? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#does-mock-service-worker-live-up-my-expectation\">#</a></h2>\n<p>Next, I need to find out if my latest article’s URL is in the Twitter Search API or not.<br />\nI have to manipulate the response from Search API for this. Well, technically, I could use fake URL as a query to get “Not found” response and real URL to get “found” one, but 1) GET is safer to experimenting and 2) I want to avoid flakiness in my tests.<br />\nImportantly, I want to try out Mock Service Worker.</p>\n<p>Whenever I experiment a new tool for the first time, I start by making an isolated environment for it. So I have a dedicated directory for this kind of work. The benefits of doing this is that it’s safe and clean, meaning I don’t have to worry about muddying the ongoing project, and I have a central place to look up how actually things work.</p>\n<p><a href=\"https://mswjs.io/\">Mock Service Worker</a> has a great document helping me set it up, and I did create an example using a publicly available API (means that I don’t have to go through Auth process to GET responses).</p>\n<p>I don’t exactly know how this thing works, but I know how to make it works for me.</p>\n<p>My initial test against this function looked like this:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Twitter Search API returns ZERO result'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  <span class=\"token comment\">// Arrange</span><br />  <span class=\"token keyword\">const</span> query <span class=\"token operator\">=</span> <span class=\"token string\">'TEST'</span><span class=\"token punctuation\">;</span><br />  <span class=\"token comment\">// Act</span><br />  <span class=\"token keyword\">const</span> actual <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">doesSearchReturnZero</span><span class=\"token punctuation\">(</span>query<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token comment\">// Assert</span><br />  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>actual<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toBe</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>But, I soon realized this doesn’t add any value as a test since I’ve mocked response from <code>https://api.twitter.com/1.1/search/tweets.json</code> to always return <code>[]</code>.</p>\n<p>Eliel Saarinen, a finnish-American architect once said:</p>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>Always design a thing by considering it in its next larger context – a chair in a room, a room in a house, a house in an environment, an environment in a city plan.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Eliel Saarinen</figcaption>\n</figure>\n<p>Whenever I face the situation like this, I always come back to his quote and always remind me what I’m intended to do originally.</p>\n<p>I want to design a gateway. This gateway will stop the process when criteria have met. Before thinking about designing this gateway, I need to think about more detail about the next action.</p>\n<p>However, I’ve learned what to do with Mock Service Worker.</p>\n<h2 id=\"realizing-via-visualizing\">Realizing via visualizing <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#realizing-via-visualizing\">#</a></h2>\n<p>My next action, according to my initial outline is: “Create a text for a tweet. Remember there are 240 characters limit on Twitter”.</p>\n<p>I’ve decided to go with this simple format: <code>${title} via ${siteTitle}: ${url}</code> and I need get those from the JSON Feed.</p>\n<p>Let’s get it visualized.</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions.fig1.png\" alt=\"Explaining the entire process\" title=\"Fig 1: Visualizing the entire process\" /></p>\n<p>Dashed boxes on Fig 1 are ones that need to be mocked and now I can see the whole picture, I should go ahead work on “Prepare Status Text”.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Prepare a status text for a tweet'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />\t<span class=\"token comment\">// Arrange</span><br />\t<span class=\"token keyword\">const</span> ingredient <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />\t  status<span class=\"token operator\">:</span> <span class=\"token string\">'This is a test tweet with in 240 characters limit'</span><span class=\"token punctuation\">,</span><br />\t  url<span class=\"token operator\">:</span> <span class=\"token string\">'https://virga.frontendweekly.tokyo/test-'</span><span class=\"token punctuation\">,</span><br />\t  siteName<span class=\"token operator\">:</span> <span class=\"token string\">'Virga'</span><span class=\"token punctuation\">,</span><br />\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br />\t<span class=\"token comment\">// Act</span><br />\t<span class=\"token keyword\">const</span> actual <span class=\"token operator\">=</span> <span class=\"token function\">prepareStatusText</span><span class=\"token punctuation\">(</span>ingredient<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />\t<span class=\"token comment\">// Assert</span><br />\t<span class=\"token keyword\">const</span> expected <span class=\"token operator\">=</span><br />\t  <span class=\"token string\">'This is a test tweet with in 240 characters limit via Virga: https://virga.frontendweekly.tokyo/test-'</span><span class=\"token punctuation\">;</span><br />\t<span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>actual<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toEqual</span><span class=\"token punctuation\">(</span>expected<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Based on my visualization, I’d say this is the most complicated part of all, and it’s not too difficult to do. (I’m assuming URL is 40 characters, by the way.)</p>\n<p><code>prepareStatusText()</code> would be only test that have value, but I’m going to add mocks for “Fetch JSON Feed” and “Post a tweet”, too.</p>\n<h2 id=\"back-to-mostly-empty-state\">Back to mostly empty state <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#back-to-mostly-empty-state\">#</a></h2>\n<p>At this point, I’d have sufficient tests, so I’ll delete most of my implementation.<br />\nWell, I don’t literally delete it, but I put them away from the editor. Then try to remember what I had written and generate new implementation from the memory.</p>\n<p>I’m not smart, but I still can use my memory as a filter, removing excessive and organizing what is vital.<br />\nMy unit tests are there to guide me where I’m going.</p>\n<p>I don’t have to do this every time, but I do this often. I really like the part where I delete the implementation. This helps me think and remember. I might end up with the same lines of codes, but that’s ok. Some will say, it’s wast of time. Sure, I don’t disagree with it at all.</p>\n<p>But having a good feedback cycle helps me grow. And I believe feedbacks are not just from someone else. When a feedback comes from myself, that may be called a reflection, but the concept is same.</p>\n<h2 id=\"writing-is-writing\">Writing is writing <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-09-indieweb-posse-using-eleventy-and-netlify-functions/#writing-is-writing\">#</a></h2>\n<p>I love writing. I don’t discriminate what language I write. HTML, CSS and JavaScript are languages that I’ve learned and use. (I don’t speak them, but I do read them, sometimes just for fun.)</p>\n<p>Writing is writing. It shouldn’t be matter what language I’m writing. This is how I learn to write better.</p>\n<p>I’m going to finish my implementation, and it’ll be at my <a href=\"https://github.com/frontendweekly/virga/tree/master/functions\"><code>functions/</code></a> directory.</p>\n<p>I haven’t finished it yet, and I haven’t touched Netlify Dev, but I’ll end my story here.<br />\nThis one has become very long one, and I’m going to need editing.</p>\n<p>I might write a story for creating a component just like this one.</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2021-01-09T00:06:25Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/",
      "url": "https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/",
      "title": "Shareable Configs",
      "summary": "A story about creating shareable configurations for ESLint, stylelint, Jest preset and Browserlist",
      "content_html": "<h2 id=\"unstable-linting\">Unstable Linting <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#unstable-linting\">#</a></h2>\n<p>Static testing AKA linting has been integrated with my development for some times; however, my configurations for ESLint and stylelint haven’t had a single source of truth.</p>\n<p>I’ve been copy and pasting configurations for long so that there are several versions of them.</p>\n<p>In addition, I run linting as a part of tests using Jest runners, and I realized that I have several versions for Jest configuration.</p>\n<p>I knew there are a way to create a shareable configuration for ESLint, but didn’t know how.<br />\nI didn’t know there are a way to do a shareable configuration for stylelint nor Jest.</p>\n<p>I need a home for those configurations.</p>\n<p>And this is where my journey begins.</p>\n<p>This is a story about creating shareable configurations for ESLint, stylelint, Jest preset and Browserlist.</p>\n<h2 id=\"eslint\">ESLint <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#eslint\">#</a></h2>\n<p>ESLint <a href=\"https://eslint.org/docs/developer-guide/shareable-configs\">has a dedicated page for shareable configs</a> therefore it is relatively easy to set it up.</p>\n<h3 id=\"indexjs-for-exporting-configs\">index.js for exporting configs <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#indexjs-for-exporting-configs\">#</a></h3>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>Shareable configs are simply npm packages that export a configuration object. To start, create a Node.js module like you normally would. Make sure the module name begins with <code>eslint-config-</code>, such as <code>eslint-config-myconfig</code>.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— “Shareable Configs.” ESLint, <a href=\"http://eslint.org/docs/developer-guide/shareable-configs\">eslint.org/docs/developer-guide/shareable-configs</a>.</figcaption>\n</figure>\n<p>“[A] configuration object” means what <code>.eslintrc.js</code> has in it. I had several of those scattering around all over my repositories, so I decided to start from scratch for new year.</p>\n<p>I’ve used GitHub package instead of npm and that works great.</p>\n<h3 id=\"plugins\">Plugins <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#plugins\">#</a></h3>\n<p>I’m using 11 plugins and here is 5 of them:</p>\n<ul>\n<li><a href=\"https://github.com/prettier/eslint-config-prettier\">prettier/eslint-config-prettier</a>: Turns off all rules that are unnecessary or might conflict with Prettier</li>\n<li><a href=\"https://github.com/mysticatea/eslint-plugin-node\">mysticatea/eslint-plugin-node</a>: Additional ESLint’s rules for Node.js</li>\n<li><a href=\"https://github.com/amilajack/eslint-plugin-compat\">amilajack/eslint-plugin-compat</a>: Lint the browser compatibility</li>\n<li><a href=\"https://github.com/nodesecurity/eslint-plugin-security\">nodesecurity/eslint-plugin-security</a>: ESLint rules for helping identify potential security hotspots, but finds a lot of false positives which need triage by a human</li>\n<li><a href=\"https://github.com/jest-community/eslint-plugin-jest\">jest-community/eslint-plugin-jest</a>: ESLint plugin for Jest</li>\n</ul>\n<h3 id=\"so-eslintrcjs-has-become-one-liner\">So <code>.eslintrc.js</code> has become one-liner <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#so-eslintrcjs-has-become-one-liner\">#</a></h3>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">extends</span><span class=\"token operator\">:</span> <span class=\"token string\">'@frontendweekly/eslint-config-molle'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Technically it is not a one-liner, but once I have set up my shareable config at GitHub package, all I need in <code>.eslintrc.js</code> is <code>extends</code> it.</p>\n<h2 id=\"stylelint\">stylelint <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#stylelint\">#</a></h2>\n<p>Fortunately, stylelint has similar approach to ESLint one for creating a shareable config and <a href=\"https://github.com/stylelint/stylelint-config-standard\">stylelint/stylelint-config-standard</a> has great rules for writing CSS so I only have 5 plugins.</p>\n<p>Again, I’ve used GitHub package instead of npm.</p>\n<p>All in all, my <code>.stylelintrc.js</code> has:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">extends</span><span class=\"token operator\">:</span> <span class=\"token string\">'@frontendweekly/stylelint-config-molle'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"jest\">Jest <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#jest\">#</a></h2>\n<p>Last year, I’ve spent some time renewing my knowledge and skill for testing via <a href=\"https://testingjavascript.com/\">Testing Javascript by Kent C. Dodds</a>.</p>\n<p>I love tinkering with my config(that’s why I’m writing this story), so “Configure Jest for Testing JavaScript Applications” is one of my favorite sections.</p>\n<p>In that section, Kent C. Dodds showed real-world configuration for a large real-world application, and I have distilled it for my environment.</p>\n<h3 id=\"jest-has-jest-presetjs\">Jest has <code>jest-preset.js</code> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#jest-has-jest-presetjs\">#</a></h3>\n<p>First, Jest has <code>jest.config.js</code> so I thought I could use same approach as ESLint and stylelint for creating a shareable config.<br />\nEven though, I think I could make it work, but I’ve found a better way.</p>\n<p>I’ve stumble upon <code>preset</code> when I’m reading Jest documentation.</p>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>A preset that is used as a base for Jest’s configuration. A preset should point to an npm module that has a jest-preset.json or jest-preset.js file at the root.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— “Configuring Jest.” Jest, <a href=\"http://jestjs.io/docs/en/configuration.html\">jestjs.io/docs/en/configuration.html</a>.</figcaption>\n</figure>\n<p>In Jest world, I need <code>jest-preset.js</code> for a shareable config, yet differences between ESLint and stylelint basically end here.</p>\n<p>Once I’ve set up <code>jest-preset.js</code>, my <code>jest.config.js</code> has:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  preset<span class=\"token operator\">:</span> <span class=\"token string\">'@frontendweekly/jest-preset-molle'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"browserlist\">Browserlist <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#browserlist\">#</a></h2>\n<p>My renewed ESLint and stylelint has rules for linting browser compatibilities so having a shared Browserlist setting comes in handy.</p>\n<p>I’ve realized that I depend on Browserlist tightly, yet I only know a few things about it.<br />\nNaturally, I didn’t know about its shareable configs capability.</p>\n<p>However, how to set it up is quite similar to ESLint and stylelint.<br />\nOnce I have <code>export</code>ed an array which has browsers queries at index.js, I need to import at <code>browserslistrc</code>.</p>\n<pre class=\"language-text\"><code class=\"language-text\">extends @frontendweekly/browserslist-config-molle</code></pre>\n<p>While I’m digging into Browserslist document, I did found a gem.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">npx browserslist@latest --update-db</code></pre>\n<p>Browserslist relies on <a href=\"https://github.com/ben-eb/caniuse-lite\">caniuse-lite</a> for doing <code>last 2 versions</code> or <code>&gt;1%</code> so about once a month I would need to run above command to update it.</p>\n<p>As of the time of writing, <a href=\"https://browserl.ist/\">Browserslist is seeking help for its funding</a> and I’m considering to become a backer.</p>\n<h2 id=\"molle-rc\">MOLLE-rc <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2021-01-01-shareable-configs/#molle-rc\">#</a></h2>\n<p>All of my shareable configs have now a home.</p>\n<p>Since I mainly use it for my side project which is done in Eleventy, I consider it as a part of my <a href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/\">MOLLE</a> family.</p>\n<p><a href=\"https://github.com/frontendweekly/molle-rc\">molle-rc</a> is a new home.</p>\n<p><em>I don’t recommend using them at all…this is my config for my side project.</em></p>\n<p>I use yarn 2 without Lerna for mono-repo setup for this, but that’s another story.</p>\n<p>I’ve spent some time to re-create new configs for ESLint, stylelint, Jest and Browserslist, and I’m happy for now.<br />\nI might add my prettier config to molle-rc later.</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2021-01-01T12:15:31Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/",
      "title": "Making of Six",
      "summary": "This is a story about creating new theme \"Six\" for Sixty Six",
      "content_html": "<h2 id=\"finding-a-new-home-for-sixty-six\">Finding a new home for Sixty Six <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#finding-a-new-home-for-sixty-six\">#</a></h2>\n<p class=\"explanation\">@ 00:05 May 31, 2020</p>\n<p>I finally get to read <a href=\"https://frankchimero.com/blog/2020/redesign-wrapping-up/\">“Redesign: Clearing A Path”</a> by Frank Chimero. This post was the final note from his redesign journey.<br />\nNot only I love his design, I do also love what he writes. Reading these redesign notes got me think that it’s time to find a new home for <a href=\"https://sixtysix.frontendweekly.tokyo/\">Sixty Six</a>.</p>\n<p>Virga was created for <a href=\"https://frontendweekly.tokyo/\">Frontend Weekly Tokyo</a>. Not for Sixty Six. Moreover, Sixty Six is in an unique territory since it collects quotes.</p>\n<p>That is why I’ll create a new theme “Six” for Sixty Six. (I like naming stuff. Well, “Six” is not that difficult to come up, but I like it anyway.)</p>\n<p>And this is where my journey begins.</p>\n<p>This is a story about creating a theme for Eleventy, and I’ll do it on open as Frank Chimero has done.</p>\n<p>As always I don’t know how this story going to end, but I’ll document what happened to me along the way.</p>\n<p>Notice the time stamp right after the header?<br />\nI think this journey will be long one, so I’m going to write this story open as well which means when I finished writing an “update”, I’ll make it public.<br />\nThe time stamp indicates modification time.</p>\n<h2 id=\"blank-not-broken\">Blank. Not broken <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#blank-not-broken\">#</a></h2>\n<p class=\"explanation\">@ 22:18 May 31, 2020</p>\n<p>I’m not a designer. I had once called myself one but not anymore.<br />\nI haven’t done any development as a professional for long time either.<br />\nI definitely work around this area, but I’m not there.</p>\n<p>Anyway.</p>\n<p>Sixty Six has been distilled to blank state. Surprised to find out it is not broken. Surprised to see how simple Sixty Six is.<br />\nWhich forces me to think about what Sixty Six is.</p>\n<p>Here’s what I have come up so far.</p>\n<p>“Sixty Six is a collection of highlights which makes a foundation for the discoverable mental notes.”</p>\n<p>My english skill has been diminishing, but I still can tell this isn’t good one, but it is not broken.</p>\n<p>What is the kernel of Sixty Six?</p>\n<p>I’m not a designer. I may not be able to introduce myself as an engineer anymore, however I still love HTML and CSS. That has to account for something.</p>\n<p>I’m nowhere close to answer the question.<br />\nI’ll start with HTML to find a way in.</p>\n<h2 id=\"my-canvas\">My canvas <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#my-canvas\">#</a></h2>\n<p class=\"explanation\">@ 23:17 June 3, 2020</p>\n<p>In “The Festival of Sunflower” (Translation is mine. It’s titled “ひまわりの祝祭” in Japanese) which is one of my favorite mystery book by Iori Fujiwara, main character had always built his canvas from a plywood in his high school.</p>\n<p>He paint it white, torch it, make it flat and paint it white again. He does this several times to build his canvas.<br />\nI’m no artist. I’ve never done any oil painting, but I can empathize why he does this.</p>\n<p>He said by doing this, he can produce interesting “matière”.</p>\n<p>I’ve been thinking that browsers are the canvas.<br />\nThe browser is not the canvas. HTML is.<br />\nThe browser is the plywood.</p>\n<p>I paint it white, torch it, make it flat and paint it white again. And I do this several times.</p>\n<p>I think I now have interesting “matière”.<br />\nI now own the material I can build upon.</p>\n<h2 id=\"start-from-the-caboose\">Start from the Caboose <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#start-from-the-caboose\">#</a></h2>\n<p class=\"explanation\">@ 23:15 June 9, 2020</p>\n<p>I love tinkering with footer. When I design stuff, I tend to start working from footer.<br />\nApparently so does Frank Chimero.<br />\nI bet there is a collection of footer design somewhere.</p>\n<p>So that’s what I’ve done.</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2020-06-08-qtnrwZZm@2x.png\" alt=\"Footer on Sixty Six\" /></p>\n<p>It’s been there for about one week.<br />\nI thought about using grid, but decided to go with <a href=\"https://every-layout.dev/layouts/switcher/\">The Switcher</a>.</p>\n<p>Every content are in it, but I think it’s too vanilla.<br />\nBut It’s too early to talk about personality of Six yet.</p>\n<p>Let’s work on other kind of footer: meta.<br />\nThat’s where I put something like author, publish date etc.<br />\nIt’s kind of like footer. I often even use <code>&lt;footer&gt;</code> for it.</p>\n<p>Sixty Six has only one meta, yet again working from footer make sense for me.<br />\nI’ve prepended a symbol <code>—</code> to bylines which carry the message about Sixty Six.</p>\n<p>I’ve gone back and forward if I should have other metadata other than authors.</p>\n<h2 id=\"the-quote\">The quote <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#the-quote\">#</a></h2>\n<p class=\"explanation\">@ 21:18 June 15, 2020</p>\n<p>Main contents for Sixty Six are quotes, and I have been working on it since I’ve started to do redesign.</p>\n<p>I tend to quote the whole paragraph if it’s not too long; therefore, my contents tend to be short. It’s quite safe to say they are not long-form at all.</p>\n<p>I need them to stand out, so the quote have given the largest font size.</p>\n<p>Georgia is my choice for this redesign. I love working with typeface since I don’t get to do so in my day job. Japanese fonts are very heavy so for performance budget we’ve set, I cannot use custom fonts.</p>\n<p>However, I still choose Georgia since this is how typically read in my Instapaper app which is where the most of the quotes come from.</p>\n<p>Sixty Six is my bedrock for the discoverable memory. I don’t have any research to back this up, but I think it helps me to remember if the typeface for reading and recalling is same. I don’t have to question my self why I chose different typeface at least.</p>\n<p>It’s been about one week since I’ve finished working on the quote and list of quotes.<br />\nIt’s still very minimum, but I like minimum.</p>\n<h2 id=\"adding-spirit\">Adding spirit <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#adding-spirit\">#</a></h2>\n<p class=\"explanation\">@ 21:39 June 18, 2020</p>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>One of the ways that I’ve found to add spirit to simple designs is through color. The color need not be showy, only rich and nuanced.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Frank Chimero, Redesign: Clearing A Path. (2020, May 24)</figcaption>\n</figure>\n<p>I am going to follow his advice. It seems very good one since I do like to work on color.</p>\n<p>I want to add hint of my personality via color. I like green. I like red. And I like black and white. I was gonna pick one, but I use them all.</p>\n<p>I’ve got a lot of help from <a href=\"https://www.color.ninja/\">Color Ninja</a> and <a href=\"https://sipapp.io/\">Sip</a> for doing this.</p>\n<p>And I think I’ve settled with current setting. I wouldn’t call it as a scheme since there no science behind my choice, but I think that’s what make this personal.</p>\n<p>I also used a texture(it’s from <a href=\"https://www.heropatterns.com/\">Hero Patterns</a>). It’s very subtle. <code>fill-opacity='0.08'</code> subtle.</p>\n<h2 id=\"six-is-100\">Six is <code>1.0.0</code> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-30-making-of-six/#six-is-100\">#</a></h2>\n<p class=\"explanation\">@ 23:50 June 24, 2020</p>\n<p><a href=\"https://sixtysix.frontendweekly.tokyo/\">Sixty Six</a> is stable, so Six is <code>1.0.0</code>.<br />\nIt’s been 24 days. I’ve been working on this whenever I have time, yet I feel I haven’t done much.<br />\nHowever, this journey has come to the end for now.<br />\nI’m sure I’m going to nurture this design time to time.</p>\n<p>Very minimum but has a split. That’s how I see Six.<br />\nI’m happy with the result.<br />\nIt’s been fun for sure.</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2020-05-30T14:15:35Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/",
      "title": "Does Netlify Build Plugin improve my build speed?",
      "summary": "This is a story about untangling Netlify Build Plugin to improve my build speed.",
      "content_html": "<h2 id=\"act-i-im-still-not-sure-saving-2-mins-on-build-worth-the-time\">ACT I: I’m still not sure saving 2 mins on build worth the time <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#act-i-im-still-not-sure-saving-2-mins-on-build-worth-the-time\">#</a></h2>\n<p class=\"explanation\">Meet the Hero—their world, what they want, what they fear.</p>\n<p>My last journey was to <a href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/\">auto generate image from article data</a> and by adding this feature, I’ve also added 2 mins of build time since generating screenshots takes time.</p>\n<p>In the finale of my story, I’ve mentioned Netlify Build Plugins, and their capability to access to the cache between build.</p>\n<p>I was going to wait for a blog post from Phil Hawksworth as he mentioned writing it on his Tweet, but it would be more fun for me to get my own hand dirty on this topic.</p>\n<p>As always, I’m not sure how this story is going to end, but I’ll record what happened to me along the way.</p>\n<p>And this is where my journey begins.<br />\nThis is a story about untangling Netlify Build Plugins so that I can create one to speed up my build.</p>\n<h3 id=\"inciting-incident-figuring-out-netlify-build-plugins\">Inciting Incident: Figuring out Netlify Build Plugins <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#inciting-incident-figuring-out-netlify-build-plugins\">#</a></h3>\n<p class=\"explanation\">Your Hero’s worst fears realized.</p>\n<p>Before I actually write some JavaScript(I’m assuming that is the language I can use to build Netlify Build Plugins), I need to find out about I can run Netlify Build Plugins locally.</p>\n<p>Here are references I’ve found so far, and I haven’t read it all yet.</p>\n<ul>\n<li><a href=\"https://www.netlify.com/blog/2020/04/30/whats-a-netlify-build-plugin-series-part-1-using-build-plugins/\">What are Netlify Build Plugins? Part 1 - How to Use Build Plugins</a></li>\n<li><a href=\"https://docs.netlify.com/configure-builds/build-plugins/#create-your-own\">Build Plugins | Netlify Docs</a></li>\n<li><a href=\"https://github.com/netlify/build\">netlify/build: Netlify Build Plugins. Join the early access beta 👉</a></li>\n<li><a href=\"https://github.com/netlify/plugins\">netlify/plugins: Netlify plugins directory</a></li>\n<li><a href=\"https://github.com/netlify-labs/netlify-plugin-debug-cache\">netlify-labs/netlify-plugin-debug-cache: Debug &amp; verify the contents of your Netlify build cache</a></li>\n<li><a href=\"https://github.com/jlengstorf/netlify-plugin-gatsby-cache\">jlengstorf/netlify-plugin-gatsby-cache</a></li>\n</ul>\n<p>According to <a href=\"https://github.com/netlify/build\">netlify/build</a>, after enabling Build Plugins at Netlify, what I need to do is add:</p>\n<pre class=\"language-text\"><code class=\"language-text\">[[plugins]]<br />  package = \"netlify-plugin-debug-cache\"</code></pre>\n<p>Something like this to my <code>netlify.toml</code>.</p>\n<p>Before I’ve added above, I run <code>npx netlify build --dry</code> and that gave me this:</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">┌─────────────────────────────┐<br />│        Netlify Build        │<br />└─────────────────────────────┘<br /><br />❯ Version<br />  @netlify/build <span class=\"token number\">0.4</span>.26<br /><br />❯ Flags<br />  dry: <span class=\"token boolean\">true</span><br />  mode: cli<br /><br />❯ Current directory<br />  /Users/studiomohawk/Sync/Hack/sixtysix<br /><br />❯ Config <span class=\"token function\">file</span><br />  /Users/studiomohawk/Sync/Hack/sixtysix/netlify.toml<br /><br />❯ Context<br />  production<br /><br />❯ Netlify Build Commands<br />  For <span class=\"token function\">more</span> information on build events see the docs https://github.com/netlify/build<br /><br />  Running <span class=\"token variable\"><span class=\"token variable\">`</span>netlify build<span class=\"token variable\">`</span></span> will execute this build flow<br /><br />  ┌──────────────────┬──────────────────┐<br />  │ Event            │ Location         │<br />  └──────────────────┴──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">1</span>. onPreBuild  ↓ │ Plugin @netlify/plugin-functions-install-core<br />  └──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">2</span>. onBuild     ↓ │ build.command from netlify.toml<br />  └──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">3</span>. onPostBuild   │ Plugin @netlify/plugin-functions-core<br />  └──────────────────┘<br /><br />  If this looks good to you, run <span class=\"token variable\"><span class=\"token variable\">`</span>netlify build<span class=\"token variable\">`</span></span> to execute the build</code></pre>\n<p>This is what I get from the same command after I’ve added the configuration to <code>netlify.toml</code>.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">┌─────────────────────────────┐<br />│        Netlify Build        │<br />└─────────────────────────────┘<br /><br />❯ Version<br />  @netlify/build <span class=\"token number\">0.4</span>.26<br /><br />❯ Flags<br />  dry: <span class=\"token boolean\">true</span><br />  mode: cli<br /><br />❯ Current directory<br />  /Users/studiomohawk/Sync/Hack/sixtysix<br /><br />❯ Config <span class=\"token function\">file</span><br />  /Users/studiomohawk/Sync/Hack/sixtysix/netlify.toml<br /><br />❯ Context<br />  production<br /><br />❯ Installing plugins<br />   - netlify-plugin-debug-cache<br /><br />❯ Loading plugins<br />   - netlify-plugin-debug-cache@1.0.3<br /><br />❯ Netlify Build Commands<br />  For <span class=\"token function\">more</span> information on build events see the docs https://github.com/netlify/build<br /><br />  Running <span class=\"token variable\"><span class=\"token variable\">`</span>netlify build<span class=\"token variable\">`</span></span> will execute this build flow<br /><br />  ┌──────────────────┬──────────────────┐<br />  │ Event            │ Location         │<br />  └──────────────────┴──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">1</span>. onPreBuild  ↓ │ Plugin @netlify/plugin-functions-install-core<br />  └──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">2</span>. onBuild     ↓ │ build.command from netlify.toml<br />  └──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">3</span>. onPostBuild ↓ │ Plugin @netlify/plugin-functions-core<br />  └──────────────────┘<br />  ┌──────────────────┐<br />  │ <span class=\"token number\">4</span>. onEnd         │ Plugin netlify-plugin-debug-cache<br />  └──────────────────┘<br /><br />  If this looks good to you, run <span class=\"token variable\"><span class=\"token variable\">`</span>netlify build<span class=\"token variable\">`</span></span> to execute the build</code></pre>\n<p>Nice.<br />\nIt did automatically install the plugin as a npm module and looks like <code>netlify-plugin-debug-cache</code> is executed <code>onEnd</code> event.</p>\n<p>When I do <code>npx netlify build</code> (without <code>--dry</code>), there is <code>cache-output.json</code> in my <code>dist</code> directory. Since I haven’t save anything in cache yet, I have <code>[]</code> in my <code>cache-output.json</code>.</p>\n<h2 id=\"act-ii-how-to-create-own-netlify-build-plugin\">ACT II: How to create own Netlify Build Plugin <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#act-ii-how-to-create-own-netlify-build-plugin\">#</a></h2>\n<p class=\"explanation\">The Hero makes a decision about how to resolve the problem created by the Inciting Incident.</p>\n<p>Now I’ve learned how to run a Netlify Build Plugin locally, let’s dig a bit deeper. Next objective will be saving the cache, but before doing that I need to know how to create own Netlify Build Plugin.</p>\n<p>According to <a href=\"https://github.com/netlify/build#anatomy-of-a-plugin\">netlify/build</a>, a plugin consists of two files: a <code>manifest.yml</code> and a JavaScript file exporting an object, so I made those.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">plugins<br />└── netlify-plugin-molle-cache<br />   ├── index.js<br />   └── manifest.yml</code></pre>\n<p><code>manifest.yml</code> has:</p>\n<pre class=\"language-yml\"><code class=\"language-yml\"><span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> netlify<span class=\"token punctuation\">-</span>plugin<span class=\"token punctuation\">-</span>molle<span class=\"token punctuation\">-</span>cache</code></pre>\n<p><code>index.js</code> has:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token function-variable function\">onPreBuild</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onPreBuild event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token function-variable function\">onPostBuild</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onPostBuild event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token function-variable function\">onEnd</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onEnd event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And I’ve updated <code>netlify.toml</code>:</p>\n<pre class=\"language-text\"><code class=\"language-text\">[[plugins]]<br />  package = \"./plugins/netlify-plugin-molle-cache\"<br />[[plugins]]<br />  package = \"netlify-plugin-debug-cache\"</code></pre>\n<p>Then again run <code>npx netlify build</code>.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\">┌─────────────────────────────────────────────────────────────────┐<br />│ <span class=\"token number\">2</span>. onPreBuild <span class=\"token builtin class-name\">command</span> from ./plugins/netlify-plugin-molle-cache │<br />└─────────────────────────────────────────────────────────────────┘<br /><br />Hello world from onPreBuild event<span class=\"token operator\">!</span></code></pre>\n<p>🎉 Yay.<br />\nI wish I could get this info by doing <code>npx netlify build --dry</code>, but worked as I’ve expected.</p>\n<h3 id=\"first-reversal-how-does-netlify-build-plugin-cache-thing-works\">First Reversal: how does Netlify Build Plugin cache thing works? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#first-reversal-how-does-netlify-build-plugin-cache-thing-works\">#</a></h3>\n<p class=\"explanation\">The Hero makes the first major progress in their journey.</p>\n<p>My objective is to save cache which means I need to save something. It really doesn’t matter what that is since I’m just trying to figure out how Netlify Build Plugin cache thing works.</p>\n<p>In the Tweet of Phil Hawksworth, he shared <a href=\"https://twitter.com/philhawksworth/status/1257284661874692097/photo/1\">this screenshot about cache</a> and looks like there is <code>utils.cache</code> available somewhere.</p>\n<p>So let’s find out what <code>utils</code> is:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token function-variable function\">onPreBuild</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onPreBuild event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token function-variable function\">onPostBuild</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>utils<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onPostBuild event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>utils<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This will log:</p>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token punctuation\">{</span><br />  build: <span class=\"token punctuation\">{</span><br />    failBuild: <span class=\"token punctuation\">[</span>Function: failBuild<span class=\"token punctuation\">]</span>,<br />    failPlugin: <span class=\"token punctuation\">[</span>Function: failPlugin<span class=\"token punctuation\">]</span>,<br />    cancelBuild: <span class=\"token punctuation\">[</span>Function: cancelBuild<span class=\"token punctuation\">]</span><br />  <span class=\"token punctuation\">}</span>,<br />  git: <span class=\"token punctuation\">{</span><br />    modifiedFiles: <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>,<br />    createdFiles: <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>,<br />    deletedFiles: <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>,<br />    commits: <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>,<br />    linesOfCode: <span class=\"token number\">0</span>,<br />    fileMatch: <span class=\"token punctuation\">[</span>Function: bound fileMatch<span class=\"token punctuation\">]</span><br />  <span class=\"token punctuation\">}</span>,<br />  cache: <span class=\"token punctuation\">{</span><br />    save: <span class=\"token punctuation\">[</span>Function: save<span class=\"token punctuation\">]</span>,<br />    restore: <span class=\"token punctuation\">[</span>Function: restore<span class=\"token punctuation\">]</span>,<br />    remove: <span class=\"token punctuation\">[</span>Function: remove<span class=\"token punctuation\">]</span>,<br />    has: <span class=\"token punctuation\">[</span>Function: has<span class=\"token punctuation\">]</span>,<br />    list: <span class=\"token punctuation\">[</span>Function: list<span class=\"token punctuation\">]</span>,<br />    getCacheDir: <span class=\"token punctuation\">[</span>Function: getCacheDir<span class=\"token punctuation\">]</span><br />  <span class=\"token punctuation\">}</span>,<br />  run: <span class=\"token punctuation\">[</span>Function: run<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">{</span> command: <span class=\"token punctuation\">[</span>Function: runCommand<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span>,<br />  functions: <span class=\"token punctuation\">{</span> add: <span class=\"token punctuation\">[</span>Function: add<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>Looks like I can use <code>util.cache.save()</code> to fulfill my objective, so my next action is figuring out what to save.</p>\n<p>My ultimate objective here is to avoid taking screenshots as much as I can so that I can speed up my build.<br />\nSo let’s save screenshots which are saved at <code>dist/previews</code>.</p>\n<p>There are <a href=\"https://github.com/netlify/build#plugin-constants\">Plugin constants</a> which allows me to access to a directory which contains the deploy-ready HTML files and assets generated by the build.</p>\n<p>I’ve stolen and modified this snippet from <a href=\"https://github.com/jlengstorf/netlify-plugin-gatsby-cache/\">jlengstorf /netlify-plugin-gatsby-cache</a>:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token function-variable function\">onPreBuild</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Hello world from onPreBuild event!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token keyword\">async</span> <span class=\"token function\">onPostBuild</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>constants<span class=\"token punctuation\">,</span> utils<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">await</span> utils<span class=\"token punctuation\">.</span>cache<span class=\"token punctuation\">.</span><span class=\"token function\">save</span><span class=\"token punctuation\">(</span>constants<span class=\"token punctuation\">.</span><span class=\"token constant\">PUBLISH_DIR</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Stored the </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>constants<span class=\"token punctuation\">.</span><span class=\"token constant\">PUBLISH_DIR</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> to speed up future builds.</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span><br />      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Nothing found.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p><code>await utils.cache.save(constants.PUBLISH_DIR)</code> saves everything inside of <code>constants.PUBLISH_DIR</code> and will create a <code>cache</code> directory in a <code>.netlify</code> directory contains the cache.</p>\n<p>This means I can remove <code>netlify-plugin-debug-cache</code> since I save this for debugging cache but <code>.netlify</code> has enough info to do that.</p>\n<h2 id=\"midpoint-utilizing-cache-to-prevent-taking-screenshots\">Midpoint: Utilizing cache to prevent taking screenshots <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#midpoint-utilizing-cache-to-prevent-taking-screenshots\">#</a></h2>\n<p class=\"explanation\">The point of no return. Something big and unexpected happens, and now there’s no going back to the Hero’s normal life.</p>\n<p>Saving caches are only half the battle. I need to figure out how to restore them.<br />\nI think Eleventy doesn’t come with “increment build”, so I need a way to prevent taking screenshots if there are caches.</p>\n<p>My <code>screenshot.11ty.js</code> has this as a main function.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">ELEVENTY_ENV</span> <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">const</span> dom <span class=\"token operator\">=</span> <span class=\"token function\">markup</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>screenshot<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">getscreenshot</span><span class=\"token punctuation\">(</span>dom<span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>So I need a new condition to prevent running those 2 functions.</p>\n<p><code>utils.cache.list()</code> returns list of cached file names in an array which can be executed on <code>onPreBuild</code>, so if I can write this to a file then I can load that file in <code>screenshot.11ty.js</code>.</p>\n<p>It looks like a solid plan. Let’s see if fits in reality.</p>\n<h3 id=\"finale-the-answer-is-yes\">Finale: The answer is yes <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-15-does-netlify-build-plugin-improve-my-build-speed/#finale-the-answer-is-yes\">#</a></h3>\n<p class=\"explanation\">The Hero confronts that obstacle by making a leap of faith that allows them to overcome it.</p>\n<p>And after an hour or so, I have finished modifying my plugin and <code>screenshot.11ty.js</code>:</p>\n<ul>\n<li>Plugin: <a href=\"https://github.com/frontendweekly/molle/tree/master/packages/netlify-plugin-screenshot-cache\">https://github.com/frontendweekly/molle/tree/master/packages/netlify-plugin-screenshot-cache</a></li>\n<li><code>screenshot.11ty.js</code>: <a href=\"https://github.com/frontendweekly/sixtysix/blob/master/src/previews/screenshot.11ty.js\">https://github.com/frontendweekly/sixtysix/blob/master/src/previews/screenshot.11ty.js</a></li>\n</ul>\n<p>So Does Netlify Build Plugin improve my build speed?</p>\n<p>With caching, I’ve got <code>Build time: 1m. Total deploy time: 1m 1s</code> when there is no new quote. I have <code>Build time: 2m 56s. Total deploy time: 3m 11s</code> without caching.<br />\nIf I have a new quote, I have <code>Build time: 1m. Total deploy time: 1m 3s</code>.</p>\n<p>The answer is yes.</p>\n<p>Netlify Build Plugins have lots of possibilities, and it is relatively easy to debug, so it’s enjoyable to implement.<br />\nI’ll see what could I’ve done with this for Eleventy.</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2020-05-15T23:42:06Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/",
      "title": "Auto Generate Images from article data with Eleventy and Puppeteer",
      "summary": "This is a story about auto generating image from article data",
      "content_html": "<h2 id=\"act-i-generating-images-from-quotes-in-sixty-six\">ACT I: Generating images from quotes in <a href=\"https://sixtysix.frontendweekly.tokyo/\">Sixty Six</a> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#act-i-generating-images-from-quotes-in-sixty-six\">#</a></h2>\n<p>I’ve been publishing weekly roundup of frontend related news and articles for about 6 or 7 years.</p>\n<p>It’s safe to say I like reading, and I’ve started to highlight when I read. (I use <a href=\"https://getpocket.com/\">Pocket</a> for reading on Web and Kindle for books. I’ve been switching between Pocket and Instapaper)</p>\n<p>I used to give talks on meetups and conferences and all the talks I’ve given (about 40 talks), I always ended with a quote.</p>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>Derek says it’s always good to end a paper with a quote. He says someone else has already said it best. So if you can’t top it, steal from them and go out strong.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Danny Vinyard. American History X, (1998)</figcaption>\n</figure>\n<p>I’ve followed this advice and quotes are not just in the end. Moreover, If quotes are in English which are almost always, I translate them into Japanese. I needed to have a system not to redo my translation therefore I made a collection of quotes.</p>\n<p>I want to create a new home for highlights from my newly found habit and old quotes I’ve collected.</p>\n<p>That’s why I’ve started <a href=\"https://sixtysix.frontendweekly.tokyo/\">Sixty Six</a>. (What’s with the name? It comes from quote symbol which looks like 66.)</p>\n<p>Sixty Six has been very useful for me since I still quote when I write in Virga.</p>\n<p>Then I remembered I’ve tried to implement generating social media preview images, but I thought it’s not all that worth to put efforts into implementing, generating and storing images just for social media.</p>\n<p>While I need to figure out how to tackle accessibility obstacles using images which primary content is text, I could use good-looking quotes.</p>\n<p>There are many excellent tutorials on this topic already:</p>\n<ul>\n<li><a href=\"https://www.d-hagemeier.com/en/articles/en/articles/generate-social-media-preview-images/\">Generate Social Media Preview Images</a></li>\n<li><a href=\"https://dev.to/5t3ph/automated-social-sharing-images-with-puppeteer-11ty-and-netlify-22ln\">Automated Social Sharing Images with Puppeteer, 11ty, and Netlify</a></li>\n<li><a href=\"https://github.com/netlify-labs/netlify-functions-headless-chrome\">Headless chrome netlify functions</a></li>\n</ul>\n<p>All right, let’s give it another shot.</p>\n<p>And this is where my journey begins.<br />\nThis is a story about implementing auto-generate Images from article data with Eleventy and Puppeteer.</p>\n<h3 id=\"inciting-incident\">Inciting Incident: <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#inciting-incident\">#</a></h3>\n<p>Although I haven’t thought about how I want this image would look like, I’ve given a thought about what I need to do to make this happen.</p>\n<ol>\n<li>Create a template HTML</li>\n<li>Prepare data for the template HTML to generate final HTML</li>\n<li>Take a snapshot of generated HTML</li>\n</ol>\n<p>Eleventy is a static site generator, so it’s very good at doing 1) and 2).<br />\nFor 3), I’ll be using <a href=\"https://github.com/puppeteer/puppeteer/\">Puppeteer</a> for taking a snapshot.</p>\n<h2 id=\"act-ii-eleventy-is-very-good-at-templating\">ACT II: Eleventy is very good at templating <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#act-ii-eleventy-is-very-good-at-templating\">#</a></h2>\n<p>For 1) and 2), <a href=\"https://www.d-hagemeier.com/en/articles/en/articles/generate-social-media-preview-images/\">Generate Social Media Preview Images</a> by Dennis Hagemeier is quite helpful.</p>\n<p>Eleventy has this <a href=\"https://www.11ty.dev/docs/pagination/\">pagination</a> feature and despite its name, I can use this to iterate over a data set and create pages for individual chunks of data.</p>\n<p>I already have a “data set” which is my quote which is my main content for article in Sixty Six.</p>\n<p>Each of my article has this in its front matter:</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token punctuation\">---</span><br /><span class=\"token key atrule\">date</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'2014-02-13'</span><br /><span class=\"token key atrule\">quote</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">|</span><span class=\"token punctuation\">-</span><br />  You can't connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future.<br /><span class=\"token key atrule\">tags</span><span class=\"token punctuation\">:</span><br />  <span class=\"token punctuation\">-</span> Steve Jobs<br /><span class=\"token key atrule\">when</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'2005, Jun 12'</span><br /><span class=\"token key atrule\">cite</span><span class=\"token punctuation\">:</span> Stanford Commencement Address.<br /><span class=\"token punctuation\">---</span><br /></code></pre>\n<p>I already have whole quote which comes in very handy for this story.</p>\n<p>As for “create pages”, it can be done by “just” creating a template. It is rarely justified to say “just” in this kind of story but with Eleventy, I think it’s OK to say “just” here.</p>\n<p>I did follow Dennis Hagemeier’s tutorial with a few modifications.</p>\n<pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token punctuation\">---</span><br /><span class=\"token key atrule\">pagination</span><span class=\"token punctuation\">:</span><br />  <span class=\"token key atrule\">data</span><span class=\"token punctuation\">:</span> collections.posts<br />  <span class=\"token key atrule\">size</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><br />  <span class=\"token key atrule\">alias</span><span class=\"token punctuation\">:</span> preview<br /><span class=\"token key atrule\">permalink</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"/previews/{{ preview.data.page.fileSlug }}/index.html\"</span><br /><span class=\"token key atrule\">eleventyExcludeFromCollections</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span><br /><span class=\"token punctuation\">---</span></code></pre>\n<p>I want to name generated HTMLs same as my article’s and that is what <code>permalink: &quot;/previews/{{ preview.data.page.fileSlug }}/</code> is doing. I did need help of <code>console.log()</code> for figuring out to come up with <code>{{ preview.data.page.fileSlug }}</code>. It turned out <a href=\"https://www.11ty.dev/docs/collections/#collection-item-data-structure\">official document has this documented</a>.</p>\n<p>And here it is, after an hour or so, I’ve come up with the design:</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2020-05-09-ow3H5TJq@2x.png\" alt=\"Preview I've ended up with\" title=\"Final design for preview\" /></p>\n<p>Now I need to take screenshots.</p>\n<h2 id=\"midpoint-taking-screenshots\">Midpoint: Taking screenshots <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#midpoint-taking-screenshots\">#</a></h2>\n<p>Puppeteer does all the heavy work for me. From <a href=\"https://github.com/puppeteer/puppeteer/\">its README</a>, Puppeteer works like this:</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> puppeteer <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'puppeteer'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">const</span> browser <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> puppeteer<span class=\"token punctuation\">.</span><span class=\"token function\">launch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">const</span> page <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> browser<span class=\"token punctuation\">.</span><span class=\"token function\">newPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">await</span> page<span class=\"token punctuation\">.</span><span class=\"token function\">goto</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://example.com'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">await</span> page<span class=\"token punctuation\">.</span><span class=\"token function\">screenshot</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>path<span class=\"token operator\">:</span> <span class=\"token string\">'example.png'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token keyword\">await</span> browser<span class=\"token punctuation\">.</span><span class=\"token function\">close</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Now I need to figure out how to provide URLs of all the generated HTML and file name for <code>{path: 'PATH/FILE-NAME.png'}</code>.</p>\n<p>Tutorials I’ve mentioned earlier have done this via JSON file which is generated by Eleventy, and I’ve been following this path along as well.</p>\n<p>Again, from Dennis Hagemeier’s tutorial:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">[</span><br />  <span class=\"token punctuation\">{</span><br />    <span class=\"token property\">\"filename\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"import-tweets-from-twitter-api-in-11ty-en-preview\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token property\">\"path\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://www.d-hagemeier.com/assets/preview-images/import-tweets-from-twitter-api-in-11ty-en-preview.html\"</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">]</span></code></pre>\n<p>It does look simple, and I can imagine how this would be used in Puppeteer for taking screenshots.</p>\n<p>Then I took another look at <a href=\"https://dev.to/5t3ph/automated-social-sharing-images-with-puppeteer-11ty-and-netlify-22ln\">Stephanie Eckles’s article</a>. Her approach is a bit different from Dennis Hagemeier’s.</p>\n<p>She has a template which will be feed into Puppeteer as plain HTML, then she used generated JSON file(which is done by Eleventy) to manipulate that HTML. Puppeteer has <code>page.setContent()</code> method which can consume strings of HTML to <code>setContent</code> on <code>page</code>.</p>\n<p>Then I thought, could I combine these approaches together?</p>\n<p>Eleventy allows me to use <a href=\"https://www.11ty.dev/docs/languages/javascript/\">JavaScript as one of the template language</a> which means I can use Puppeteer in it and I’m sure I can use Pagination feature which provides data I need to generate HTMLs.</p>\n<p>At this point, I already have created HTMLs using Pagination feature, but I need to port that to JavaScript Template Language(Let’s call this <code>.11ty.js</code> from here on).</p>\n<p>I could’ve created a boilerplate HTML like Stephanie Eckles’s solution, but I decided to do all the HTML generation in <code>.11ty.js</code> since my entire HTML is about 50 lines or so.</p>\n<p>It was turned out to be a bad decision.<br />\nI’m sure I’m missing something but…:</p>\n<ul>\n<li>🗻 There is no <code>include</code> in <code>.11ty.js</code> - ↪ I have loaded it via <code>fs.readFileSync()</code></li>\n<li>🔎 Couldn’t find a way to use filters - ↪ Only filter I need was mine, so I imported it as a normal modules and use it as a normal function</li>\n<li>😢 I needed to do lots of <code>console.log()</code> to see where the data I need - ↪ I should’ve done TDD using Jest, so I could have used <code>toMatchSnapshot()</code>.</li>\n</ul>\n<h3 id=\"metatags-to-display-them-as-social-media-preview-images\">Metatags to display them as social media preview images <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#metatags-to-display-them-as-social-media-preview-images\">#</a></h3>\n<p>Despite my bad decision, I have made it work so let’s use them to display on social media. I always consult <a href=\"https://github.com/joshbuchea/HEAD\">HEAD by Josh Buchea</a> whenever I need to add metatags in <code>&lt;head&gt;</code> and it does indeed have <a href=\"https://github.com/joshbuchea/HEAD#social\">Social</a> section.</p>\n<p>I wanted to add <code>socialImage</code> field to each posts’ data, but couldn’t get it work as expected so:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span><br />  <span class=\"token attr-name\">property</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>og:image<span class=\"token punctuation\">\"</span></span><br />  <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>{{ site.url }}/previews/{{ page.fileSlug }}/preview.png<span class=\"token punctuation\">\"</span></span><br /><span class=\"token punctuation\">/></span></span></code></pre>\n<p>I did this instead which works fine, I think.<br />\n…And it works:</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2020-05-10-DRS76CHa@2x.png\" alt=\"Validated with Twitter Card Validator\" title=\"It is valid!\" /></p>\n<h2 id=\"finale\">Finale <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-06-auto-generate-ogp-image-with-eleventy-and-puppeteer/#finale\">#</a></h2>\n<p>Generating screenshots takes a lot of time, so I only do it when <code>process.env.ELEVENTY_ENV === 'production';</code>. I haven’t pushed it to GitHub, so I don’t know what will happen on Netlify build yet.</p>\n<p>I’m thinking about using <a href=\"https://www.netlify.com/build/plugins-beta/\">Netlify Build Plugins</a>. According to Phil Hawksworth, <a href=\"https://twitter.com/philhawksworth/status/1257284661874692097\">it can access to the cache between build</a> which sounds like a godsend to my situation.</p>\n<p>Exploring Netlify Build Plugins will be a great story.</p>\n<p>Finally, Netlify build is done: <code>Build time: 3m 17s. Total deploy time: 3m 27s</code> and last time I had deployed Sixty Six, it was <code>Build time: 1m 18s. Total deploy time: 1m 30s</code>.<br />\nFor now, I can live with it, but I won’t be porting this feature to any other blogs right now.</p>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2020-05-06T08:33:34Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/",
      "title": "Setting Up Webmention on Eleventy",
      "summary": "This is a story about setting up Webmention on Eleventy",
      "content_html": "<h2 id=\"when-you-own-your-contents-then-who-owns-reactions-for-them\">When you own your contents, then who owns reactions for them? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#when-you-own-your-contents-then-who-owns-reactions-for-them\">#</a></h2>\n<p class=\"explanation\">ACT I: Meet the Hero — their world, what they want, what they fear.</p>\n<p><a href=\"https://frontendweekly.tokyo/\">Frontend Weekly Tokyo</a> was used to be on Medium, but it has gone a bit rogue in my opinion. Eleventy and Netlify allow me to own my contents with ease, so I’ve decided to give them a try.</p>\n<p>Owning contents is the very foundation of IndieWeb. I wanted to expand my boundary a bit further.<br />\n“You are better connected” is one of three principles of IndieWeb which includes this statement:</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://indieweb.org/\">\n<p>Even replies and likes on other services can come back to your site so they’re all in one place.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— IndieWeb. <a href=\"https://indieweb.org/\">What is the IndieWeb?</a>, (2020, Apr 13)</figcaption>\n</figure>\n<h3 id=\"webmention-is-a-web-standard-to-help-me-to-connect\">Webmention is a Web standard to help me to connect <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#webmention-is-a-web-standard-to-help-me-to-connect\">#</a></h3>\n<p class=\"explanation\">Inciting Incident: Your Hero’s worst fears realized.</p>\n<p>So to answer the question, I should own reactions to my contents, but how can I do that?</p>\n<p>This is what <a href=\"https://www.w3.org/TR/webmention/\">Webmention</a> tries to solve.</p>\n<p>There are numbers of excellent tutorials on setting up Webmention on Eleventy and one I’m going to follow is <a href=\"https://mxb.dev/blog/using-webmentions-on-static-sites/\">Static Indieweb pt2: Using Webmentions</a> by Max Böck.</p>\n<p>He also shares <a href=\"https://github.com/maxboeck/eleventy-webmentions\">a basic starter template for Eleventy blogs with added support for webmentions on GitHub</a>.</p>\n<p>I’ll use these as my base to start the implementation.</p>\n<p>And this is where my journey begins.<br />\nThis is a story about implementing Webmention in Eleventy.</p>\n<h2 id=\"strategy-to-enable-webmention-on-virga\">Strategy to enable Webmention on Virga <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#strategy-to-enable-webmention-on-virga\">#</a></h2>\n<p class=\"explanation\">ACT II: The Hero makes a decision about how to resolve the problem created by the Inciting Incident.</p>\n<h3 id=\"diagnosis\">Diagnosis <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#diagnosis\">#</a></h3>\n<p>To enable Webmention, I need to do 1) Receive, 2) Transform the data, 3) Display the data on Post pages.</p>\n<ul>\n<li>I want to make it as portable as I can so that I can use this implementation in all of my blogs</li>\n<li>1) will involve with making the data available to the next step</li>\n<li>2) could be done using filter which can be a plugin</li>\n<li>However, 3) it involves with template so making it as a plugin would be difficult</li>\n</ul>\n<h3 id=\"guiding-policy\">Guiding Policy <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#guiding-policy\">#</a></h3>\n<ul>\n<li>Let’s not just “copy and paste” Max Böck’s implementation. Steal it, modify it and own it</li>\n<li>See if <a href=\"https://github.com/11ty/eleventy-cache-assets\"><code>eleventy-cache-assets</code></a> can be used to minimize my implementation</li>\n</ul>\n<h3 id=\"actions\">Actions <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#actions\">#</a></h3>\n<ul>\n<li>1) Receive: - Use <a href=\"https://webmention.io/\">webmention.io</a> as my endpoint - Use <code>_data/webmention.js</code> to fetch the data - Try out <a href=\"https://github.com/11ty/eleventy-cache-assets\"><code>eleventy-cache-assets</code></a></li>\n<li>2) Transform: Create filters - Use <a href=\"https://github.com/maxboeck/eleventy-webmentions/blob/master/.eleventy.js#L39-L88\"><code>webmentionsForUrl</code></a> as the base</li>\n<li>3) Display: Create templates - See <a href=\"http://localhost:8080/posts/2020-05-03-setting-up-webmentions-on-eleventy/#heading-ui:-fat-marker-sketch\">Fat marker sketch</a></li>\n</ul>\n<h4 id=\"ui-fat-marker-sketch\">UI: <a href=\"https://basecamp.com/shapeup/1.3-chapter-04#fat-marker-sketches\">Fat marker sketch</a> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#ui-fat-marker-sketch\">#</a></h4>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/webmention-virga.png\" alt=\"Webmention sketch\" title=\"Fat marker sketch\" /></p>\n<h3 id=\"receiving-webmention\">Receiving Webmention <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#receiving-webmention\">#</a></h3>\n<p class=\"explanation\">First Reversal: The Hero makes the first major progress in their journey.</p>\n<p>In order to receive webmentions, I need to declare an endpoint to accept them.<br />\nI could host this on my server, but for Eleventy (in the case of static sites), I need a third-party service for this.<br />\nWhich is where <a href=\"https://webmention.io/\">webmention.io</a> comes in.</p>\n<h4 id=\"sign-in-with-webmentionio\">Sign in with <a href=\"http://webmention.io/\">webmention.io</a> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#sign-in-with-webmentionio\">#</a></h4>\n<p><a href=\"http://webmention.io/\">Webmention.io</a> is a free service and using <a href=\"https://indieauth.com/\">IndieAuth</a> to sign in.</p>\n<p>I could sign it in using Twitter or GitHub, but I will use my e-mail to sign in.</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token property\">\"author\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Yuya Saito\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"mail\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"hello@studiomohawk.com\"</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>I have this field filled at <code>_data/site.json</code> which in result outputs <code>&lt;link rel=&quot;me&quot; href=&quot;mailto:&quot;&gt;</code> so I can go ahead enter my URL at <a href=\"https://webmention.io/\">Webmention.io</a>.</p>\n<h4 id=\"accepting-webmentions\">Accepting Webmentions <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#accepting-webmentions\">#</a></h4>\n<p>After successful sign in, <a href=\"http://webmention.io/\">Webmention.io</a> will navigate me to <code>https://webmention.io/settings</code> and there is it a snippet to copy &amp; paste. Handy.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>webmention<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://webmention.io/virga.frontendweekly.com/webmention<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span><br /><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>link</span> <span class=\"token attr-name\">rel</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>pingback<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">href</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://webmention.io/virga.frontendweekly.com/xmlrpc<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span></code></pre>\n<p>I can copy &amp; paste this into <code>&lt;head&gt;</code>.</p>\n<h4 id=\"but-will-anybody-send-webmention\">But, will anybody send Webmention? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#but-will-anybody-send-webmention\">#</a></h4>\n<p>When I’m writing this I’ve already finished implementing a part where I fetch webmentions, so I can answer this question.</p>\n<p>Answer is no. At least, not for me.<br />\nSo I need another tool. <a href=\"https://brid.gy/\">Bridgy</a>.</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://mxb.dev/blog/using-webmentions-on-static-sites/\">\n<p>Bridgy is another free service that can monitor your Twitter, Facebook or Instagram activity and send a webmention for every like, reply or repost you receive.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Max Böck. <a href=\"https://mxb.dev/blog/using-webmentions-on-static-sites/\">Static Indieweb pt2: Using Webmentions</a>, (2019, Jan 10)</figcaption>\n</figure>\n<p>I went to Bridgy and connected with my Twitter account.<br />\nI have THREE(!) webmentions (which are not mine) on virga.frontendweekly.tokyo.<br />\nWell, three is better than zero.</p>\n<p>Because you see, this story about implementing Webmentions on Eleventy is actually the second try for me.<br />\nWhat happened to the first one?<br />\nI DIDN’T have any webmentions on Virga, so I couldn’t go further.</p>\n<p>Having a not so popular blog which tries to tell a story about Webmention turned out to be a challenge, I must say.</p>\n<h4 id=\"fetching-webmentions\">Fetching Webmentions <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#fetching-webmentions\">#</a></h4>\n<p>I have rediscovered the power of Eleventy when I look at the starter template by Max Böck.</p>\n<p>I can use JavaScript at <code>src/_data</code> to fetch data, and the object will be available to all templates. I somehow believed that data in <code>src/_date</code> have to be JSON, but they just need to return object.</p>\n<p>His <a href=\"https://github.com/maxboeck/eleventy-webmentions/blob/master/_data/webmentions.js\">example code is here</a>.</p>\n<p>My favorite bit from his code is here:</p>\n<pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">const</span> cache <span class=\"token operator\">=</span> <span class=\"token function\">readFromCache</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>lastFetched<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> cache<span class=\"token punctuation\">;</span><br /><br />  <span class=\"token comment\">// Only fetch new mentions in production</span><br />  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">ELEVENTY_ENV</span> <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span> <span class=\"token operator\">||</span> <span class=\"token operator\">!</span>lastFetched<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">const</span> feed <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetchWebmentions</span><span class=\"token punctuation\">(</span>lastFetched<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>feed<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />      <span class=\"token keyword\">const</span> webmentions <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />        lastFetched<span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toISOString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br />        children<span class=\"token operator\">:</span> <span class=\"token function\">mergeWebmentions</span><span class=\"token punctuation\">(</span>cache<span class=\"token punctuation\">,</span> feed<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br />      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br /><br />      <span class=\"token function\">writeToCache</span><span class=\"token punctuation\">(</span>webmentions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />      <span class=\"token keyword\">return</span> webmentions<span class=\"token punctuation\">;</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">}</span><br /><br />  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>cache<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">.</span>length<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> webmentions loaded from cache</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token keyword\">return</span> cache<span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<ul>\n<li>Fetching webmentions occurs only in production.</li>\n<li>Fetched webmentions are cached.</li>\n<li>If there are cached data, it fetches data from <code>lastFetched</code>.</li>\n</ul>\n<p>This is brilliant, but I wanted to try <a href=\"https://github.com/11ty/eleventy-cache-assets\"><code>eleventy-cache-assets</code></a> for more versatility.</p>\n<h4 id=\"swap-the-cache-implementation-with-eleventy-cache-assets\">Swap the cache implementation with <a href=\"https://github.com/11ty/eleventy-cache-assets\"><code>eleventy-cache-assets</code></a> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#swap-the-cache-implementation-with-eleventy-cache-assets\">#</a></h4>\n<p>Zach Leatherman has shared <a href=\"https://github.com/11ty/eleventy-cache-assets\"><code>eleventy-cache-assets</code></a> a couple weeks ago.</p>\n<p>I can use this to remove <code>writeToCache()</code> and <code>readFromCache()</code> functions from Max Böck’s original.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// url is API endpoint</span><br /><span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">CacheAsset</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><br />  duration<span class=\"token operator\">:</span> <span class=\"token string\">'1d'</span><span class=\"token punctuation\">,</span><br />  type<span class=\"token operator\">:</span> <span class=\"token string\">'json'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This means cache this request to <code>url</code> for 1 day and save it as json.<br />\nI could still use <code>process.env.ELEVENTY_ENV === 'production'</code> to prevent running in PROD, but this will be cached for 1 day, so I don’t think I need to worry about performance anymore.</p>\n<p>I wish there is a way to <code>read</code> the cache data, or maybe there already is.</p>\n<h2 id=\"transform-the-data\">Transform the data <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#transform-the-data\">#</a></h2>\n<p class=\"explanation\">Midpoint: The point of no return. Something big and unexpected happens, and now there’s no going back to the Hero’s normal life.</p>\n<p>Now I need transform this fetched data to be UI ready.</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br />  <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"entry\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"author\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"card\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Yuya Saito\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token property\">\"photo\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://webmention.io/avatar/pbs.twimg.com/b80465a02c7f06aa18d2116b0661ca1e7965c7b81f79d6ec217db070ae6dc5ae.png\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://twitter.com/cssradar\"</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://twitter.com/cssradar/status/1256682246607474688\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"published\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2020-05-02T20:29:30+00:00\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-received\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2020-05-02T20:59:36Z\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-id\"</span><span class=\"token operator\">:</span> <span class=\"token number\">790847</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-source\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://brid-gy.appspot.com/repost/twitter/frontend_weekly/1256607056313888770/1256682246607474688\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-target\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token property\">\"text\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Virga: Creating Plugins for Eleventy virga.frontendweekly.tokyo/posts/2020-04-…\"</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"repost-of\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-property\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"repost-of\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"wm-private\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>This is one of the Webmentions I received. (Well, I send this one.)<br />\nLet’s look at <code>wm-property</code> field since this piece of data will define how to display the data.</p>\n<p>According to <a href=\"http://webmention.io/\">webmention.io</a>’s README, there are 6 properties:</p>\n<ul>\n<li>in-reply-to</li>\n<li>like-of</li>\n<li>repost-of</li>\n<li>bookmark-of</li>\n<li>mention-of</li>\n<li>rsvp</li>\n</ul>\n<p>I don’t know what <code>rsvp</code> is, and I’ll ignore that and <code>bookmark-of</code> for now.<br />\nIn the world of Twitter, <code>repost-of</code> is Retweet, and I can tell others by its name.</p>\n<p>Before I start transforming the data, I need to know how I would transform them so here there are:</p>\n<p>IF <code>wm-property</code> === <code>repost-of</code> AND <code>like-of</code>, I want something like this:</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/repost-like-of-webmention-virga.png\" alt=\"repost-of and like-of\" title=\"Fat marker sketch for repost-of and like-of\" /></p>\n<p>ELSE IF <code>wm-property</code> === <code>mention-of</code> AND <code>in-reply-to</code>, I want something like this:</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/in-reply-to-mention-of-webmention-virga.png\" alt=\"mention-of and in-reply-to\" title=\"Fat marker sketch for mention-of and in-reply-to\" /></p>\n<h3 id=\"html-css-and-filter\">HTML, CSS and filter <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#html-css-and-filter\">#</a></h3>\n<p>Low Point: The Hero loses all hope, believes all is lost. But out of this darkness comes a plan to win the movie.{explanation}</p>\n<h4 id=\"filter-webmentiondata\">Filter: <code>webmentionData()</code> <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#filter-webmentiondata\">#</a></h4>\n<p><a href=\"http://webmention.io/\">Webmention.io</a> gives me Webmention data associated with my domain which is fetch by <code>src/_data/webmentions.js</code>.<br />\nIn another word, the data have all the Webmentions for Virga, but my plan is to display Webmentions related to articles.</p>\n<p><code>webmentionData()</code> filter does exactly this and is almost same as <a href=\"https://github.com/maxboeck/eleventy-webmentions/blob/master/.eleventy.js#L39-L88\">Max Böck’s</a>.</p>\n<h4 id=\"htmlnunjucks-css\">HTML(Nunjucks) &amp; CSS <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#htmlnunjucks-css\">#</a></h4>\n<p>When it comes to build UIs, HTML is the center of my universe. However, I need contents when I design UIs and when I design, I do it using HTML &amp; CSS with a help with fat marker sketches. (I’ve started to use <a href=\"https://excalidraw.com/\">Excalidraw</a> for doing this recently.)</p>\n<p>I’ve made the fat marker sketch in strategy phase because it helps me navigate.<br />\n<code>src/_data/webmentions.js</code> and <code>webmentionData()</code> have given me contents I need for design.</p>\n<p>Now it’s time to do HTML. Don’t think about the style yet, but think about structure. I mean, really. Think hard until I could almost start to see HTML when I look at the fat marker sketch.</p>\n<p>Structuring means almost same as naming because naming means almost same as finding patterns and patterns “[…] describe[s] the problem and solution to that problem, in such way that you can use this solution a million times over, without ever doing it the same way twice.” (Christopher Alexander, Sara Ishikawa and Murray Silverstein, A Pattern Language: Towns, Buildings, Construction. (1977)).</p>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/2020-05-05-fQ4kWrUv@2x.png\" alt=\"UI I've ended up with\" title=\"Final UI\" /></p>\n<p>This is the UI what I’ve ended up with for now.<br />\nI have introduced 3 objects(<a href=\"http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/\">Media Object</a>, <a href=\"https://every-layout.dev/layouts/sidebar/\">Sidebar</a> and <a href=\"https://every-layout.dev/layouts/switcher/\">Switcher</a>, which I’ve ended up not using it) to CSS. I have also learned how to use <a href=\"https://mozilla.github.io/nunjucks/templating.html#macro\">macro</a>.</p>\n<h2 id=\"finale\">Finale <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-05-03-setting-up-webmentions-on-eleventy/#finale\">#</a></h2>\n<p class=\"explanation\">The Hero confronts that obstacle by making a leap of faith that allows them to overcome it.</p>\n<ul>\n<li>One of the hardest things in this journey which I’ve mentioned earlier is I don’t have many Webmentions to display 😢.</li>\n<li>All the code to fetch and display Webmention is only on Virga for now, but I want this in all of my blogs, so I’ll figure out how to port this to MOLLE.</li>\n<li>I wish there is a way to make a plugin for the template (Second time.) - Could shortcodes grant me this with?</li>\n<li>I’ve used Three-act structure to guide me write this story. I should have Act Ⅲ but climax of this story is all in UI.</li>\n</ul>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2020-05-03T03:49:56Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/",
      "title": "Creating Plugins for Eleventy",
      "summary": "A story about creating plugins for Eleventy",
      "content_html": "<h2 id=\"preface\">Preface <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#preface\">#</a></h2>\n<p>Before I introduced my story about creating plugins for Eleventy, let me write about How I’m imaging to publish stories on Virga.</p>\n<p>Virga was born to learn about Eleventy, so I forked <a href=\"https://hylia.website/\">Hylia</a> as a starting point so Virga is also a starter kit for Eleventy. I’m using it for 2 other blogs(<a href=\"https://frontendweekly.tokyo/\">Frontend Weekly Tokyo</a> and <a href=\"https://sixtysix.frontendweekly.tokyo/\">Sixty Six</a>) and I’ve started use Virga as a blog since I didn’t think anyone actually using this as a starter kit.</p>\n<p>I’ve written a few articles mostly about Virga itself, and I have nothing to left to write.<br />\nNow I need to think about what I’m going to write. I know. This is where blogging becomes difficult, right?</p>\n<p>So here it is, this is what I’m doing about it.</p>\n<p>I write a story about what I’m going to implement, and I write about it as I do. I don’t even know how this story is going to be and that I think makes it interesting.<br />\nThis is like a diary, but I’ll call it a story anyway.</p>\n<p>This is a story about implementing plugins for Eleventy.</p>\n<h2 id=\"molle-ˈmɒlliː\">MOLLE (<code>/ˈmɒl.liː/</code>) <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#molle-%CB%88m%C9%92lli%CB%90\">#</a></h2>\n<p>What do I want for plugins? And what does “plugins” mean in Eleventy?<br />\nTo answer the latter, I’m using plugins such as <a href=\"https://github.com/11ty/eleventy-plugin-rss\"><code>eleventy-plugins-rss</code></a> and <a href=\"https://github.com/11ty/eleventy-plugin-syntaxhighlight\"><code>eleventy-plugin-syntaxhighlight</code></a> but I haven’t look at how they work.</p>\n<p><a href=\"https://github.com/brob/eleventy-plugin-blog-tools\"><code>eleventy-plugin-blog-tools</code></a> by Bryan Robinson is why I thought about making plugin at first.</p>\n<p>I have 3 blogs including this one, and they all use same 5 filters and 2 transforms. I update these scarcely but whenever I do, I have to do it 3 times.</p>\n<p>This is the very problem I’m trying to fix it with my soon-to-be created plugins and this is where MOLLE comes in.</p>\n<p>MOLLE is where I place my tiny plugins, and I want to tryout monorepo using <a href=\"https://lerna.js.org/\">Lerna</a>. While I could have published my plugins at npm, but I also want to try <a href=\"https://github.com/features/packages\">GitHub Packages</a>.</p>\n<p>This is where my journey begins.</p>\n<p>What’s with the name?<br />\nMOLLE is an acronym for Modular Lightweight Load-carrying Equipment and according to Wikipedia, “It is used to define the current generation of load-bearing equipment and backpacks used by a number of NATO armed forces, especially the British Army and the United States Army.”<br />\nI think the name rings true to what it’s going to achieve.</p>\n<h2 id=\"figuring-out-lerna\">Figuring out Lerna <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#figuring-out-lerna\">#</a></h2>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://lerna.js.org/\">\n<p>Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://lerna.js.org/\">Lerna</a></figcaption>\n</figure>\n<p>In my word, Lerna will help me to manage multi-package in one repository.<br />\nI won’t go into deep dive on Lerna since I’m figuring it out right now.</p>\n<p>While <a href=\"https://github.com/lerna/lerna\">official GitHub repo page</a> offers detailed documentation, I’ve grasped the gist of it by reading 2 articles below:</p>\n<ul>\n<li><a href=\"https://dev.to/anonimoconiglio/what-is-a-mono-repository-and-why-you-should-try-lerna-57lm\">What is a mono-repository and why you should try Lerna</a> by Santiago</li>\n<li><a href=\"https://dev.to/jody/using-lerna-to-manage-your-javascript-monorepo-4eoo\">Using Lerna to manage your JavaScript monorepo</a> by Jody Heavener</li>\n</ul>\n<p>I want to choose which plugin to install even though I need most of the plugins to run my blogs. Therefore, each of my plugins are going to have different version. This is what “Independent mode” means in Lerna.<br />\nAnd that’s what <code>lerna init --independent</code> does.</p>\n<p>There are many commands available on Lerna, but so far I’ve only used <code>lerna publish</code> which publishes updated packages to the registry.</p>\n<p>I’m going to need to learn more about Lerna, but I initialized it and am able to publish my packages to GitHub Packages (with a couple of mistakes along the way, of course).</p>\n<p>My current config for Lerna looks like this:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span><br />  <span class=\"token property\">\"npmClient\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"npm\"</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"command\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token property\">\"publish\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />      <span class=\"token property\">\"ignoreChanges\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"ignored-file\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"*.md\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />      <span class=\"token property\">\"message\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"chore(release): publish\"</span><span class=\"token punctuation\">,</span><br />      <span class=\"token property\">\"registry\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://npm.pkg.github.com\"</span><br />    <span class=\"token punctuation\">}</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"packages\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"packages/*\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"independent\"</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"configuring-for-github-packages\">Configuring for GitHub Packages <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#configuring-for-github-packages\">#</a></h2>\n<p>Publishing a package to GitHub Packages is same process as npm org, and I already have done it before at work.</p>\n<p>I needed to generate GitHub Personal Token since I forgot I already had one for GitHub Packages (Dear future me, you should save tokens on 1 password whenever you make new one).</p>\n<p>I need have <code>.npmrc</code> at my project root which have this.</p>\n<pre class=\"language-text\"><code class=\"language-text\">//npm.pkg.github.com/:_authToken=${GITHUB_PKG_TOKEN}<br />registry=https://npm.pkg.github.com/frontendweekly</code></pre>\n<p>I use <a href=\"https://github.com/direnv/direnv\">direnv</a> to load and unload environment variables so actual value of <code>${GITHUB_PKG_TOKEN}</code> is in <code>.envrc</code> file.</p>\n<p>I haven’t figure out how to use GitHub Actions to automate publishing a package yet but that’s something I am going to do in the future.</p>\n<h2 id=\"what-makes-it-a-plugin-in-eleventy\">What makes it a plugin in Eleventy? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#what-makes-it-a-plugin-in-eleventy\">#</a></h2>\n<p>According to official document, “Plugins are custom code that Eleventy can import into a project from an external repository.”</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> pluginRss <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@11ty/eleventy-plugin-rss'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">eleventyConfig</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addPlugin</span><span class=\"token punctuation\">(</span>pluginRss<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And this is how a plugin might be “imported” from an “external repository”.</p>\n<p>I’ve read some of the plugins’ code, but I didn’t know why I want to do <code>addPluin()</code> when you could do <code>addFilter()</code> or <code>addTransform()</code>?</p>\n<p><a href=\"https://github.com/brob/eleventy-plugin-blog-tools\"><code>eleventy-plugin-blog-tools</code></a> by Bryan Robinson offers 5 shortcodes, 2 filters and 1 collection as a plugin and I can import all by doing <code>addPluin()</code> which is handy for sure.</p>\n<p>And I could do that by setting up <code>.eleventy.js</code> as I would normally do in Eleventy.<br />\nNow I see what makes a plugin a plugin.</p>\n<p>I’ve already had 4 packages ported to MOLLE, and I’ve published each packages, but those packages don’t have <code>.eleventy.js</code>.<br />\nI should have come to that realization before publishing packages, however I have a good idea to save my mistake.</p>\n<p>Published packages are going to stay as there are. Just packages. But I can import them individually if I want.<br />\nAnd I’ll make a new package which will be a proper Eleventy plugin, which has all filters and transforms.</p>\n<h2 id=\"making-of-eleventy-plugin\">Making of Eleventy plugin <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#making-of-eleventy-plugin\">#</a></h2>\n<p>I’ve already have <a href=\"https://github.com/orgs/frontendweekly/packages\">published 4 packages on GitHub</a> so I would say it’s good time to make an Eleventy plugins.</p>\n<p>As Joe Armstrong who is a creator of Erlang wrote “The first in acquiring any new skill is not being able to do your own thing but being able to reproduce what other people before you.”, I’ve looked at how <a href=\"https://github.com/11ty/eleventy-plugin-rss\"><code>eleventy-plugins-rss</code></a> implements a plugin and stole useful bits (Thank you, Mr. Zach Leatherman) and ended up like this:</p>\n<pre class=\"language-text\"><code class=\"language-text\">.<br />├── example/<br />├── node_modules<br />├── .eleventy.js<br />├── .eleventyignore<br />├── .npmignore<br />├── LICENSE.md<br />├── package-lock.json<br />├── package.json<br />└── README.md</code></pre>\n<p>Inside of <code>.eleventy.js</code>, I have:</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> filterDateOrdinalSuffix <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../filter-date-with-ordinal-suffix'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> filterDateIso <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../filter-date-iso'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> transformHtmlMin <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../transform-htmlmin'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> transformEnhancePostHtml <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../transform-enhance-post-html'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">eleventyConfig</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addFilter</span><span class=\"token punctuation\">(</span><span class=\"token string\">'dateOrdinalSuffixFilter'</span><span class=\"token punctuation\">,</span> filterDateOrdinalSuffix<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addFilter</span><span class=\"token punctuation\">(</span><span class=\"token string\">'dateIsoFilter'</span><span class=\"token punctuation\">,</span> filterDateIso<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addTransform</span><span class=\"token punctuation\">(</span><span class=\"token string\">'htmlmin'</span><span class=\"token punctuation\">,</span> transformHtmlMin<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addTransform</span><span class=\"token punctuation\">(</span><span class=\"token string\">'enhancePostHtml'</span><span class=\"token punctuation\">,</span> transformEnhancePostHtml<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And this is how I would use it:</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> molle <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@frontendweekly/molle'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">config</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  config<span class=\"token punctuation\">.</span><span class=\"token function\">addPlugin</span><span class=\"token punctuation\">(</span>molle<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Although I haven’t use it on my blog yet, I have an <code>example</code> dir to confirm it seems working as intended.</p>\n<h2 id=\"coming-back-to-lerna\">Coming back to Lerna <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#coming-back-to-lerna\">#</a></h2>\n<p>As I’ve mentioned above, I have this in <code>.eleventy.js</code>.<br />\nShould I make those <code>require</code>s from registry?<br />\nThe answer is Yes because I want to update individual packages without breaking <code>molle</code>.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> filterDateOrdinalSuffix <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../filter-date-ordinal-suffix'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> filterDateIso <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../filter-date-iso'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> transformHtmlMin <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../transform-htmlmin'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> transformEnhancePostHtml <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../transform-enhance-post-html'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I made the change and run <code>npx lerna bootstrap</code>.<br />\nI don’t know what exactly <code>lerna bootstrap</code> does, and I thought it’ll install all packages I’ve specified in the code.</p>\n<p>Nope.</p>\n<p>Looks like I need to do that manually, so I did:</p>\n<pre class=\"language-bash\"><code class=\"language-bash\">npx lerna <span class=\"token function\">add</span> @frontendweekly/filter-date-ordinal-suffix packages/molle --registry https://npm.pkg.github.com<br />npx lerna <span class=\"token function\">add</span> @frontendweekly/filter-date-iso packages/molle --registry https://npm.pkg.github.com<br />npx lerna <span class=\"token function\">add</span> @frontendweekly/transform-enhance-post-html packages/molle --registry https://npm.pkg.github.com<br /><span class=\"token comment\"># ... and other dependencies</span></code></pre>\n<p>It seems like I have to do this for every dependency I need to add, but this does the tricks.</p>\n<h2 id=\"taking-out-molle-for-spin\">Taking out MOLLE for spin <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#taking-out-molle-for-spin\">#</a></h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> @frontendweekly/molle --save</code></pre>\n<p>and add this at <code>.eleventy.js</code> and of course, removing local filters and transforms…</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> molle <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@frontendweekly/molle'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">config</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  config<span class=\"token punctuation\">.</span><span class=\"token function\">addPlugin</span><span class=\"token punctuation\">(</span>molle<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>… and It works 🎉</p>\n<p>MOLLE now lives in <a href=\"https://github.com/frontendweekly/molle\">https://github.com/frontendweekly/molle</a> and I’m using it on Virga as I write this very sentence.</p>\n<h2 id=\"retrospect\">Retrospect <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-30-creating-plugins-for-eleventy/#retrospect\">#</a></h2>\n<ul>\n<li>Two of the hard things in this journey were coming up with the name “MOLLE” and Lerna</li>\n<li>I actually didn’t write any new code. I’ve moved them to new place but while doing it, I’ve added unit tests for most of them</li>\n<li>GitHub Packages is good. I didn’t have to think about it after I have configuration for it</li>\n<li>I wish there is a way to make a plugin for template</li>\n<li>I have few more pieces of codes I need to move to MOLLE</li>\n</ul>\n<p>Well, then until next journey.</p>\n",
      "date_published": "2020-04-30T10:46:06Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/",
      "title": "Eleventy with Rollup",
      "summary": "My favorite languages are HTML and CSS, but sometimes I do need JavaScript and when I do I use Rollup",
      "content_html": "<p>I’ve written on <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/\">“Eleventy with Theo, Sass and PostCSS”</a> which is about how to utilize Eleventy JavaScript Templates to build Theo, Sass and PostCSS.</p>\n<p>This time, I’ll demonstrate how to build JavaScript using Rollup with the same method I’ve mentioned above.</p>\n<h2 id=\"what-is-rollup\">What is Rollup? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/#what-is-rollup\">#</a></h2>\n<p>According to Rollup guide:</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://rollupjs.org/guide/en/\">\n<p>Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://rollupjs.org/guide/en/\">rollup.js/guide</a></figcaption>\n</figure>\n<p>If you like to add some JavaScript into Eleventy, having Rollup to bundle JavaScript files comes in handy.</p>\n<h2 id=\"rollup-config-file\">Rollup config file <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/#rollup-config-file\">#</a></h2>\n<p>Rollup does recommend having a config file so…</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> resolve <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@rollup/plugin-node-resolve'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> commonjs <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@rollup/plugin-commonjs'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>terser<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'rollup-plugin-terser'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  input<span class=\"token operator\">:</span> <span class=\"token string\">'src/_js/main.js'</span><span class=\"token punctuation\">,</span><br />  plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token function\">commonjs</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    file<span class=\"token operator\">:</span> <span class=\"token string\">'dist/_js/bundle.js'</span><span class=\"token punctuation\">,</span><br />    format<span class=\"token operator\">:</span> <span class=\"token string\">'iife'</span><span class=\"token punctuation\">,</span><br />    sourcemap<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><br />    plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token function\">terser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This is the config file for this example. You can do a lot in this config so if you’re interested to learn, <a href=\"https://rollupjs.org/guide/en/#configuration-files\">please read official guide</a>.</p>\n<p>I’ll use this in both Eleventy JavaScript Templates and CLI.</p>\n<h2 id=\"eleventy-javascript-templates\">Eleventy JavaScript Templates <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/#eleventy-javascript-templates\">#</a></h2>\n<p>Let’s look at Eleventy JavaScript Templates.<br />\nI’d say 99% of this code comes <a href=\"https://rollupjs.org/guide/en/#programmatically-loading-a-config-file\">from the official guide</a>.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> rollup <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'rollup'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> loadConfigFile <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'rollup/dist/loadConfigFile'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>resolve<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token keyword\">const</span> rollupConfigFile <span class=\"token operator\">=</span> <span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'../../rollup.config.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token keyword\">class</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">async</span> <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token comment\">// Stolen from:</span><br />    <span class=\"token comment\">// https://rollupjs.org/guide/en/#programmatically-loading-a-config-file</span><br />    <span class=\"token function\">loadConfigFile</span><span class=\"token punctuation\">(</span>rollupConfigFile<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>format<span class=\"token operator\">:</span> <span class=\"token string\">'iife'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><br />      <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>options<span class=\"token punctuation\">,</span> warnings<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />        <span class=\"token keyword\">const</span> option <span class=\"token operator\">=</span> options<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><br />        <span class=\"token comment\">// \"warnings\" wraps the default `onwarn` handler passed by the CLI.</span><br />        <span class=\"token comment\">// This prints all warnings up to this point:</span><br />        console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">We currently have </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>warnings<span class=\"token punctuation\">.</span>count<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> warnings</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />        <span class=\"token comment\">// This prints all deferred warnings</span><br />        warnings<span class=\"token punctuation\">.</span><span class=\"token function\">flush</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />        <span class=\"token comment\">// options is an \"inputOptions\" object with an additional \"output\"</span><br />        <span class=\"token comment\">// property that contains an array of \"outputOptions\".</span><br />        <span class=\"token comment\">// The following will generate all outputs and write them to disk the same</span><br />        <span class=\"token comment\">// way the CLI does it:</span><br />        <span class=\"token keyword\">const</span> bundle <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> rollup<span class=\"token punctuation\">.</span><span class=\"token function\">rollup</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />        <span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">.</span>output<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>bundle<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />        <span class=\"token comment\">// You can also pass this directly to \"rollup.watch\"</span><br />        rollup<span class=\"token punctuation\">.</span><span class=\"token function\">watch</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />      <span class=\"token punctuation\">}</span><br />    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>So this code does “loadConfigFile”:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> loadConfigFile <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'rollup/dist/loadConfigFile'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token operator\">...</span><br /><span class=\"token keyword\">const</span> rollupConfigFile <span class=\"token operator\">=</span> <span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'../../rollup.config.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And “bundle” JavaScript:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> bundle <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> rollup<span class=\"token punctuation\">.</span><span class=\"token function\">rollup</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And “write” file:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">await</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">.</span>output<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>bundle<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This will also write a map file as well.</p>\n<p>Finally, “watch” file changes:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">rollup<span class=\"token punctuation\">.</span><span class=\"token function\">watch</span><span class=\"token punctuation\">(</span>option<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>If you’re familiar with CLI of Rollup, you might see the similarities.</p>\n<h3 id=\"usage-of-cli-for-production-build\">Usage of CLI for production build <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-04-05-eleventy-with-rollup/#usage-of-cli-for-production-build\">#</a></h3>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token property\">\"build:js\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"rollup -c\"</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p><code>rollup -c</code> means build JavaScript files with the config file.<br />\nSo if you’ve set up a config file, you can do production build very easily.</p>\n",
      "date_published": "2020-04-05T11:13:14Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/",
      "title": "Eleventy with Theo, Sass and PostCSS",
      "summary": "You can use Design Token in Eleventy and here's how I might do it",
      "content_html": "<p>Eleventy is very flexible on how you want to process a file. In the recent post <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/\">“How Virga processes PostCSS”</a>, I explained how I use JavaScript as Eleventy templates to process PostCSS.<br />\nWith the same idea with little changes, you can do more complex process.</p>\n<p>I’ll demonstrate this in this post with using Theo, Sass and PostCSS(again).<br />\nBefore I get into the details, I believe I owe an explanation on Theo and Sass.</p>\n<p>If you want to see the example repo I have created for this post, It’s at <a href=\"https://github.com/frontendweekly/11ty-theo-sass-postcss-example\">11ty-theo-sass-postcss-example</a>.</p>\n<h2 id=\"what-is-theo\">What is Theo? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#what-is-theo\">#</a></h2>\n<p>Theo is an abstraction for transforming and formatting Design Tokens which is open sourced by Salesforce.</p>\n<p>In short, Theo transforms yaml files which define Design Tokens into various formats like <code>sass variables</code>.</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://www.lightningdesignsystem.com/design-tokens/\">\n<p>Design tokens are the visual design atoms of the design system — specifically, they are named entities that store visual design attributes. We use them in place of hard-coded values (such as hex values for color or pixel values for spacing) in order to maintain a scalable and consistent visual system for UI development.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://www.lightningdesignsystem.com/design-tokens/\">Design Tokens</a></figcaption>\n</figure>\n<p>This is how Design Tokens are defined in Lightning Design System of Salesforce.</p>\n<p>Design Tokens now have own <a href=\"https://github.com/design-tokens/community-group\">W3C Community Group</a> and I’m really excited about this.</p>\n<h2 id=\"dart-sass-not-node-sass\">Dart Sass, not Node Sass <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#dart-sass-not-node-sass\">#</a></h2>\n<p>Have you noticed that Sass has changed its primary implementation of Sass?</p>\n<p>Sass was originally written in Ruby and then LibSass is a C/C++ port of the Sass engine. LibSass is just a library, so it has been used with a wrapper like Node Sass.</p>\n<p>Now Sass is written in Dart, and it is the primary implementation of Sass which means it gets new features before any other implementation.</p>\n<p>In this post, when I mention Sass, I’m taking about Dart Sass.</p>\n<p>You can install Dart Sass via <code>npm</code>.</p>\n<pre><code>npm install sass (--save-deps|--save)\n</code></pre>\n<h2 id=\"importing-theos-yaml-into-sass\">Importing Theo’s <code>yaml</code> into Sass <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#importing-theos-yaml-into-sass\">#</a></h2>\n<p>Theo provides a command line tool to transform <code>yaml</code> files into various format.</p>\n<pre><code>theo tokens.yml --format map.scss --dest .\n</code></pre>\n<p>Above command means <code>tokens.yml</code> file will be transformed into <code>map.scss</code> format and output file in <code>.</code> (which is same directly as the command executed).</p>\n<p>The output file, in this case will be <code>tokens.map.scss</code> which contains something like this:</p>\n<pre class=\"language-sass\"><code class=\"language-sass\"><span class=\"token variable-line\"><span class=\"token variable\">$tokens-map</span><span class=\"token punctuation\">:</span> (</span><br />  <span class=\"token string\">'${props}'</span><span class=\"token selector\">: (${value})</span><span class=\"token selector\">,</span><br /><span class=\"token selector\">);</span></code></pre>\n<p>However, Sass has <code>importer</code> option which can be utilized to do some thing like this in Sass file.</p>\n<pre class=\"language-sass\"><code class=\"language-sass\"><span class=\"token atrule-line\"><span class=\"token atrule\">@import</span> './tokens/token.yml';</span></code></pre>\n<p><code>importer</code> executes JavaScript function(s) when a <code>@use</code> rule or an <code>@import</code> rule is encountered.<br />\nThat means Sass can run <code>theo</code> in <code>importer</code> function to do the transformation.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">/* Stolen from https://basalt.io/blog/theo-design-tokens-using-node-sass-importer-for-any-build-method */</span><br /><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>resolve<span class=\"token punctuation\">,</span> parse<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> theo <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'theo'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token comment\">/**<br /> * Theo Design Token Sass Importer<br /> * Import scss variables from Yaml files directly<br /> * @param {string} url - path to the file passed into import statement, i.e. `@import \"design-tokens.yml\";`<br /> * @param {string} prev - path to the file the import statement is located at, useful for calculating relative paths<br /> * @link &lt;https://www.npmjs.com/package/theo><br /> */</span><br /><span class=\"token keyword\">function</span> <span class=\"token function\">theoImporter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">url<span class=\"token punctuation\">,</span> prev</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token comment\">// If the imported file doesn't end in `.yml` or `.yaml`, then `return null` early to tell node-sass that we're not going to do anything. It'll go on to the next function or just try to handle the import itself.</span><br /><br />  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">\\.ya?ml$</span><span class=\"token regex-delimiter\">/</span></span><span class=\"token punctuation\">.</span><span class=\"token function\">test</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token comment\">// `prev` is the where it was imported from, we just want the directory it is in</span><br />  <span class=\"token keyword\">const</span> prevDirectory <span class=\"token operator\">=</span> <span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>prev<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>dir<span class=\"token punctuation\">;</span><br />  <span class=\"token comment\">// imports are almost always relative, so let's figure out how to get to there from here so we end up with an absolute url</span><br />  <span class=\"token keyword\">const</span> designTokenFilePath <span class=\"token operator\">=</span> <span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>prevDirectory<span class=\"token punctuation\">,</span> url<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token keyword\">const</span> theoConverted <span class=\"token operator\">=</span> theo<span class=\"token punctuation\">.</span><span class=\"token function\">convertSync</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br />    transform<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />      type<span class=\"token operator\">:</span> <span class=\"token string\">'web'</span><span class=\"token punctuation\">,</span><br />      file<span class=\"token operator\">:</span> designTokenFilePath<span class=\"token punctuation\">,</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />    format<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />      <span class=\"token comment\">// This can be any format Theo supports (or your own custom one!) &lt;https://www.npmjs.com/package/theo#formats></span><br />      <span class=\"token comment\">// I'm choosing map.scss</span><br />      type<span class=\"token operator\">:</span> <span class=\"token string\">'map.scss'</span><span class=\"token punctuation\">,</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br />    contents<span class=\"token operator\">:</span> theoConverted<span class=\"token punctuation\">,</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><br /><br />module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> theoImporter<span class=\"token punctuation\">;</span></code></pre>\n<p>And you can “load” this <code>importer</code> function like:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> theoImporter <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'../../_theo-importer'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token keyword\">const</span> sassResult <span class=\"token operator\">=</span> sass<span class=\"token punctuation\">.</span><span class=\"token function\">renderSync</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br />  file<span class=\"token operator\">:</span> rawFilepath<span class=\"token punctuation\">,</span><br />  outputStyle<span class=\"token operator\">:</span> <span class=\"token string\">'expanded'</span><span class=\"token punctuation\">,</span><br />  importer<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><br />    theoImporter<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Here</span><br />  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>With this <code>importer</code>(and JavaScript API from Sass), I can use same technique from <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/\">“How Virga processes PostCSS”</a>.</p>\n<h2 id=\"eleventy-javascript-templates-is-powerful\">Eleventy JavaScript Templates is powerful <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#eleventy-javascript-templates-is-powerful\">#</a></h2>\n<p>So to recap, what I want to do is:</p>\n<ul>\n<li><code>importer</code> function option in Sass will process Theo</li>\n<li>Sass will process <code>scss</code> to CSS</li>\n<li>CSS will be processed with Autoprefixer and cssnano</li>\n</ul>\n<p>All this can be done with Eleventy JavaScript Templates.</p>\n<p><a href=\"https://github.com/frontendweekly/11ty-theo-sass-postcss-example/blob/master/src/_sass/sass.11ty.js\"><code>sass.11ty.js</code> looks like this</a>.</p>\n<p>I’ll explain interesting parts.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> sassResult <span class=\"token operator\">=</span> sass<br />  <span class=\"token punctuation\">.</span><span class=\"token function\">renderSync</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br />    file<span class=\"token operator\">:</span> rawFilepath<span class=\"token punctuation\">,</span><br />    outputStyle<span class=\"token operator\">:</span> <span class=\"token string\">'expanded'</span><span class=\"token punctuation\">,</span><br />    importer<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>theoImporter<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br />  <span class=\"token punctuation\">.</span>css<span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>As I showed few lines above, this is Sass JavaScript API which use <code>importer</code> option.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token keyword\">class</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token function\">data</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br />      permalink<span class=\"token operator\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">_css/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fileName<span class=\"token punctuation\">.</span>css<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><br />  <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">return</span> <span class=\"token function\">postcss</span><span class=\"token punctuation\">(</span>plugins<span class=\"token punctuation\">)</span><br />      <span class=\"token punctuation\">.</span><span class=\"token function\">process</span><span class=\"token punctuation\">(</span>sassResult<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><br />        from<span class=\"token operator\">:</span> rawFilepath<span class=\"token punctuation\">,</span><br />      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br />      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> result<span class=\"token punctuation\">.</span>css<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And this is Eleventy JavaScript Templates part.<br />\nI was very happy since it looked like easy thing to do.</p>\n<h2 id=\"but-sass-command-line-doesnt-come-with-importer-option\">But, <code>sass</code> command line doesn’t come with <code>importer</code> option <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#but-sass-command-line-doesnt-come-with-importer-option\">#</a></h2>\n<p><code>node-sass</code> cli does have <code>importer</code> option but Dart Sass doesn’t.</p>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># This works</span><br />node-sass --importer ./theo-importer.js src/_sass/main.scss src/_includes/assets/styles/main.css<br /><br /><span class=\"token comment\"># But this IS NOT</span><br />sass --importer ./theo-importer.js src/_sass/main.scss src/_includes/assets/styles/main.css</code></pre>\n<p><code>importater</code> has been “Experimental” in <code>node-sass</code>. I’m not sure if Dart Sass will have this available in the future.<br />\nSo I’ve decided to reuse <code>sass.11ty.js</code> to run from command line.<br />\nYou can do <code>‌node src/_sass/sass.11ty.js</code> to invoke it.<br />\nAnd since I only run this from command line in production, I’ve added this lines of codes.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">ELEVENTY_ENV</span> <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Writing CSS to </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>prodDistpath<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">...</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  fs<span class=\"token punctuation\">.</span><span class=\"token function\">writeFileSync</span><span class=\"token punctuation\">(</span>prodDistpath<span class=\"token punctuation\">,</span> sassResult<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>Well, actually you’d need <code>fs.writeFileSync(prodDistpath, sassResult);</code> this line to make it work.<br />\n<code>postcss</code> CLI will pickup the file generated from above and do Autoprefixer and cssnano.</p>\n<h2 id=\"how-to-run-the-example\">How to run the example? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-eleventy-with-theo-sass-and-postcss/#how-to-run-the-example\">#</a></h2>\n<p>I have set up an example files on GitHub.</p>\n<p><a href=\"https://github.com/frontendweekly/11ty-theo-sass-postcss-example\">https://github.com/frontendweekly/11ty-theo-sass-postcss-example</a></p>\n<p>Fork this repo and clone it into your local machine then:</p>\n<ul>\n<li><code>npm install</code></li>\n<li><code>npm start</code> for watching file changes and run build and server. CSS file will be at <code>dist/_css/main.css</code></li>\n<li>(Quit the server) <code>npm run build:prpduction</code> will generate minified CSS file in <code>src/_includes/assets/styles/main.css</code></li>\n</ul>\n<p>I’m assuming you have <code>node</code> installed on your machine.</p>\n",
      "date_published": "2020-03-29T04:12:48Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/",
      "title": "How Virga processes PostCSS",
      "summary": "Virga use PostCSS and here's how I'm processing it",
      "content_html": "<p>“Eleventy is zero-config by default but has flexible configuration options.”, according to <a href=\"https://www.11ty.dev/docs/\">Eleventy Documentation</a>, which often means that you will most likely have to set up “configuration options” yourself.<br />\nOne of the options I always set up is tooling around CSS.</p>\n<p><a href=\"https://github.com/frontendweekly/virga\">Virga</a> is based on <a href=\"https://github.com/hankchizljaw/hylia\">Hylia</a> and one of the reason why I’ve created Virga is to use PostCSS instead of Sass which is what Hylia uses.(I have written about <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/\">“Differences between Hylia and Virga”</a>.)</p>\n<p>In this post, I’ll explain how Virga process PostCSS.</p>\n<h2 id=\"configurations\">Configurations <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/#configurations\">#</a></h2>\n<p>I have already <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/\">explained how Virga structures CSS</a>.</p>\n<p>In short, since Virga has several directories and files inside of them, <code>main.pcss</code> is there to “glue” them together.<br />\nWhich is why I use <a href=\"https://github.com/postcss/postcss-import\"><code>postcss-import</code></a> and the process starts from here.</p>\n<p>PostCSS can be configured by having <code>.postcssrc.js</code> file(well, there are several ways). And here is Virga’s one.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// .postcssrc.js</span><br />module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">ctx</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><br />  map<span class=\"token operator\">:</span> ctx<span class=\"token punctuation\">.</span>env <span class=\"token operator\">!==</span> <span class=\"token string\">'production'</span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span>inline<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br />  plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token string\">'postcss-import'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />    <span class=\"token string\">'postcss-preset-env'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />      stage<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />    autoprefixer<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />    cssnano<span class=\"token operator\">:</span> ctx<span class=\"token punctuation\">.</span>env <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Next step of process is to “convert modern CSS into something most browsers can understand, determining the polyfills you need based on your targeted browsers or runtime environments” via <a href=\"https://github.com/csstools/postcss-preset-env\"><code>PostCSS Preset Env</code></a>.<br />\nIt is like <a href=\"https://babeljs.io/\">Babel</a> for CSS.</p>\n<p>the third step is <a href=\"https://github.com/postcss/autoprefixer\"><code>autoprefixer</code></a> which parses CSS and adds vendor prefixes to rule by Can I Use. Even though needs for “vendor prefixes” getting smaller now, I would still include this plugin.</p>\n<p>The final step is <a href=\"https://github.com/cssnano/cssnano\"><code>cssnano</code></a> which is a modular minifier, built on top of the PostCSS ecosystem.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">cssnano<span class=\"token operator\">:</span> ctx<span class=\"token punctuation\">.</span>env <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Are you wondering what’s with this line?<br />\nThis is a condition to use <code>cssnano</code> or not based on environment variable. If it is <code>production</code> then use <code>cssnano</code> to minify CSS.</p>\n<p>Unfortunately having <code>.postcssrc.js</code> isn’t going to do all the process above so let’s dig deeper.</p>\n<h2 id=\"development-build\">Development Build <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/#development-build\">#</a></h2>\n<p>A “build” process is to have a file(in this case, CSS) which will be load into browsers.<br />\nVirga does this at <a href=\"https://github.com/frontendweekly/virga/blob/master/src/_postcss/postcss.11ty.js\"><code>src/_postcss/postcss.11ty.js</code></a> for development environment.</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> fs <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'fs'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> path <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> postcss <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'postcss'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> postcssrc <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'postcss-load-config'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>plugins<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> postcssrc<span class=\"token punctuation\">.</span><span class=\"token function\">sync</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token keyword\">const</span> fileName <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  postcss<span class=\"token operator\">:</span> <span class=\"token string\">'main.pcss'</span><span class=\"token punctuation\">,</span><br />  css<span class=\"token operator\">:</span> <span class=\"token string\">'main.css'</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br /><br />module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token keyword\">class</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">async</span> <span class=\"token function\">data</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">const</span> rawFilepath <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">./</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fileName<span class=\"token punctuation\">.</span>postcss<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span><br />      permalink<span class=\"token operator\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">css/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fileName<span class=\"token punctuation\">.</span>css<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span><br />      eleventyExcludeFromCollections<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span><br />      rawFilepath<span class=\"token punctuation\">,</span><br />      rawCss<span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> fs<span class=\"token punctuation\">.</span><span class=\"token function\">readFileSync</span><span class=\"token punctuation\">(</span>rawFilepath<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><br />    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><br />  <span class=\"token keyword\">async</span> <span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>rawCss<span class=\"token punctuation\">,</span> rawFilepath<span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">return</span> <span class=\"token function\">postcss</span><span class=\"token punctuation\">(</span>plugins<span class=\"token punctuation\">)</span><br />      <span class=\"token punctuation\">.</span><span class=\"token function\">process</span><span class=\"token punctuation\">(</span>rawCss<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><br />        <span class=\"token operator\">...</span>options<span class=\"token punctuation\">,</span><br />        from<span class=\"token operator\">:</span> rawFilepath<span class=\"token punctuation\">,</span><br />      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br />      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> result<span class=\"token punctuation\">.</span>css<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>I stole this from <a href=\"https://github.com/philhawksworth/eleventyone\">EleventyOne</a> by Phil Hawksworth.<br />\nThis file is processed by Eleventy. Although it doesn’t look like a “template language”, it actually is.</p>\n<p>According to <a href=\"https://www.11ty.dev/docs/languages/javascript/#classes\">Eleventy Documentation</a>, “Eleventy looks for classes that have a <code>render</code> method and uses <code>render</code> to return the content of the template.”<br />\nSince YAML Front Matter is not supported in JavaScript template types. <code>data</code> method is there to pass <code>data</code> to control how this template will render(in other words, build) a file.<br />\nSo according to this setting, the final css will be generated into <code>dist/css/main.css</code>.</p>\n<p>Finally, you would want to add <code>addWatchTarget</code> at <code>.eleventy.js</code> so that when the file or the files in this directory change Eleventy will trigger a build which would look like this:</p>\n<pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">exports</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">config</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />  config<span class=\"token punctuation\">.</span><span class=\"token function\">addWatchTarget</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./src/_postcss/'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>You can take a look at <a href=\"https://github.com/frontendweekly/virga/blob/master/.eleventy.js\">actual <code>.eleventy.js</code> file here.</a></p>\n<h2 id=\"production-build\">Production Build <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-29-how-virga-processes-postcss/#production-build\">#</a></h2>\n<p>As for production build, Virga utilizes <a href=\"https://github.com/postcss/postcss-cli\"><code>PostCSS CLI</code></a> to do the build.</p>\n<p>Why do you separate the build process between development and production?<br />\nIt is a very good question.</p>\n<p>Hylia inlines all CSS into <code>&lt;style&gt;</code> in <code>&lt;head&gt;</code> and Virga does this too.<br />\nIn development environment, Virga generates CSS into <code>dist/css/main.css</code> directly but In production, it is <code>src/_includes/assets/styles/main.css</code> so CSS file is in Eleventy Layouts.</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>style</span><span class=\"token punctuation\">></span></span><span class=\"token style\"><span class=\"token language-css\"><br />  <span class=\"token punctuation\">{</span>% include <span class=\"token string\">\"assets/styles/main.css\"</span> %<span class=\"token punctuation\">}</span><br /></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>style</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>By using <code>include</code> you can “inline” CSS like above.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token string\">\"build:postcss\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token string\">\"cross-env NODE_ENV=production postcss src/_postcss/main.pcss -o src/_includes/assets/styles/main.css\"</span></code></pre>\n<p>When you run <code>npm run build:postcss</code>, above command will be executed.<br />\n<code>-o src/_includes/assets/styles/main.css</code> does the “output” build css into <code>src/_includes/assets/styles/main.css</code>.</p>\n<p>All in all, this is why Virga separate build process.</p>\n",
      "date_published": "2020-03-28T11:30:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-28-money-blues/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-28-money-blues/",
      "title": "Money Blues",
      "summary": "Virga is now used for my personal blog and Coil for experimenting web monetized standard",
      "content_html": "<p>I have decided that I’ll use <a href=\"https://github.com/frontendweekly/virga\">Virga</a> for my personal blog, so I have added <code>paymentPointer</code> in <code>src/_data/site.json</code> which is to experiment web monetized content in your browser while supporting sites by using <a href=\"https://coil.com/\">Coil</a>.</p>\n<p>Coil is very cool since:</p>\n<ul>\n<li>its goal is to make it based on <a href=\"https://webmonetization.org/docs/explainer.html\">an actual web standard</a></li>\n<li>it is very easy to set up; create an account on Coil(it’s free) and add a <code>&lt;meta&gt;</code> tag in the <code>&lt;head&gt;</code> of your site</li>\n</ul>\n<p>Example:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span><br />  <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>monetization<span class=\"token punctuation\">\"</span></span><br />  <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>$pay.stronghold.co/1a1d5ecbf6f988e4be3abc11cfb0a0b912d<span class=\"token punctuation\">\"</span></span><br /><span class=\"token punctuation\">/></span></span></code></pre>\n<p>Honestly, I don’t intend to earn money at all.<br />\nI want to support the web standard.</p>\n<p>If you were to decide to fork Virga to start your own blog, do please replace <code>paymentPointer</code> value in <code>src/_data/site.json</code> otherwise your hard work will be contributing my earning.</p>\n<p>Chris Coyier from CSS Tricks has covered about Coil on <a href=\"https://css-tricks.com/site-monetization-with-coil-and-removing-ads-for-supporters/\">“Site Monetization with Coil (and Removing Ads for Supporters)”</a>. You should check out the article and hope you would experiment with Coil.</p>\n<p>By the way, the title of this post is form Bob Dylan’s song.</p>\n",
      "date_published": "2020-03-28T09:07:19Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/",
      "title": "How Would I Extend Virga?",
      "summary": "Virga is a starter kit for who love to extend after all.",
      "content_html": "<h2 id=\"modification-ideas-for-virga\">Modification ideas for Virga <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/#modification-ideas-for-virga\">#</a></h2>\n<p>Virga is based on <a href=\"https://hylia.website/\">Hylia</a> without Netlify CMS bit and few modifications (<a href=\"https://virga.frontendweekly.tokyo/2020-03-02-differences-between-hylia-and-virga/\">I did wrote about differences between the two</a>).</p>\n<p>Virga is pretty much ready for starting a blog, I think. I don’t own a blog, but I’m thinking about using Virga on <a href=\"https://frontendweekly.tokyo/\">this site called Frontend Weekly Tokyo</a> which was build using Hylia.</p>\n<p>At Frontend Weekly Tokyo, I’ve done some modifications on Hylia. So these are good candidates to extend Virga, too.</p>\n<ul>\n<li><strong>Monetization</strong> through service called <a href=\"https://coil.com/about\">Coil</a>. I choose this because Coil is currently only provider for <a href=\"https://webmonetization.org/\">Web Monetization spec</a>.</li>\n<li><strong>Webmentions</strong>, Webmentions is working at Frontend Weekly Tokyo. I’ve followed this <a href=\"https://mxb.dev/blog/using-webmentions-on-static-sites/\">Max Böck’s tutorial on setting up Webmentions on Eleventy</a>. Very detailed and helpful.</li>\n<li><strong>Auto Tweet using Netlify functions</strong>. Netlify provides AWS Lambda as Netlify Functions, so you achieve lots of things via “serverless”. On Frontend Weekly Tokyo, Netlify Functions does Tweet when a post went public. Again, I’ve stolen this <a href=\"https://mxb.dev/blog/syndicating-content-to-twitter-with-netlify-functions/\">Max Böck’s tutorial</a>.</li>\n</ul>\n<h2 id=\"indieweb\">IndieWeb <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/#indieweb\">#</a></h2>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>There are many reasons why you should use the IndieWeb.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"http://indieweb.org/\">Indieweb.org</a></figcaption>\n</figure>\n<p>Eleventy is very good at practicing IndieWeb since using it means you already own your content.</p>\n<p>Virga surely not covering every aspect of IndieWeb but does offer a starting points.</p>\n<h3 id=\"place-for-your-content\">Place for your content <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/#place-for-your-content\">#</a></h3>\n<p>Netlify is good place to serve your content.<br />\nVirga has been configured to deploy to Netlify.<br />\nNetlify has DNS service, so you can set up your custom domain very easily.</p>\n<h3 id=\"add-info-about-yourself\">Add info about yourself <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-07-extend-ideas-for-virga/#add-info-about-yourself\">#</a></h3>\n<p>Virga utilizes <a href=\"https://indieweb.org/rel-author\"><code>rel-author</code></a> to help provide authorship information.</p>\n<p>Virga is flexible when it comes to authorship. Any numbers of writer can can authorship via front matter data.</p>\n<pre class=\"language-text\"><code class=\"language-text\">---<br />title: How Would I Extend Virga?<br />date: 2020-03-07<br />author: Yuya Saito<br />desc: Virga is a starter kit for who love to extend after all.<br />---</code></pre>\n<p>If you omit <code>author</code> in front matter, Virga uses data from <code>src/_data/site.json</code>.</p>\n<p>You could dig really deep on IndieWeb with Eleventy and Virga in that direction.</p>\n",
      "date_published": "2020-03-07T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/",
      "title": "Yet Another Post Example",
      "summary": "Table, Video embed and other markdown enhancement",
      "content_html": "<h2 id=\"table\">Table <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#table\">#</a></h2>\n<table>\n<thead>\n<tr>\n<th>Color Name</th>\n<th>Hex</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Gray 100</td>\n<td><code>#F9F9F9</code></td>\n</tr>\n<tr>\n<td>Gray 200</td>\n<td><code>#E9E9E9</code></td>\n</tr>\n<tr>\n<td>Gray 300</td>\n<td><code>#DADADA</code></td>\n</tr>\n<tr>\n<td>Gray 400</td>\n<td><code>#BABABA</code></td>\n</tr>\n<tr>\n<td>Gray 500</td>\n<td><code>#9A9A9A</code></td>\n</tr>\n<tr>\n<td>Gray 600</td>\n<td><code>#7A7A7A</code></td>\n</tr>\n<tr>\n<td>Gray 700</td>\n<td><code>#5A5A5A</code></td>\n</tr>\n<tr>\n<td>Gray 800</td>\n<td><code>#3A3A3A</code></td>\n</tr>\n<tr>\n<td>Gray 900</td>\n<td><code>#1A1A1A</code></td>\n</tr>\n</tbody>\n</table>\n<h2 id=\"video\">Video <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#video\">#</a></h2>\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube-nocookie.com/embed/UaelNxjgGCo\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"></iframe>\n<h2 id=\"footnote\">Footnote <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#footnote\">#</a></h2>\n<p>Here is a footnote reference,<sup class=\"footnote-ref\"><a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#fn1\" id=\"fnref1\">[1]</a></sup> and another.<sup class=\"footnote-ref\"><a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#fn2\" id=\"fnref2\">[2]</a></sup></p>\n<p>Subsequent paragraphs are indented to show that they belong to the previous footnote.</p>\n<h2 id=\"figureimage-recap\">Figure/Image (Recap) <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#figureimage-recap\">#</a></h2>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/virga-site-flow.png\" alt=\"Site flow for Virga\" title=\"This is a site flow for Virga\" /></p>\n<h2 id=\"code-recap\">Code (Recap) <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#code-recap\">#</a></h2>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">h1,<br />.h1,<br />.alpha,<br />h2,<br />.h2,<br />.beta,<br />h3,<br />.h3,<br />.gamma,<br />h4,<br />.h4,<br />.delta,<br />h5,<br />.h5,<br />.epsilon,<br />h6,<br />.h6,<br />.zeta</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>and here is <code>inline code</code>.</p>\n\n<section class=\"o-footnotes\">\n<ol class=\"o-footnotes__list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Here is the footnote. <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>Here’s one with multiple blocks. <a href=\"https://virga.frontendweekly.tokyo/posts/2020-03-05-yet-another-post-example/#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2020-03-05T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/",
      "title": "Tools I used to build Virga",
      "summary": "Or I don't know how I make stuff without those great tools.",
      "content_html": "<h2 id=\"hardware-macbook\">Hardware: MacBook <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/#hardware-macbook\">#</a></h2>\n<p>First off, I’m Apple guy so tools I’ll Introduce here are heavily leaning to that direction.</p>\n<p>My current is MacBook (Retina, 12-inch, 2017).<br />\nI don’t own an external keyboard nor monitor.</p>\n<h2 id=\"editor-intellj-idea-ia-writer\">Editor: IntellJ IDEA &amp; iA Writer <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/#editor-intellj-idea-ia-writer\">#</a></h2>\n<p>I used be a Vimmer, but I’ve been using <a href=\"https://www.jetbrains.com/idea/\">IntellJ IDEA</a> for 4 or 5 years now for coding.<br />\nAnd I use iA <a href=\"https://ia.net/writer\">Writer</a> for any other writing which is where Virga’s inspiration comes from by the way.<br />\nI love iA Writer. I’ve been using it since it’s released.</p>\n<p>I’ve been looking for very lightweight editor for coding. IntellJ IDEA is too heavy for small changes.<br />\n<a href=\"https://xi-editor.io/\">Xi editor</a> looks very promising, so I’m looking forward its progress.</p>\n<h2 id=\"terminal-iterm2\">Terminal: iTerm2 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/#terminal-iterm2\">#</a></h2>\n<p>iTerm2 is my choice for a Terminal app. I’ve tried Hyper for while, but I went back to iTerm2.<br />\nMy default shell is now <a href=\"https://fishshell.com/\"><code>fish</code></a> which I’ve made the switch after I upgrade to Catalina.</p>\n<p>I have so many command line tools with me, so I’m not going to share them all here, but I’ll list ones I use in developing websites.</p>\n<dl>\n<dt><a href=\"https://direnv.net/\"><code>direnv</code></a></dt>\n<dd>Load/unload environment variables based on $PWD</dd>\n<dt><a href=\"https://stedolan.github.io/jq/\"><code>jq</code></a></dt>\n<dd>Lightweight and flexible command-line JSON processor</dd>\n<dt><a href=\"https://lynx.browser.org/\"><code>lynx</code></a></dt>\n<dd>Text-based web browser</dd>\n<dt><a href=\"https://github.com/sharkdp/bat\"><code>bat</code></a></dt>\n<dd>Clone of cat(1) with syntax highlighting and Git integration</dd>\n<dt><a href=\"https://github.com/rupa/z\"><code>z</code></a></dt>\n<dd>Tracks most-used directories to make cd smarter</dd>\n<dt><a href=\"https://cli.github.com/\"><code>gh</code></a></dt>\n<dd>GitHub CLI</dd>\n<dt><a href=\"https://github.com/Schniz/fnm\"><code>fnm</code></a></dt>\n<dd>Fast and simple Node.js version manager</dd>\n<dt><a href=\"https://github.com/htacg/tidy-html5\"><code>tidy-html5</code></a></dt>\n<dd>Granddaddy of HTML tools, with support for modern standards</dd>\n<dt><a href=\"https://github.com/BurntSushi/ripgrep\"><code>ripgrep</code></a></dt>\n<dd>Search tool like grep and The Silver Searcher</dd>\n<dt><a href=\"https://github.com/JamieMason/ImageOptim-CLI\"><code>imageoptim-cli</code></a></dt>\n<dd>Automates ImageOptim, ImageAlpha, and JPEGmini for Mac to make<br />\nbatch optimisation of images part of your automated build process</dd>\n<dt><a href=\"https://github.com/tjunnone/npm-check-updates\"><code>npm-check-updates</code></a></dt>\n<dd>Find newer versions of dependencies than what your package.json or bower.json allows</dd>\n</dl>\n<h2 id=\"other-apps\">Other apps <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/#other-apps\">#</a></h2>\n<p>I don’t do UI design but when I need to do some vector related stuff, I use <a href=\"https://www.sketch.com/\">Sketch</a>.</p>\n<p>I like color. So I have <a href=\"https://sipapp.io/\">Sip</a> and <a href=\"http://www.eigenlogik.com/spectrum/mac\">Spectrum</a>. The former is a color picker app though I love its color contrast ability for it. The latter is a color scheme design app.</p>\n<p>My default browser is <a href=\"https://www.mozilla.org/en-US/firefox/developer/\">Firefox Developer Edition</a>.<br />\nI’ve made the switch from Chrome from this year, and I only go back to Chrome when I need to do some serious performance audit.</p>\n<h2 id=\"web-tools\">Web Tools <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-04-tools-i-use-to-build-virga/#web-tools\">#</a></h2>\n<dl>\n<dt><a href=\"https://www.colorbox.io/\">ColorBox by Lyft Design</a></dt>\n<dd>Color scheme for Virga is come from this tool</dd>\n<dt><a href=\"https://whimsical.com/\">Whimsical</a></dt>\n<dd>Flowcharts、wireframes, sticky notes and mind maps tool. I use this almost everyday</dd>\n</dl>\n<p>There are other tools I use at work regularly but for building Virga, I use those 2 tools.</p>\n",
      "date_published": "2020-03-04T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/",
      "title": "TROCT CSS Architecture",
      "summary": "TROCT is not even a word but this is how I apply ITCSS.",
      "content_html": "<p>The title is just a clickbait and I won’t claim I invented this since it is just my way of applying the Inverted Triangle architecture (AKA ITCSS) which was first introduced by Harry Roberts.</p>\n<p>In simplest words, ITCSS is a methodology for organizing CSS files within layers-from generic to explicit, and from low to high specificity.<br />\nIf you want to learn more in depth, you should <a href=\"https://youtu.be/hz76JIU_xB0\">check out Harry’s talk</a>.</p>\n<p>While ITCSS has 7 layers (Settings, Tools, Generic, Elements, Objects, Components, Utilities), TROCT has 5 layers which are:</p>\n<ul>\n<li><strong>T</strong>okens</li>\n<li><strong>R</strong>oots</li>\n<li><strong>O</strong>bjects</li>\n<li><strong>C</strong>omponents</li>\n<li><strong>T</strong>ools</li>\n</ul>\n<p>Before I’m explaining responsibilities for each layer, I’ll show you how I’m applying it at this very project.</p>\n<pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token builtin class-name\">.</span><br />├── tokens<br />│  ├── _color.pcss<br />│  └── _space.pcss<br />├── roots<br />│  ├── _element.pcss<br />│  ├── _theme.pcss<br />│  └── _typography.pcss<br />├── objects<br />│  ├── _hr.pcss<br />│  ├── _wrapper.pcss<br />│  └── _skip-link.pcss<br />├── components<br />│  ├── _intro.pcss<br />│  ├── _navigation.pcss<br />│  ├── _post-list.pcss<br />│  ├── _post-meta.pcss<br />│  ├── _post.pcss<br />│  ├── _site-foot.pcss<br />│  └── _site-head.pcss<br />├── tools<br />│  ├── _prefers-reduced-motion.pcss<br />│  ├── _syntax-highlighting.pcss<br />│  └── _visually-hidden.pcss<br />├── main.pcss</code></pre>\n<p>Let’s dig in to each layer.</p>\n<h3 id=\"tokens\">Tokens <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#tokens\">#</a></h3>\n<p>Tokens layer is for Design tokens. Now Design tokens has <a href=\"https://github.com/design-tokens\">own W3C Community Group</a> and since the name comes from the Salesforce design system team, I’ll quote the original definition here.</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://www.lightningdesignsystem.com/design-tokens/\">\n<p>Design tokens are the visual design atoms of the design system — specifically, they are named entities that store visual design attributes.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Design Tokens, <a href=\"https://www.lightningdesignsystem.com/design-tokens/\">Lightning Design System</a></figcaption>\n</figure>\n<p>I might be able to put these “tokens” into Roots, but I really love the principles of Design tokens so it stays.</p>\n<h3 id=\"roots\">Roots <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#roots\">#</a></h3>\n<p>Responsibilities for Roots layer are same as Generic AND Elements in ITCSS.</p>\n<p>In ITCSS, Generic houses all the very high-level, far-reaching styles. it often contains things like normalize.css, CSS resets, and for example box-sizing rules.</p>\n<p>And Elements refer to all un-classed HTML tags. Styles in here get applied to specific HTML tags, like headings, links, and lists. This is the last layer where we use type selectors.</p>\n<p>It has both “very high-level and far-reaching styles” and project default styles AKA “all un-classed HTML tags”.<br />\nBoth belongs to “roots” of project so that’s where the name comes from.</p>\n<p><code>_element.pcss</code> has most styles for “all un-classed HTML tags” which also has “reset” or “normalize” rules.</p>\n<figure class=\"o-blockquote\">\n<blockquote cite=\"https://meyerweb.com/eric/tools/css/reset/\">\n<p>[Reset CSS] is a starting point, not a self-contained black box of no-touchiness.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— <a href=\"https://meyerweb.com/eric/tools/css/reset/\">CSS Tools: Reset CSS</a></figcaption>\n</figure>\n<p>This is from Eric Meyer who introduced “Reset CSS” into this world so I’m following his words.</p>\n<h3 id=\"objects\">Objects <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#objects\">#</a></h3>\n<p>This layer houses same responsibilities as ITCSS does which follow OOCSS (Object-Oriented CSS) principles. They are small and reusable pieces with no aesthetics which can be used in UI composition.</p>\n<h3 id=\"components\">Components <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#components\">#</a></h3>\n<p>This is same as ITCSS as well.<br />\nIt houses specific UI components.</p>\n<h3 id=\"tools\">Tools <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#tools\">#</a></h3>\n<p>This layer would be very confusing for those who are familiar with ITCSS.<br />\nIn ITCSS, “Tools” means globally used mixins and functions for preprocessors like Sass.<br />\nBut since I’m using PostCSS, I’m using the name “Tools” as “Utilities” and/or “Trumps” in ITCSS.</p>\n<p>Reason behind this is, “Utilities” is hard for me to type, and I always have to look up what “Trumps” means so in other word, it is “language barrier” for me, so I want to change it so that it would be easier for me.</p>\n<h2 id=\"troct-is-itcss\">TROCT is ITCSS <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-03-TROCT-CSS-Architecture/#troct-is-itcss\">#</a></h2>\n<p>ITCSS, at its core, is a set of principles to answer many of issues around writing scalable and predictable CSS in large projects.<br />\nSo TROCT just applies those principles accordingly.</p>\n<p>Just like how I had opened this post, title of this post is just a clickbait. It’s just showing example of ITCSS as I understand it.</p>\n",
      "date_published": "2020-03-03T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/",
      "title": "Differences between Hylia and Virga",
      "summary": "Virga is based on Hylia but there are some differences you should know",
      "content_html": "<h2 id=\"credit-where-credits-due\">Credit where credit’s due. <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/#credit-where-credits-due\">#</a></h2>\n<p>First, Hylia is a great Eleventy starter kit, and I’ve learned a lot about Eleventy from this kit so I thank Andy Bell for creating and sharing Hylia.</p>\n<h2 id=\"if-hylia-were-great-why-virga-exists\">If Hylia were great, why Virga exists? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/#if-hylia-were-great-why-virga-exists\">#</a></h2>\n<p>Easy and short answer is because this is how I learn new stuff.</p>\n<p>I’ve been reading a lot of good things about Eleventy, but I haven’t had chance to get my hand on it.</p>\n<p>I had been running this blog(sorta) called <a href=\"https://frontendweekly.tokyo/\">“Frontend Weekly”</a> for while on Medium, but I’ve wanted to go back hosting it on my own.</p>\n<p>So I’ve decided to get my hand dirty once for all to use Eleventy to host my blog.</p>\n<p>Hylia is very easy to learn, and it is also easy to extend for my own needs, yet I want to change a few things about it.</p>\n<h2 id=\"what-virga-had-done-differently-from-hylia\">What Virga had done differently from Hylia <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/#what-virga-had-done-differently-from-hylia\">#</a></h2>\n<p>While Hylia uses Sass, Virga uses PostCSS.<br />\nI’ve used Sass in production, and I do think it’s great companion for writing CSS but relying heavily on Sass make me feel like I’ve detached from reality of CSS.</p>\n<p>I realized that I haven’t used new CSS spec like Custom Properties, Custom Media Queries and/or <code>:matches</code> pseudo-class because I don’t really need to since I’ve already “using” them in Sass.</p>\n<p>So in Virga, I’ve decided to use PostCSS with <a href=\"https://preset-env.cssdb.org/\">PostCSS Preset Env</a> alone(well, plus <a href=\"https://autoprefixer.github.io/\">Autoprefixer</a>, <a href=\"https://github.com/postcss/postcss-import\">postcss-import</a> and <a href=\"https://cssnano.co/\">cssnano</a>) so I can write CSS.</p>\n<p>Other than the choice of preprocessor, Virga and Hylia is almost same.<br />\nThere are slight differences in directory structure, but those are come from personal preference.</p>\n<p>Oh, I’ve dropped few small features from Hylia, too.<br />\nThe most notable would be use of Netlify CMS.</p>\n<p>I’m not sure why you choose Virga over Hylia, to be honest, but if you do, please be aware those differences.</p>\n<p>Virga is incomplete and minimum on purpose so that I can extend it faster.</p>\n<h2 id=\"whats-with-the-name\">What’s with the name? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-03-02-differences-between-hylia-and-virga/#whats-with-the-name\">#</a></h2>\n<p>As you can probably tell, I’m not native English speaker, and I have no idea Virga is meteorological term(well, I’ve never heard the term in Japanese, which is my native language, either).</p>\n<p>Virga comes from a name of backpack by Granite Gear which I own and love. I actually have color scheme set up taken from the bag.<br />\nWhile I’ve ended up not using the scheme, the name stuck.</p>\n",
      "date_published": "2020-03-01T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    },
    {
      "id": "https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/",
      "url": "https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/",
      "title": "Let's take a look at how a post would be like",
      "summary": "Be aware, lorem ipsum is everywhere.",
      "content_html": "<h1 id=\"this-is-an-heading-1-lorem-ipsum-dolor\">This is an heading 1 lorem ipsum dolor <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#this-is-an-heading-1-lorem-ipsum-dolor\">#</a></h1>\n<p>This is body copy lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n<p>This is body copy duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<h2 id=\"this-is-an-heading-2\">This is an heading 2 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#this-is-an-heading-2\">#</a></h2>\n<p>This is body copy duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<h3 id=\"heading-3\">heading 3 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#heading-3\">#</a></h3>\n<p>This is body copy duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<h4 id=\"this-is-heading-4\">This is heading 4 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#this-is-heading-4\">#</a></h4>\n<p>This is body copy duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<h5 id=\"this-is-heading-5\">This is heading 5 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#this-is-heading-5\">#</a></h5>\n<p>This is body copy duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<h1 id=\"this-is-heading-1\">This is heading 1 <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#this-is-heading-1\">#</a></h1>\n<h2 id=\"and-heading-2-as-subheading\">And heading 2 as subheading <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#and-heading-2-as-subheading\">#</a></h2>\n<p>Code block would looks like this:</p>\n<pre class=\"language-css\"><code class=\"language-css\"><span class=\"token selector\">h1,<br />.h1,<br />.alpha,<br />h2,<br />.h2,<br />.beta,<br />h3,<br />.h3,<br />.gamma,<br />h4,<br />.h4,<br />.delta,<br />h5,<br />.h5,<br />.epsilon,<br />h6,<br />.h6,<br />.zeta</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><br /><span class=\"token selector\">h1,<br />.h1,<br />.alpha</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token selector\">h2,<br />.h2,<br />.beta</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token selector\">h3,<br />.h3,<br />.gamma</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token selector\">h4,<br />.h4,<br />.delta</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token selector\">h5,<br />.h5,<br />.epsilon</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span><br /><span class=\"token selector\">h6,<br />.h6,<br />.zeta</span> <span class=\"token punctuation\">{</span><br /><span class=\"token punctuation\">}</span></code></pre>\n<p>and here is <code>inline code</code>.</p>\n<h3 id=\"heading-3-introducing-block-quote\">heading 3 introducing block quote <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#heading-3-introducing-block-quote\">#</a></h3>\n<figure class=\"o-blockquote\">\n<blockquote>\n<p>You can’t connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future.</p>\n</blockquote>\n<figcaption class=\"o-blockquote__attribution\">— Jobs, Steve. “Stanford Commencement Address.” 12 June 2005. Speech.</figcaption>\n</figure>\n<h2 id=\"how-about-images\">How about images? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#how-about-images\">#</a></h2>\n<h3 id=\"with-heading-3-as-subheading\">With heading 3 as subheading <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#with-heading-3-as-subheading\">#</a></h3>\n<p><img src=\"https://virga.frontendweekly.tokyo/images/virga-site-flow.png\" alt=\"Site flow for Virga\" title=\"This is a site flow for Virga\" /></p>\n<h2 id=\"how-about-footnotes\">How about footnotes? <a class=\"o-heading-link\" href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#how-about-footnotes\">#</a></h2>\n<p>Here is a footnote reference,<sup class=\"footnote-ref\"><a href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#fn1\" id=\"fnref1\">[1]</a></sup> and another.<sup class=\"footnote-ref\"><a href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#fn2\" id=\"fnref2\">[2]</a></sup></p>\n\n<section class=\"o-footnotes\">\n<ol class=\"o-footnotes__list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Here is the footnote. <a href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p>Here’s one with multiple blocks. <a href=\"https://virga.frontendweekly.tokyo/posts/2020-02-28-lorem-ipsum/#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2020-02-28T00:00:00Z",
      "authors": [
        {
          "name": "Yuya Saito"
        }
      ]
    }
  ]
}