Building a website with Emacs
I would like to make a confession… I detest most websites I visit on a daily basis. I wanted to make a difference with my little personal corner of the internet. What do you know? Emacs can totally do that.
You see, Emacs packs an exceptional mode, called Org Mode, that comes
with many wonderful functionalities, that which powers this website
In short, you specify the location of a particular thing, and where it should go upon export, as a result, we have the utmost freedom to design our own file hierarchy - here's what I've come up with:
~/projects/grtcdr.github.io ├── org/ │ ├── blog/ │ ├── css/ │ ├── data/ │ ├── img/ │ ├── index.org │ └── contact.org │ └── html/ ------ This directory is generated by org-publish ├── blog/ ├── css/ ├── data/ ├── img/ ├── index.html └── contact.html
1. An example to get you started
I'd like to introduce you to the most basic form of a working
(require 'ox-html) (setq org-publish-project-alist '(("example.com/org" :base-directory "~/website/org/" :base-extension "org" :publishing-directory "~/website/html/" :publishing-function org-html-publish-to-html)))
What happens when you create a
.org document within your
:base-directory – save it – hit
M-x org-publish RET, is nothing
short of magic!
Org, being the smarty-pants tool it is, takes the original file and
publishes it to
That's exactly what we would need if we had tens or hundreds of
documents and wanted to automate the export process.
Things to keep in mind:
:base-extensionexpects an extension, without a
:publishing-functiondepends on the type of content you intend to export.
Let's have a look at another example, though this time, we'll export some stylesheets, too.
(setq org-publish-project-alist '(("example.com/org" :base-directory "~/website/org/" :base-extension "org" :publishing-directory "~/website/html/" :publishing-function org-html-publish-to-html) ("example.com/css" :base-directory "~/website/css/" :base-extension "css" :publishing-directory "~/website/css/" :publishing-function org-publish-attachment)))
Now we have two different publishing projects, one for
and another for
The main differences being, the
:publishing-function and the project
identifier, i.e. the
CAR of the association list. My advice, pick
meaningful names for your project identifiers. It doesn't necessarily
have to start with a URL, that's just my preference.
Okay! This is enough to get your website rolling, although you might want to see the next section for a more complicated setup.
I always like to experiment with the structure of my
leaves me with a temporarily broken setup sometimes.
I took the steps to remedy this with a few functions, which I'll use
:publishing-directory properties, the
more sensitive area of this setup.
(defvar site-base-directory "~/projects/grtcdr.github.io/" "The base of the site where files will are to be processed and exported.") (defun site-content-directory (context &optional directory) "Prefixes the provided DIRECTORY with the ’site-base-directory’ given the CONTEXT." (cond ((equal context 'publish) (concat site-base-directory "html/" directory)) ((equal context 'base) (concat site-base-directory "org/" directory))))
site-base-directory is the base location of my site, and
site-content-directory will build a path depending on the parameters
I pass. This makes it a lot safer if I ever decide to move things
Now I'd like to present my setup. It does all of the heavy lifting for me, and allows me to focus on more important things such as chatting with strangers on IRC.
(use-package ox-publish :custom (org-publish-project-alist `(("grtcdr.github.io/content" :base-directory ,(site-content-directory 'base) :base-extension "org" :publishing-directory ,(site-content-directory 'publish) :publishing-function org-html-publish-to-html :exclude "\\(README\\|setup\\).org" :recursive t :sitemap-filename "index.org" :sitemap-title "grtcdr's website" :with-author nil :with-creator nil :with-date nil :with-email nil :with-title nil :with-toc nil :section-numbers nil) ("grtcdr.github.io/img" :base-directory ,(site-content-directory 'base "img/") :base-extension "png\\|jpe?g" :publishing-directory ,(site-content-directory 'publish "img/") :publishing-function org-publish-attachment) ("grtcdr.github.io/blog" :base-directory ,(site-content-directory 'base "blog/") :base-extension "org" :publishing-directory ,(site-content-directory 'publish "blog/") :publishing-function org-html-publish-to-html :exclude ".\\(setup\\|navigation\\).org" :with-date t :with-title nil :with-toc nil :section-numbers nil) ("grtcdr.github.io/css" :base-directory ,(site-content-directory 'base "css/") :base-extension "css" :publishing-directory ,(site-content-directory 'publish "css/") :publishing-function org-publish-attachment) ("grtcdr.github.io/data" :base-directory ,(site-content-directory 'base "data/") :base-extension "txt\\|pdf" :publishing-directory ,(site-content-directory 'publish "data/") :publishing-function org-publish-attachment) ("grtcdr.github.io" :components ("grtcdr.github.io/img" "grtcdr.github.io/data" "grtcdr.github.io/css" "grtcdr.github.io/content" "grtcdr.github.io/blog")))))
There's a project identifier for every component of the website, and the last one groups them all together, so that I don't have to selectively export every single one.
If you'd like to explore this topic in greater detail, please read the wonderful documentation provided by the Org project.