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:
- find the file scss/screen.scss
- route it to css/screen.css
- 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