How to Publish Hugo Website from Emacs
Introduction
This is a short guide on how to setup a Hugo website where pages / posts can easily be captured and published from within Emacs. I will assume you have an Emacs distribution and github account setup.
What I Use (at the time of writing):
- Doom Emacs (installation method may vary for different distributions)
- Website hosted with Github Pages
- Hugo
- ox-hugo (Emacs package)
- Hextra Hugo Theme
Installation
Hugo
Install using preferred method, I used the following commands:
sudo apt update
sudo apt install hugo
Check if Hugo is correctly installed by using:
hugo version
ox-hugo
Install the ox-hugo Emacs package - I installed it using Melpa but feel free to use your preferred installation method.
Setup
Hugo Website
First create a basic hugo site:
hugo new site site-name
Github Pages
cd into the newly created folder and init your git repository:
cd site-name
git init
Now create a repository on github named “username.github.io” e.g. in my case it is “mushyp3a.github.io”. Add that remote repo as the origin for your newly created local one:
git remote add origin <remote-repo-URL>
Now upload all the newly created hugo site files to your remote repository.
If you would like the ability to commit all changes and push them from a single command within Emacs you can add the following code to your config.el file:
(defun my-git-push-site ()
(interactive)
(let ((default-directory "~/path/to/hugo/site")) ;; Change this to your repo path
(shell-command "git add . && git commit -m 'Auto-update' && git push")))
Hugo Themes
I won’t cover the setup of hugo themes as each have different configuration options. However, you can install them by adding a git submodule:
git submodule add https://link-to-theme.git themes/theme-name
And then enable it in hugo.toml:
echo 'theme = "theme-name"' >> config.toml
ox-hugo Configuration
The basic variables needed to start publishing org notes to your hugo website are org-hugo-section and org-hugo-base-dir
(setq org-hugo-section "website-section")
;;e.g. where you want your pages/posts to appear - "blog" for website.github.io/blog
(setq org-hugo-base-dir "~/path-to-your-hugo-website-folder")
Usage
In any .org file you can run the command:
org-hugo-export-wim-md
It will use the default values for org-hugo-section and org-hugo-base-dir set above - e.g. if using “blog” as section a new post will appear (depending on your theme).
Customise Export Settings Per File
org-hugo-section and org-hugo-base-dir can be set on a per file basis by including metadata at the top of the org mode file in this format:
#+HUGO_BASE_DIR: /path/to/your/hugo/site
#+HUGO_SECTION: section-name
Publishing
If you also use github pages to host your site then you can manually commit your changes and push your changes to your remote repo but you still need to create a github action to publish the site.
First create a new file “.github/workflows/deploy.yaml” in your hugo site directory. Then, paste in my github action below which automatically publishes on any new push or create your own:
name: Deploy Hugo site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
# Default to bash
defaults:
run:
shell: bash
jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.137.1
steps:
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Build with Hugo
env:
HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
HUGO_ENVIRONMENT: production
TZ: America/Los_Angeles
run: |
hugo \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4