This is part 4 of a multipart series where we will look at getting a website / blog set up with hakyll and customized a fair bit.
- Pt. 1 – Setup & Initial Customization
- Pt. 2 – Generating a Sitemap XML File
- Pt. 3 – Generating RSS and Atom XML Feeds
- Pt. 4 – Copying Static Files For Your Build
- Pt. 5 – Generating Custom Post Filenames From a Title Slug
- Pt. 6 – Pure Builds With Nix
- (wip) Pt. 7 – Customizing Markdown Compiler Options
You will inevitably need to copy static files over to your build folder at some point in a hakyll project, and this short tutorial will show you a simple way to do so.
- Copying Files the Long Way
- Simplify File Copying With a List
- Simplify File Copying With Pattern Composition Operators
- GitHub Pages Tip for Dotfiles and Dotfolders
Copying Files the Long Way
As of the time of this writing, the default hakyll example for copying files looks like this:
"images/*" $ do match route idRoute compile copyFileCompiler
This is great and gets the job done! When I first looked at copying more files, I went down this path:
"CNAME" $ do match route idRoute compile copyFileCompiler "robots.txt" $ do match route idRoute compile copyFileCompiler "images/*" $ do match route idRoute compile copyFileCompiler "fonts/*" $ do match route idRoute compile copyFileCompiler -- ...and so on
Obviously, there is some code duplication here; there must be a better way!
Simplify File Copying With a List
Here are all the items I need copied over:
CNAME robots.txt _config.yml images/* fonts/* .well-known/*
As it turns out, this list of file identifiers to copy can be used in
to take some foldable structure (for us, a list), map each element to a monadic
action that uses hakyll’s
match function, ignore the results and ultimately
simplify our code.
The type signature for
forM_ is as follows:
forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
And here is the implementation:
"CNAME" forM_ [ "robots.txt" , "_config.yml" , "images/*" , "fonts/*" , ".well-known/*" , $ \f -> match f $ do ] route idRoute compile copyFileCompiler
Nice! While this technique is not mentioned in the documentation, it is present
in the hakyll website’s
so we know we’re in good company if jaspervdj is
already using it.
If you want to read more about the possible patterns that can be matched, check out the commentary in the source here: https://github.com/jaspervdj/hakyll/blob/1abdeee743d65d96c6f469213ca6e7ea823340a7/lib/Hakyll/Core/Identifier/Pattern.hs.
Simplify File Copying With Pattern Composition Operators
In this /r/haskell reddit thread
by GAumala, they point out that hakyll’s
pattern composition operators
can also be used to accomplish the same goal. Here is how we would could convert
forM_ above to instead use
"CNAME" match (.||. "favicon.ico" .||. "robots.txt" .||. "_config.yml" .||. "images/*" .||. "fonts/*" .||. ".well-known/*") $ do route idRoute compile copyFileCompiler
While I understand the
forM_ better, this does seem to be more attractive!
GitHub Pages Tip for Dotfiles and Dotfolders
If you’re using GitHub pages and have any dotfiles or dotfolders to copy over, make sure you pay attention here.
Let’s say you have signed up for Brave Payments and need to verify your site by placing a file at
Unfortunately, GitHub Pages, which uses jekyll under the hood, will ignore your dotfiles and dotfolders by default and will therefore not deploy them.
We can fix this by adding a
_config.yml file to our project (you can see it
included in the list in the previous section) and telling it to include what it
# _config.yml include: [".well-known"]
Once you’ve done this, you can commit this file, push it up to GitHub and view it on your published site.
You can read more about jekyll’s configuration options here: https://jekyllrb.com/docs/configuration/options/.
Today we learned a simple way to list what files we want to be copied over in
our hakyll projects, got exposed to
forM_ and uncovered a potential issue
with dotfiles and dotfolders not getting published on GitHub Pages.
Next up: * Pt. 5 – Generating Custom Post Filenames From a Title Slug * (wip) Pt. 6 – Customizing Markdown Compiler Options
Thank you for reading!