How I organise my project-specific plugin code in Bridgetown

posted by Ayush Newatia
8 December, 2020



As I covered in my last post, Bridgetown is a new static site generator that’s been forked from Jekyll. It includes Webpack as a first class citizen so it’s all set up to allow developers to build modern front ends without any extra configuration.

For most simple websites, you’re unlikely to need any custom Ruby code as Bridgetown packs in quite a bit of functionality out of the box; but for anything non-trivial; it’s very likely you’ll have to extend Bridgetown with plugins.

In my last project, I wanted to showcase some of my photography along with the technical data for each shot (shutter speed, aperture etc.). I also wanted Bridgetown to generate the appropriate pages for the photo albums and the photos based on the file system structure.

This required model classes for each Album and Photo that extract and contain the EXIF data in each photo; Bridgetown::Page subclasses for AlbumPage and PhotoPage; some generic helper code and finally the code that actually generates the HTML pages.

Without some kind of structure, this code would quite easily descend into chaos; so I’d like to share how I organised my code in this project and how Bridgetown’s autoloading makes it a cinch.

My plugins folder structure

This is what my plugins folder looks like:

├── builders
│ ├── photo_albums_builder.rb
│ └── photo_albums_generator.rb
├── helpers
│ └── hashify.rb
├── models
│ ├── album.rb
│ └── photo.rb
├── pages
│ ├── album_page.rb
│ └── photo_page.rb
└── site_builder.rb

site_builder.rb and builders/ is what an empty Bridgetown project creates for you. All files in the plugins directory and subdirectories except for helpers gets autoloaded at build time.

Since site_builder.rb is the only file in the root, it is the first one loaded so I put all my requires at the top of that to avoid creating another file.

I also added a line to autoload all files in the helpers directory so this is what my site_builder.rb looks like:

Dir.glob("#{ __dir__ }/helpers/*.rb").each { |file| require file }

require 'exifr/jpeg'
require 'yaml'
require 'active_support/core_ext/integer/inflections'

class SiteBuilder < Bridgetown::Builder
  # write builders which subclass SiteBuilder in plugins/builder
end

With this structure, I can add files anywhere in my plugins directory and all my required gems and helper code will be available.

Conclusion

Obviously this structure is just as per my personal preference and it worked great in the one project I’ve tried it in.

Bridgetown’s autoloading is awesome because it means that files don’t need to be individually required and any gems can be required just once in site_builder.rb.

You could also create separate directories for custom Liquid tags and filters so they don’t get mixed in with code responsible for building your site.