23
Build a static site in Ruby with Bridgetown
Table of Contents
Once upon a time, in ye olden days of 2008, the world saw the release of Jekyll, the first popular static site generator. Fast forward 2+ decades, and its popularity has been eclipsed by newer JavaScript counterparts like Gatsby and Eleventy. And why not? Jekyll runs on Ruby (boo!) so it is unsexy and obviously super slow. (Hint: in that article, read down to where the author notes, "Also surprising is that Jekyll performed faster than Eleventy for every run.")
Sarcasm aside, Jekyll seems to be built on a solid enough foundation, but unfortunately it has not received a lot of updates in recent years. Is this another arena where, as they say, Ruby is dead?
Enter Bridgetown, a fork of Jekyll which aims to compete toe-to-toe with its modern JS cousins, providing even more Ruby tools for building static sites. Very exciting.
Many of Bridgetown's Ruby upgrades are already released, so I (happy for any chance to write Ruby) rebuilt and extended my blog with Bridgetown. Here's how I did it. Note that these instructions apply to Bridgetown 0.21, the latest version at the time of writing. Also note that a knowledge of Ruby is assumed here, but not necessarily any prior experience in building a static site.
You can see the final result of this process in my site's GitHub repo. The site itself is at fpsvogel.com.
- Follow the steps on Bridgetown's Getting Started page.
- If you want to use a CSS framework: Bulmatown or Bootstrap blog theme. But instead I used a classless CSS framework (see below in "Design").
- If you see strange or missing styling when serving up your site locally, just wait a bit when running
yarn start
until the Webpack manifest is generated (you'll be notified in the console when it is generated), then exit and runbridgetown serve
. Note thatbridgetown serve
does not generate a Webpack manifest, so useyarn start
oryarn webpack-dev
whenever you see CSS issues and need to regenerate it.
- Install plugins:
- SEO tags
- Sitemap generator
- Atom feed
- SVG inliner
- Turbo for quick page transitions without a full reload.
- Stimulus if you need JavaScript sprinkles. (Alternatively you could use LitElement, as explained in the Components doc).
- Switch to the resource content engine.
- Doc: Resources
- In
bridgetown.config.yml
, addcontent_engine: resource
. - In the Liquid templates, change
page
toresource
, and access front matter via thedata
variable. For example: instead ofpage.title
, useresource.data.title
.
- Switch from Liquid to ERB templating.
- Doc: ERB and Beyond
- In
bridgetown.config.yml
, addtemplate_engine: erb
. - Convert the Liquid templates in
src/_layouts
andsrc/_components
to ERB. Then move the templates from_components
into a newsrc/_partials
directory, and add an underscore to the beginning of each filename, e.g.head.liquid
becomes_head.erb
. - Convert the Liquid code in
posts.md
to ERB.
- Set your preferred permalink style.
- Set up pagination.
- Create a
_posts-drafts/
directory for drafts that will not be published with your other posts. (The documented way of doing this works only for the legacy content engine, but the docs will be updated by the time the resource content engine becomes the default.) - Set your site's info in
src/_data/site_metadata.yml
. - Add a Pygments CSS theme for code syntax highlighting.
- Either download one of the handily premade CSS files, or pick from the full list then install Pygments and make it generate a CSS file. (I picked one of the premade stylesheets and then created a second one to override some of the colors.)
- Place the CSS file in
frontend/styles/
. - Import it into
frontend/styles/index.scss
: for example, for Monokai place@import "monokai.css";
near the top ofindex.scss
.
As a foundation I used holiday.css, a classless stylesheet for semantic HTML, and then I extended it with custom elements.
However, I still used CSS classes wherever a custom element would need to inherit from an element other than span
or div
, because this inheritance can only be set up via JavaScript, and that seems like more trouble than it's worth at this point.
Occasionally I took a part of a page and abstracted it out into a partial, such as _page_selector.erb
and _tweet_button.erb
.
Partials work great for simply sectioning off parts of the page, but for any significant manipulation of data prior to rendering, building a Ruby component makes more sense. In my case, I wanted a "Reading" page that lists titles from my reading.csv
file (my homegrown alternative to Goodreads), including only books that I rated at least a 4 out of 5.
Following the doc on Ruby components, I created a ReadingList
component in _components/reading_list.rb
, and its template _components/reading_list.erb
.
After writing the HTML + ERB + CSS for the reading list element, I used Stimulus to add JavaScript sprinkles to expand/collapse rows with reading notes or long blurbs, to filter rows by rating or genre, and to sort rows (though sorting is disabled on my site, since I went with the minimal "favorite or not" way of showing ratings).
Then I filled out reading_list.rb
to load my reading list and provide data for reading_list.erb
. This was just a matter of extracting CSV-parsing code from a previous app into a gem, then including it in my component and tying up the loose ends.
Thanks to a tip (one of many) from the Bridgetown creators on the Discord server, I realized my Ruby component had way too much logic in it which should be separated out into a plugin. So I dove into the docs on plugins and moved nearly all of my component's code into a plugin.
So now the plugin parses my CSV file and saves it into the site's data, then my component's .rb
file pulls that data into instance variables, then the ERB template uses the instance variables as it displays the reading list.
If you create a plugin and want to make it more easily available to other Bridgetown site creators, you should make it into a gem and possibly create an automation for it. I didn't for my reading list plugin, because the intersection of people who track their reading in a CSV file and people who will make a Bridgetown site is… very few people, I'm sure.
Publishing my site was as simple as choosing the GitHub repo on Netlify and configuring the custom domain.
One possible improvement remains. Currently, to update the reading list I must delete it (_data/reading.yml
) and rebuild the site locally (so that my reading.csv
can be re-parsed) before pushing it to be built and deployed on Netlify. I could avoid these manual steps by taking advantage of the fact that my reading.csv
is automatically synced to Dropbox: I could change my plugin to connect to Dropbox and update the list from there instead of from the copy on my local machine.
Besides Bridgetown itself, I learned a number of new things in this project:
- Semantic HTML.
- More CSS.
- Stimulus, and more JavaScript than I'd written before.
But what I really loved was using what I already knew (Ruby) in a completely new way. Bridgetown is doing a wonderful job of bringing the joy of Ruby into the world of modern static site generators.
23