Extra Dependencies in Hakyll

I use scss for my site's stylesheets. scss is a language very similar to CSS that adds support for variables, nesting, mixins, selector inheritance, and more---while retaining a syntax very similar to CSS itself.

# Split Stylesheets

A common practice I've noticed with the use of scss is to avoid having one monolithic stylesheet and instead opt to split it out into separate semantic files. For example, post.scss would concern styling for posts, syntax.scss would concern styling for Pygments syntax highlighting, etc. These files are then imported into one stylesheet, e.g., screen.scss, using the @import directive. It is this stylesheet that gets compiled by the scss compiler into the monolithic CSS.

# Problem

In Hakyll, rules are generally designated by a pattern that matches a resource coupled with a route and a compiler. So this was the rule I originally had for scss/screen.scss:

match "scss/screen.scss" $ do
  route $ constRoute "css/screen.css"
  compile $ sassCompiler

The rule simply states that Hakyll should:

  1. find the file scss/screen.scss
  2. route it to css/screen.css
  3. compile it using my custom sassCompiler.

This worked fine, but it meant that when I built or previewed the site, if I modified one of the split stylesheets, such as post.scss, it wouldn't regenerate the monolithic stylesheet. It would only do so if scss/screen.scss itself was modified.

# Solution

With the help of Hakyll's creator, Jasper, I learned that the solution involves the use of makePatternDependency to create a Dependency from a given Pattern, and rulesExtraDependencies to associate the dependencies with a specific Compiler.

Advanced usage: add extra dependencies to compilers. Basically this is needed when you're doing unsafe tricky stuff in the rules monad, but you still want correct builds.

A useful utility for this purpose is makePatternDependency.

Jasper on Hackage

Now when I'm previewing my site---or build the site in general---and I modify any scss file, it correctly regenerates the monolithic css/screen.css file. Here's my new scss compiler rule:

match "scss/**.scss" $ do
  compile getResourceBody

scssDependencies <- makePatternDependency "scss/**.scss"
rulesExtraDependencies [scssDependencies] $ do
  create ["css/screen.css"] $ do
    route $ idRoute
    compile $ sassCompiler
June 28, 2013