<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Writing on dwmkerr.com</title><link>https://dwmkerr.com/tags/writing/</link><description>Recent content in Writing on dwmkerr.com</description><generator>Hugo -- gohugo.io</generator><language>en-uk</language><managingEditor>Dave Kerr</managingEditor><copyright>Copright &amp;copy; Dave Kerr</copyright><lastBuildDate>Tue, 24 Dec 2019 00:00:00 +0000</lastBuildDate><atom:link href="https://dwmkerr.com/tags/writing/index.xml" rel="self" type="application/rss+xml"/><item><title>Migrating from Ghost to Hugo - Why Bother?</title><link>https://dwmkerr.com/migrating-from-ghost-to-hugo/</link><pubDate>Tue, 24 Dec 2019 00:00:00 +0000</pubDate><guid>https://dwmkerr.com/migrating-from-ghost-to-hugo/</guid><description>&lt;p&gt;With a little bit of free time for a change, I decided to finally migrate my blog from &lt;a href="https://ghost.org/"&gt;Ghost&lt;/a&gt; to a static site generator. I&amp;rsquo;ve been putting this off because it&amp;rsquo;s one of those things that I knew would take longer than I&amp;rsquo;d expect, and to be honest, it it ain&amp;rsquo;t broke, then don&amp;rsquo;t fix it.&lt;/p&gt;
&lt;!-- vim-markdown-toc GFM --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#so-why-bother"&gt;So, Why Bother?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#reason-1---i-write-in-vim"&gt;Reason 1 - I write in vim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-2---i-backup-on-github"&gt;Reason 2 - I backup on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-3---my-workflow-sucks-for-images"&gt;Reason 3 - My workflow sucks for images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-4---i-have-two-sources-of-truth"&gt;Reason 4 - I have two sources of truth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-5---i-want-to-allow-people-to-contribute"&gt;Reason 5 - I want to allow people to contribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-6---i-dont-want-to-manage-a-server"&gt;Reason 6 - I don&amp;rsquo;t want to manage a server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-7---i-need-to-learn-how-do-this"&gt;Reason 7 - I need to learn how do this&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reason-8---static-sites-are-fast-and-simple"&gt;Reason 8 - Static Sites are Fast and Simple&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#picking-a-generator"&gt;Picking a Generator&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#jekyll"&gt;Jekyll&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#gatsby"&gt;Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#hugo"&gt;Hugo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-migration-process"&gt;The Migration Process&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#automating-build-and-deploy"&gt;Automating Build and Deploy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#changing-front-matter-to-yaml"&gt;Changing Front Matter to YAML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#normalising-newlines"&gt;Normalising Newlines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#restructuring-the-content"&gt;Restructuring the Content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#bringing-the-images-to-the-posts"&gt;Bringing the images to the posts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#was-it-worth-it"&gt;Was It Worth It?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- vim-markdown-toc --&gt;
&lt;h2 id="so-why-bother"&gt;So, Why Bother?&lt;/h2&gt;
&lt;p&gt;My first website was built on BlogEngine.net, then WordPress, which has grown into a very powerful platform over the years, but was overly complex for my needs.&lt;/p&gt;
&lt;p&gt;When I first tried Ghost, I loved it. A super clean and minimal interface, with all of the content in Markdown. The editing experience was lovely:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/ghost-ui.png" alt="Screenshot: Thee Ghost UI"&gt;&lt;/p&gt;
&lt;p&gt;Ghost is great, and I&amp;rsquo;ve been a happy user for years. I&amp;rsquo;d highly recommend it to &lt;em&gt;anyone&lt;/em&gt; who wants a lean and clean content management system. However, there were a few key reasons I decided to change. This article is not be advocating for my new setup, or a criticism of Ghost, but might be useful for people who are considering similar changes.&lt;/p&gt;
&lt;h3 id="reason-1---i-write-in-vim"&gt;Reason 1 - I write in vim&lt;/h3&gt;
&lt;p&gt;The Ghost UI is lovely, but I do all of my writing in vim. Writing in the Ghost UI could sometimes be a little slow, and obviously doesn&amp;rsquo;t work offline. I&amp;rsquo;m very comfortable writing in vim. So I would end up writing the post in vim, then copying and pasting into Ghost.&lt;/p&gt;
&lt;p&gt;Right now, this is what my screen looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/vim-screenshot.png" alt="Screenshot: vim editing"&gt;&lt;/p&gt;
&lt;p&gt;Again, I&amp;rsquo;m not advocating for vim, it&amp;rsquo;s just what works for me. The screenshot is with my &amp;lsquo;focus&amp;rsquo; mode setup, which removes all unnecessary clutter (all of my configuration is available on my &lt;a href="https://github.com/dotfiles"&gt;dotfiles repo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="reason-2---i-backup-on-github"&gt;Reason 2 - I backup on GitHub&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m writing all of my content in vim, and storing it in a folder. Some posts take days to write. So it makes sense to keep all of these files in a git repository. This means that I essentially have a robust backup solution, I don&amp;rsquo;t need to use Ghosts&amp;rsquo;s backup. Ghost&amp;rsquo;s backup (for self hosted) also doesn&amp;rsquo;t handle images.&lt;/p&gt;
&lt;h3 id="reason-3---my-workflow-sucks-for-images"&gt;Reason 3 - My workflow sucks for images&lt;/h3&gt;
&lt;p&gt;Because I am writing in vim, and creating screenshots and images, I need to link to them. This means that what I have in my local markdown file won&amp;rsquo;t work for Ghost. With Ghost I need to upload the image, and it will put it in a content folder. But I want to be able to keep my images close to the text, and have consistent addresses for local writing, like so:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/folder-structure-screenshot.png" alt="Screenshot: Folder structure for a post"&gt;&lt;/p&gt;
&lt;h3 id="reason-4---i-have-two-sources-of-truth"&gt;Reason 4 - I have two sources of truth&lt;/h3&gt;
&lt;p&gt;If I need to make a change, do I update my markdown file in my GitHub repo? Or in Ghost? Or both? If I have to change a few things, then I can&amp;rsquo;t just paste in the whole markdown file without breaking the image links. So I basically have two sources of truth, which can easily diverge.&lt;/p&gt;
&lt;h3 id="reason-5---i-want-to-allow-people-to-contribute"&gt;Reason 5 - I want to allow people to contribute&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m already using GitHub and Markdown. In theory this means that it should be very straightforward for people to propose edits or contributions; they can just create pull requests. I don&amp;rsquo;t expect many people would do this, but it appeals to me that people could make corrections or suggest improvements, particularly for technical content.&lt;/p&gt;
&lt;h3 id="reason-6---i-dont-want-to-manage-a-server"&gt;Reason 6 - I don&amp;rsquo;t want to manage a server&lt;/h3&gt;
&lt;p&gt;My website is static content. It&amp;rsquo;s blog posts and that&amp;rsquo;s about it. There&amp;rsquo;s really no need for any kind of application server or database. Disqus handles comments, Google Analytics for traffic data. So I can save myself a few dollars a month by just generating a static site and hosting it on &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt; or &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Static sites can be cached by CDNs so can be very fast for readers. And given the vast majority of my content is already just text and images in a GitHub repo, it doesn&amp;rsquo;t make sense to pay for and manage server when there are a number of static site generators.&lt;/p&gt;
&lt;h3 id="reason-7---i-need-to-learn-how-do-this"&gt;Reason 7 - I need to learn how do this&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve been putting this off for a while. But it will be &lt;em&gt;really&lt;/em&gt; useful to know how to quickly get up and running with a static site generator. There are other projects that I&amp;rsquo;d love to run as sites, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dwmkerr/hacker-laws"&gt;hacker-laws&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dwmkerr/learn-a-language"&gt;learn-a-language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being able to quickly whip up a static site from markdown in GitHub seems like it could be really useful.&lt;/p&gt;
&lt;h3 id="reason-8---static-sites-are-fast-and-simple"&gt;Reason 8 - Static Sites are Fast and Simple&lt;/h3&gt;
&lt;p&gt;Without an application server doing any work, static sites are generally fast. They can be cached, pushed to CDNs and will index well with search engines. In theory, the overall browsing experience should be faster. But I will show performance benchmarks from before and after.&lt;/p&gt;
&lt;p&gt;So next - how do pick a static site generator?&lt;/p&gt;
&lt;h2 id="picking-a-generator"&gt;Picking a Generator&lt;/h2&gt;
&lt;p&gt;I had a few requirements for the generator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I can easily host on GitHub pages&lt;/li&gt;
&lt;li&gt;I can integrate Disqus and Google Analytics&lt;/li&gt;
&lt;li&gt;I have as little complexity as possible, KISS&lt;/li&gt;
&lt;li&gt;I can maintain all of the existing URLs of my posts, so that links from external sites will not break&lt;/li&gt;
&lt;li&gt;I can have a theme which is roughly similar to the original Ghost theme, something minimal and text focused&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A little bit of research suggested that there were three main contenders:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gatsbyjs.org"&gt;Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I actually tried all three. Each engine is popular on GitHub:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/blogging-platforms.png" alt="Comparison of Blogging Platforms"&gt;&lt;/p&gt;
&lt;p&gt;The number of stars a project has is of course not a genuine indicator of quality, but it is interesting to see how quickly Gatsby and Hugo have caught up to Jekyll.&lt;/p&gt;
&lt;h3 id="jekyll"&gt;Jekyll&lt;/h3&gt;
&lt;p&gt;Jekyll makes a tonne of sense. It is very easy to setup for GitHub pages (in fact, GitHub pages assumes you are using Jekyll unless you explicitly tell it you are not).&lt;/p&gt;
&lt;p&gt;Setting up Jekyll was easy - but I couldn&amp;rsquo;t properly import my blog. I used the &lt;a href="https://github.com/eloyesp/jekyll_ghost_importer"&gt;jekyll_ghost_importer&lt;/a&gt; tool, but the generated files seemed to be missing the slug. I wasted some time trying to see if I could resolve this issue, and then decided it was worth moving to the next platform and checking back in on Jekyll another time.&lt;/p&gt;
&lt;h3 id="gatsby"&gt;Gatsby&lt;/h3&gt;
&lt;p&gt;Gatsby is written in Node.js, which had some appeal, as I am far more familiar with Node than Ruby (which Jekyll uses) or Golang (which Hugo uses, and I don&amp;rsquo;t get on with).&lt;/p&gt;
&lt;p&gt;I quickly paused on Gatsby. I had some trouble finding a tool to import data from Ghost, but during my research I realised just how powerful Gatsby is. It can be the front-end for Ghost, with Ghost working as a headless CMS, it can serve GraphQL, runs a React front end and more. These are all technologies I use regularly, but I was concerned that the tool seemed perhaps more complicated than I needed.&lt;/p&gt;
&lt;p&gt;So I paused on Gatsby, but will definitely look into it in the future if I am building a more complex site from scratch.&lt;/p&gt;
&lt;h3 id="hugo"&gt;Hugo&lt;/h3&gt;
&lt;p&gt;Hugo I was the least excited about. A lot of the hype seemed to be around the speed of the tool, and the fact it is written in Golang. Speed is not really an issue for me in this case and would not be a big factor in my decision. And I&amp;rsquo;ve spent enough time coding with the Kubernetes codebase that I have developed a deep dislike of Golang.&lt;/p&gt;
&lt;p&gt;I was quickly sold on Hugo. Setup was very easy, importing was seamless with &lt;a href="https://github.com/jbarone/ghostToHugo/"&gt;ghostToHugo&lt;/a&gt;, URLs were preserved as needed. I found a nice theme called &lt;a href="https://github.com/jbub/ghostwriter"&gt;ghostwriter&lt;/a&gt; which quickly gave me a locally running site which looked not too bad.&lt;/p&gt;
&lt;p&gt;The generated folder structure was trivial enough for me to quickly work out how to create the few static pages I have (public speaking, about etc).&lt;/p&gt;
&lt;p&gt;Again; no advocating. All three engines seem to be great at what they do. Hugo was the easiest for me to get started on. Once I&amp;rsquo;d picked Hugo, it was time to get started migrating in earnest.&lt;/p&gt;
&lt;h2 id="the-migration-process"&gt;The Migration Process&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve kept some notes on how I did this in case it is useful for others. The post &lt;a href="https://rmoff.net/2018/12/17/moving-from-ghost-to-hugo/"&gt;Moving from Ghost to Hugo by Robin Moffat&lt;/a&gt; was super useful.&lt;/p&gt;
&lt;p&gt;First, I downloaded &lt;a href="https://github.com/jbarone/ghostToHugo/"&gt;&lt;code&gt;ghostToHugo&lt;/code&gt;&lt;/a&gt;. Then I ran the import command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Note: my ghost db backup is a file locally called &amp;#39;db.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./ghostToHugo --dateformat &lt;span style="color:#e6db74"&gt;&amp;#34;2006-01-02T15:04:05.000Z&amp;#34;&lt;/span&gt; -f -p dwmkerr.com db.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next I needed to copy over my images. My &lt;code&gt;~/.ssh/config&lt;/code&gt; is setup with my ghost server, so I could just use &lt;code&gt;scp&lt;/code&gt; to copy the files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scp -r dwmkerr.com:/var/www/ghost/content/images ./dwmkerr.com/static
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The whole site I put in it&amp;rsquo;s own folder, &lt;code&gt;dwmkerr.com&lt;/code&gt;, so that I could use other folders for backups, guides, whatever else I might want, and not pollute the generated site structure.&lt;/p&gt;
&lt;p&gt;Next I downloaded a couple of themes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git submodule add git@github.com:jbub/ghostwriter.git dwmkerr.com/themes/ghostwriter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git submodule add git@github.com:spf13/herring-cove.git dwmkerr.com/themes/herring-cove
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I created a &lt;code&gt;makefile&lt;/code&gt; for common commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make setup &lt;span style="color:#75715e"&gt;# install everything I need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make serve &lt;span style="color:#75715e"&gt;# serve the site locally for testing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make build &lt;span style="color:#75715e"&gt;# build the site for production&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m a big fan of &lt;code&gt;makefiles&lt;/code&gt; as a way to provide an index of key operations for any project (even if all does is call another script or program).&lt;/p&gt;
&lt;p&gt;At this stage I had a working site running locally. However, I noticed some images weren&amp;rsquo;t rendering. It seems that some of my images had paths like &lt;code&gt;/content/images/whatever.png&lt;/code&gt; and some were just &lt;code&gt;/images/whatever.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This was quick to fix in vim. First I used &lt;code&gt;vimgrep&lt;/code&gt; to populate the quickfix list with any markdown file with a &lt;code&gt;/content/images&lt;/code&gt; in the text, then used &lt;code&gt;cfdo&lt;/code&gt; to just replace the string with &lt;code&gt;/images&lt;/code&gt; (asking for confirmation each time to check I wasn&amp;rsquo;t changing something I shouldn&amp;rsquo;t.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:&lt;span style="color:#a6e22e"&gt;vimgrep&lt;/span&gt; \&lt;span style="color:#e6db74"&gt;/content\/images **/&lt;/span&gt;*.&lt;span style="color:#a6e22e"&gt;md&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:&lt;span style="color:#a6e22e"&gt;cfdo&lt;/span&gt; %&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/\/content\/images\//&lt;/span&gt;\&lt;span style="color:#e6db74"&gt;/images\//&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;gc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="automating-build-and-deploy"&gt;Automating Build and Deploy&lt;/h3&gt;
&lt;p&gt;At this stage I had a working site. Setting up a workflow to publish to GitHub pages with GitHub Actions was straightforward, as I&amp;rsquo;ve already updated some projects (such as &lt;a href="https://github.com/dwmkerr/spaceinvaders"&gt;&lt;code&gt;spaceinvaders&lt;/code&gt;&lt;/a&gt;) to publish static sites. The workflow is relatively simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Build &amp;amp; Deploy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;branches&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;master&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;build/**&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build-deploy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-18.04&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Checkout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/checkout@v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;submodules&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Setup Hugo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;peaceiris/actions-hugo@v2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;hugo-version&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;0.61.0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;working-directory&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;./dwmkerr.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;hugo --minify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Deploy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;JamesIves/github-pages-deploy-action@releases/v3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;GITHUB_TOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;BRANCH&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gh-pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;FOLDER&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;dwmkerr.com/public&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Any time a change is made to &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;feat/static-site&lt;/code&gt; gets built and published.&lt;/p&gt;
&lt;h3 id="changing-front-matter-to-yaml"&gt;Changing Front Matter to YAML&lt;/h3&gt;
&lt;p&gt;By default the front matter for the blog is written in TOML. This is not rendered well on GitHub:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/toml-frontmatter.png" alt="Screenshot: TOML front matter"&gt;&lt;/p&gt;
&lt;p&gt;It also looks less than ideal in &lt;code&gt;vim&lt;/code&gt;. After running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hugo convert toYAML
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Things look a lot nicer:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/yaml-frontmatter.png" alt="Screenshot: YAML front matter"&gt;&lt;/p&gt;
&lt;p&gt;YAML front matter is also rendered properly in &lt;code&gt;vim&lt;/code&gt; for me,&lt;/p&gt;
&lt;h3 id="normalising-newlines"&gt;Normalising Newlines&lt;/h3&gt;
&lt;p&gt;A lot of the content from 2013 and earlier was either written in WordPress or BlogEngine.net.&lt;/p&gt;
&lt;p&gt;Ghost had no problems rendering with Windows Style line endings but I wanted to clean this up a bit.&lt;/p&gt;
&lt;p&gt;To convert everything to Unix style file endings, I ran:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; $file in ./content/**/*.md; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dos2unix $file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="restructuring-the-content"&gt;Restructuring the Content&lt;/h3&gt;
&lt;p&gt;After import, my site structure looked like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/posts-and-images-screenshot.png" alt="Screenshot: Site structure"&gt;&lt;/p&gt;
&lt;p&gt;Now this is manageable, but feels awkward. I&amp;rsquo;d rather keep images next to the blog posts themselves. I want to group posts into years so that there are not too many shown in the file tree at any one time (and adding months/weeks/days makes things too fine grained). It also means that the page doesn&amp;rsquo;t render images on GitHub:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/broken-links.png" alt="Screenshot: Broken Links"&gt;&lt;/p&gt;
&lt;p&gt;The ideal structure would be just like this post:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/ideal-structure.png" alt="Screenshot: Ideal Structure"&gt;&lt;/p&gt;
&lt;p&gt;It turns out that this is absolutely fine to do - as long as you name the post markdown &lt;code&gt;index.md&lt;/code&gt;. This took an hour to work out! The feature is known as &lt;a href="https://gohugo.io/content-management/page-bundles/"&gt;Page Bundles&lt;/a&gt;. This is a delight - the content renders on GitHub just as well as it does on the site!&lt;/p&gt;
&lt;p&gt;Migrating everything by hand would be something of a nightmare. Writing a program to do this is probably overkill, so here&amp;rsquo;s how I did it in &lt;code&gt;bash&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Go through each post.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; post_path in dwmkerr.com/content/post/*.md; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Found &lt;/span&gt;$post_path&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;basename -- &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$post_path&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;filename%.*&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Grep out the date line.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dateline&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;^date: &amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$post_path&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# We know how to get the year as the date line is consistent in all posts:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# date: &amp;#34;2012-12-09T16:11:27Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; year&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;dateline:7:4&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#75715e"&gt;# i.e. the four characters from index 7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Create the folder for the post.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_folder&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dwmkerr.com/content/post/&lt;/span&gt;$year&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;$filename&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mkdir -p &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$new_folder&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Move the post.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mv &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$post_path&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$new_folder&lt;span style="color:#e6db74"&gt;/index.md&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34; -&amp;gt; &lt;/span&gt;$new_folder&lt;span style="color:#e6db74"&gt;/index.md&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives a &lt;em&gt;much&lt;/em&gt; more manageable folder structure:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/folder-structure-screenshot.png" alt="Screenshot: Better Folder Structure"&gt;&lt;/p&gt;
&lt;p&gt;However, we still have the images sitting in the &lt;code&gt;static&lt;/code&gt; folder.&lt;/p&gt;
&lt;h3 id="bringing-the-images-to-the-posts"&gt;Bringing the images to the posts&lt;/h3&gt;
&lt;p&gt;There are two image formats to deal with - the standard markdown image format, and &lt;code&gt;img&lt;/code&gt; tags, which have been used to customise the size of the image:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;img width=&amp;#34;600px&amp;#34; alt=&amp;#34;Image: The Evolution of Windows&amp;#34; src=&amp;#34;/images/2019/05/screenshot-windows-evolution.png&amp;#34; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Initially I started converting these tags using a &lt;code&gt;bash&lt;/code&gt; script, but this rapidly became too complex. In the end I wrote a quick-and-dirty Node.js script to handle the images. You can find it at:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/dwmkerr.com/blob/master/scripts/collect-images.js"&gt;https://github.com/dwmkerr/dwmkerr.com/blob/master/scripts/collect-images.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This script downloads the images if they are online, or moves them from a given source folder, collecting them all in an &lt;code&gt;images&lt;/code&gt; folder for the post.&lt;/p&gt;
&lt;h2 id="was-it-worth-it"&gt;Was It Worth It?&lt;/h2&gt;
&lt;p&gt;It took a &lt;em&gt;lot&lt;/em&gt; longer than I expected to migrate. &lt;a href="https://github.com/dwmkerr/hacker-laws#hofstadters-law"&gt;Hofstadter&amp;rsquo;s Law&lt;/a&gt; in action. Fixing Disqus pages, trying to clean up old content from 2011, all of this took time.&lt;/p&gt;
&lt;p&gt;The site is definitely faster. Below are the PageSpeed results from before:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/pagespeed-insights-home-before.png" alt="Before: PageSpeed Results"&gt;&lt;/p&gt;
&lt;p&gt;The results now are faster:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/pagespeed-insights-home-after.png" alt="After: PageSpeed Results"&gt;&lt;/p&gt;
&lt;p&gt;And finally I can simple manage my blog using GitHub, Markdown and my preferred flow for writing. Learning about Hugo was very useful, I expect to apply it to my &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series soon.&lt;/p&gt;
&lt;p&gt;One final comment - the &lt;a href="https://github.com/mismith0227/hugo_theme_pickles"&gt;Pickle&amp;rsquo;s Theme&lt;/a&gt; by &lt;a href="https://github.com/mismith0227"&gt;&lt;code&gt;msmith0227&lt;/code&gt;&lt;/a&gt; is what I am using. It was very straightforward to get working, and the code is really well documented, so I could quickly change it as needed.&lt;/p&gt;
&lt;p&gt;There are still some &lt;code&gt;TODO&lt;/code&gt;s - getting RSS working, trying to improve the PageSpeed of posts, cleaning up old content, but all in all it was a fun and worthwhile effort as an end of year programming project.&lt;/p&gt;</description><category>CodeProject</category></item></channel></rss>