Little Content Tricks for Your Bridgetown Website

Well my Ruby friends, a new day has dawned with the release of the Ruby web framework Bridgetown 2, and that means I can start to enjoy the fruits of our labor by sharing useful code examples and architectural explanations here on Fullstack Ruby. Yay! 🎉

(BTW
how cool is this custom artwork by Adrian Valenzuela??)

Greetings from River City

Now onto today’s little batch of snippets.

On a Bridgetown client project, we wanted to be able to drop in links to the client’s many videos hosted on Vimeo. I didn’t want to have to deal with the hassle of grabbing <iframe> tags for every single video, so my first inclination was to write a helper method and use those calls in the markup where needed. But then I realized I could go a step further: just paste in the damn link and get an embed on the other side! 😂

It needs to go from this Markdown source:

Ever wonder what it's like to dance under the sea? Here's your chance to experience lights that simulate moving water. These are customizable with different color variations and ripple speeds.

https://vimeo.com/390917842

to this HTML output:

<p>Ever wonder what it’s like to dance under the sea? Here’s your chance to experience lights that simulate moving water. These are customizable with different color variations and ripple speeds.</p>

<p><iframe src="https://player.vimeo.com/video/390917842" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen loading="lazy"></iframe></p>

And using a bit of string substitution in a builder hook, the solution is straightforward indeed:

# plugins/builders/vimeo_embeds.rb
class Builders::VimeoEmbeds < SiteBuilder
  def build
    hook :resources, :post_render do |resource|
      resource.output.gsub! %r!<p>https://vimeo.com/([0-9]+)</p>!, %(<p><iframe src="https://player.vimeo.com/video/\\1" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen loading="lazy"></iframe></p>)
    end
  end
end

In your case you might be using YouTube, or PeerTube, or some other form of video hosting, but the concept would be just the same. You could even layer up several gsub calls to handle them all.

Lazy Images #

For better frontend performance, due to the large number of images we display on some of the content pages, I wanted to ensure that images added in the Markdown would output with a loading="lazy" attribute. This tells browsers to hold off on loading the image until the reader scrolls down to that place in the document.

After making sure I had gem "nokolexbor" installed, and had added html_inspector_parser "nokolexbor" to my Bridgetown configuration in config/initializers.rb, I proceeded to write an HTML inspector plugin to do the job:

# plugins/builders/lazy_images.rb
class Builders::LazyImages < SiteBuilder
  def build
    inspect_html do |doc|
      main = doc.query_selector('main')
      next unless main

      main.query_selector_all("img").each do |img|
        next if img[:loading]

        img[:loading] = :lazy
      end
    end
  end
end

This loops through all img tags within the main layout element, and if it doesn’t already have a loading attribute, it will get set.

Extracting an Image for Graph #

On another project, I wanted to have some smarts where the image used for open graph previews could be pulled directly out of the content, rather than me having to set an image front matter variable by hand. I decided to solve this with a bit of regex wizardry:

# plugins/builders/image_extractions.rb
class Builders::ImageExtractions < SiteBuilder
  def build
    hook :posts, :pre_render do |resource|
      next if resource.data.image && !resource.data.image.end_with?("an-image-i-wanted-to-skip-here.png")

      md_img = resource.content.match %r!\!\[.*?\]\((.*?)\)!
      img_url, _ = md_img&.captures

      unless img_url
        html_img = resource.content.match %r!<img src="(.*?)"!
        img_url, _ = html_img&.captures
      end

      if img_url && !img_url.end_with?(".gif")
        img_url = img_url.start_with?("http") ? img_url : "#{site.config.url}#{img_url}"

        # Set the image front matter to the found URL
        resource.data.image = img_url
      end
    end
  end
end

You could simplify this if you’re only dealing with Markdown content
in my case I have a lot of old HTML-based content predating the age of modern Markdown files, so I need to support both input formats.

And that’s it for today’s round of Bridgetown tips! To stay in touch for the next installment, make sure that you follow us on Mastodon and subscribe to the newsletter. What would you like to learn about next for building websites with Bridgetown? Let us know! â˜ș small red gem symbolizing the Ruby language

Skip to content