Publishing a Website from Emacs and Hugo
After 5 years, it’s time to give the site a bit of a refresh, now with fewer images and more words. Previously I used bootstrap plus a bit of manual editing. This time I’ll be using a pipeline of Emacs org-mode -> ox-hugo -> hugo -> nearlyfreespeech.net. This post will self-document my steps to get all that up and running. The last time I did any web-related things was over 5 years ago, and I wasn’t an expert then, so these steps should be taken with a grain of salt.
sudo snap install hugo mkdir petercheng && cd petercheng hugo new site petercheng
(use-package ox-hugo :ensure t :after ox)
Set up a theme (I’m using the hyde-hyde theme)
git submodule add https://github.com/htr3n/hyde-hyde.git themes/hyde-hyde
For my intended setup, there are only 2 files I’ll be working with. The first one is
config.toml, which stores global hugo settings, as well as parameters for my chosen theme. I’m not really sure how to find all the toggle-able parameters for a given theme besides digging through the theme code or looking at example sites.
As an early example of why I’m using org mode, I can directly insert a live copy of my
config.toml file below, simply by including the line:
#+INCLUDE: "config.toml" src ini
baseURL = "https://petercheng.net/" languageCode = "en-us" title = "Peter Cheng" theme = "hyde-hyde" [params] author = "Peter Cheng" authorimage = "https://raw.githubusercontent.com/petercheng00/personal/master/website/v2/petercheng/external_files/me.jpg" description = " " highlightjs = true highlightjsstyle = "zenburn" highlightjslanguages = ["lisp"] [params.social] github = "petercheng00" linkedin = "petercheng00" [[menu.main]] name = "Posts" weight = 100 identifier = "posts" url = "/posts/" [[menu.main]] name = "About" identifier = "about" weight = 200 url = "/about/"
One early roadblock I hit was that hyde-hyde uses highlight.js for syntax highlighting, which does not contain
emacs-lisp as a language option, unlike org-mode and chroma (hugo’s default syntax highlighter). I’m currently using
lisp as a compromise, and it took me a while to realize that highlightjslanguages needed to be set to include non-default languages in highlight.js. If an unsupported (or empty!) language is passed to highlight.js, at least with hyde-hyde, it results in poorly formatted output, which led to much confusion for a while.
The other file I need to create is the org file that generates all this content, on every page, following ox-hugo’s single-page architecture. In normal Hugo, individual pages written in markdown (or now in org-mode) are placed inside the
content directory inside the project root. With ox-hugo, a single org-mode file can be used to generate all pages, posts, and any other content. This has some advantages in allowing usage of org-mode functionality, as well as re-use of content or property settings across pages.
There’s a number of hugo properties that can be set within the file, but the only required one is
HUGO_BASE_DIR, which specifies the root directory of the hugo website, relative to the org file.
Afterwards, I have 2 top-level sections in my org file,
Posts. Any properties set under a section will be applied to subsections, so I have the following properties set for each, to place pages at the top level of my exported files, and posts within a subdirectory.
* Pages :PROPERTIES: :EXPORT_HUGO_SECTION: ./ :END: * Posts :PROPERTIES: :EXPORT_HUGO_SECTION: posts :END:
I can then create pages or posts by creating subsections within the relevant section. The
EXPORT_FILE_NAME property is required to be set for each, which determines the exported filename. Here’s an example of the properties setting for this current post.
** Publishing a Website from Emacs and Hugo :PROPERTIES: :EXPORT_FILE_NAME: website-v2-setup :EXPORT_DATE: 2018-06-04 :END:
Ox-hugo adds a new export option to the org-mode export menu.
(C-c C-e) by default. There’s a few options for exporting, but currently I find it simplest just to always export all content, with
(C-c C-e H A). One setting I’ve seen used a lot is
#+HUGO_AUTO_SET_LASTMOD: t, and that doesn’t play nicely if always updating all files. But I don’t feel a need to track and update dates on every edit.
After exporting, markdown files should be created in the content directory, and hugo will auto-reload pages if already running (to start hugo, run
hugo server from the base directory).
There are some fancy options for deploying, such as this guide, which demonstrates hugo publishing on a remote server, triggered by git post-receive. For the time being I’m going to keep thing simple, and simply use a script to generate a static site, which I’ll keep synced up via rsync. A final example of showing a live code view of my publishing script:
#!/usr/bin/env bash set -eux username=$1 server=ssh.phx.nearlyfreespeech.net rm -rf public hugo # rsync is problematic on WSL (https://github.com/microsoft/WSL/issues/2138) # --whole-file is one workaround # Not being able to use -z is another limitation rsync -avh --whole-file --progress --delete public/ "$username@$server:"