From Jekyll to jorge

As of a couple of weeks ago,, previously a Jekyll website, is generated with jorge. The migration process was slightly more complicated than I expected, but still very doable. Below are the steps I took, documented for posterity. The relevant PR is here.

General Jekyll-to-jorge changes

The first few changes would be the same for any Jekyll site converted to jorge.

  1. Renamed files and directories:

    mv _layouts layouts
    mv _includes includes
    mv _data data
    mv _config.yml config.yml
    mkdir src
    mv assets src/
    rm Gemfile
  2. Removed most of the config.yml contents since they weren’t necessary anymore.
  3. Removed instances of the strip_index template filter since I didn’t port it to jorge and it wasn’t necessary anyway.
  4. Renamed configuration references in templates, to use the site.config.* namespace. For example, changed to
  5. Added a template file for the atom feed, to replace the jekyll-feed plugin.
  6. Tweaked the CSS to stop relying on whitespace for the layout of inline blocks, since that’s removed by the minifier.

I also updated a little Makefile I have, to run jorge commands instead of Jekyll. specifics

One of the peculiarities of my site (compared to other Jekyll projects), was that I generated my blog posts from org-mode files. But since the HTML generated by the default org-export has an unconventional structure, I set up my Emacs configuration to export to Markdown first and let Jekyll do the HTML conversion. So I had to make a couple of extra directory changes to migrate my posts to jorge:

rm -rf _posts          # remove intermediate .md files
mv org/_posts src/blog # put .org posts in the jorge site source

Since I was already changing the structure of my website, I wanted to take the opportunity to make an update I had been postponing. Instead of:

I wanted post URLs to look like:

So I wrote a Python script to rename the files in bulk and automate the remaining content updates:

  1. Remove the date from file names.
  2. Remove the date from internal links in the org files.
  3. Remove the #+BEGIN_EXPORT html and #+END_EXPORT that wrapped the front matter.
  4. Ensure the front matter is the first line of each post file.
  5. Ensure the front matter includes a lang key since I was relying on config.yml to set lang: es as a default.
  6. Rename the footnotes header since I was relying on org-export internals to translate it from the default, while go-org leaves it as-is.
  7. Patch image links to stop assuming file-relative paths (e.g ../assets/img/)

Since these changes required serving posts at a different location, I needed to update my Nginx configuration so old links wouldn’t break. On the first version, I used try_files so both the Jekyll and jorge directory layouts were supported. After swapping the files, I changed the configuration again to issue redirects to the new post locations.

Something I noticed after switching to jorge is that a couple of big JavaScript files, already minified by the Closure compiler, caused long build times because the minifier tried to process them anyway. I worked around this by updating jorge to allow to exclude files from the minifier.

org-related patches

Some of the changes were required because the HTML produced by go-org wasn’t the same as the one from my previous setup:

  1. My old org-export to Markdown configuration translated both * and ** headers to <h2> in the HTML. When I switched to jorge, each would produce either <h1> and <h2> or <h2> and <h3>, depending on go-org’s TopLevelHLevel setting. To preserve the layout of my posts, I needed to tweak the migration script to demote * headers to ** so the output always resulted in <h2>.
  2. I needed to replace \ast{} to \lowast{} to preserve how asterisks were rendered in section separators (I wanted ∗ but was getting *).
  3. I updated the CSS to preserve the footnote and centered blocks style.
  4. I updated the CSS to preserve the verse blocks style.