If you want to inline Sass/CSS in Jekyll you usually have two options: either inline it yourself or use a gem like jekyll-assets. This blog has two Sass files which aren’t that big, so I prefer inlining them myself to keep the dependencies slim. There is a filter called scssify, but if you have more than a trivial number of posts, your build times will spike like crazy.

Googling online for how to inline CSS in a Jekyll blog will return many blog posts and stackoverflow answers. All of these will recommend using the scssify filter, something like this:

<!-- DON'T DO THIS! -->
<style type="text/css">
  {% capture sass_file %}
      {% include main.scss %}
  {% endcapture %}
  {{ sass_file | scssify }}
</style>

While this works, it has a few issues:

  1. It runs scssify every time the liquid template is processed, even though the input Sass does not change. If you have more than a few blog posts, this delay will become noticeable.
  2. The main.scss must be placed under _includes, which is an awkward place for CSS.
  3. Requires a capture helper to actually read in the source Sass, before passing it to scssify.

In my case, the slowdown was bad enough that the repeated sass compilation took up more than 50% of the rbspy flamegraph output.

rbspy flamegraph showing redundant Sass executions

The build time was hovering at ~21 seconds for ~160 blog posts, on my i7 6500U Skylake. Note that this is calling into libsass which is implemented in C, so Ruby’s GIL is nowhere in the compilation process.

After some looking around, I decided to implement a small plugin that compiles the Sass only once per build. It then dumps the output into the site.data variable, so that you can include it in the liquid templates directly.

Jekyll plugins are fairly easy to write. You can just drop them in _plugins/<foo>.rb and Jekyll should pick it up on the next rebuild.

# file: _plugins/inline_sass.rb
class InlineSassGenerator < Jekyll::Generator
  SASS_FILE = './css/main.scss'

  def generate(site)
    site.find_converter_instance(Jekyll::Converters::Scss)
        .convert(File.read(SASS_FILE))
        .tap { |styles| site.data['styles'] = styles }
  end
end

We implement a Jekyll::Generator that handles the Sass compilation bit, making use of the already instantiated Converter within Jekyll. This also ensures that any sass configuration in your _config.yml is picked up automatically.

The next bit is to simply inline this in your <style> tags.

<head>
    ...
    <style type="text/css">
        {{ site.data.styles }}
    </style>
    ...
</head>

As you can see, it feels a lot more natural to use. You can now move your main.scss out of the _includes directory, to a more appropriate place like _sass or css.

The above plugin can be customized to support multiple Sass files, caching and other features as needed. Though at that point, I would recommend just going with jekyll-assets.

In terms of performance, my build is now down to 6 seconds, so that’s an improvement of ~70%. It’s kinda hilarious how stupidly inefficient some of the advice out there is. 😛