brainbaking/content/post/2021/01/hugo-rss-feeds-and-lazy-ima...

4.3 KiB

title subtitle date tags categories
RSS Feeds, Hugo, and Lazy Image Loading Where's my content? It's a tarp! 2021-01-05
hugo
rss
webdesign

Full RSS Content in Hugo

Just a quick one I wanted to get out there in case you are, like me, using Hugo to power a blog. Apparently, in 2017, the default behavior changed from using the .Content to the .Summary variable in the default rss.xml.

What's the big deal? I had no idea, until I started using a proper RSS reader today - the open source NetNewsWire for Mac. This is what your RSS feed will look like:

The above screenshot might mislead you into thinking I simply captured only a part - I did not. That's the .Summary, right there. Since reading all "the news" in one place sounds intriguing, and I'd like other visitors to enjoy my full blog posts in these tools too, I'd have to change the default behavior. That can be easily done by copy-pasting the default into layouts/_default/rss.xml and altering it to your liking - such as swapping .Summary for .Content.

However, that brings us to to problem number two.

Lazy loading and RSS Feeds

Recently, after trying to maximize my Lighthouse score, especially on performance levels, I implemented lazysizes, a simple solution to lazy load <img/> tags, thereby reducing the critical path for a single page to load. That requires a custom render-image.html (only available when using the Goldmark Markdown renderer) in _default/_markup/ that looks like this:

<figure>
    <a href="{{ .Destination | safeURL }}" class="lbox">
        <noscript>
            <img src="{{ .Destination | safeURL }}" {{ with .Text }} alt="{{ . }}"{{ end }} {{ with .Title}} title="{{ . }}"{{ end }}>
        </noscript>     
        <img class="lazyload" data-src="{{ .Destination | safeURL }}" {{ with .Text }} alt="{{ . }}"{{ end }} {{ with .Title}} title="{{ . }}"{{ end }}>
    </a>
    {{ with .Title }}
        <figcaption>{{ . }}</figcaption>
    {{ end }}
</figure>

Do not forget the <noscript/> tag in case JavaScript is disabled or the visitor will not see any images1 Same goes for the RSS feed: your index.xml that NetNewsWire loads will see an image tag, but not a src attribute. To fix that, I replaced the content, like so:

{{ $lazyLoadImg := "<img class=\"lazyload\" data-src=" }}
{{ $eagerLoadImg := "<img src=" }}
{{ $content := .Content | replaceRE $lazyLoadImg $eagerLoadImg | safeHTML }}      
<description>
  {{ $content }}
  ]]>
</description>

I still wasn't satisfied. Some blog posts use a "big image" (or "featured image" masthead), that is part of the article header, and is currently not shown in the RSS reader. After inspecting the RSS specifications, it seems that a <img/> tag in the description should do it, provided a CDATA wrapper is present. So, the above description tag was extended, and now looks like this:

<description>
  {{ `<![CDATA[ ` | safeHTML }}
  {{ if .Params.bigimg }}
    <p>
      <img hspace="5" src="{{ $baseurl }}bigimg/{{ .Params.bigimg }}"/>
    </p>
  {{ end }}

  {{ $content | safeHTML }}
  ]]>
</description>

Let's inspect the changes with our RSS reader:

Scrolling down also reveals properly loaded images, hooray! Do not forget to add feed metadata to the <header/> tag so that NetNewsWire can automatically detect the location of your RSS feed:

<link href="{{ .RelPermalink }}" rel="alternate" type="application/rss+xml" title="Brain Baking" />
<link href="{{ .RelPermalink }}" rel="feed" type="application/rss+xml" title="Brain Baking" />

Enjoy my RSS feed at /index.xml.


  1. Try it your for yourself by disabling JS in your browser. Your blog should be accessible to anyone - no CSS, no JS, accessibility options - try to include everyone. ↩︎