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??)
Now onto todayâs little batch of snippets.
Swapping Video Links with Embeds #
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! âșïž