Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: jekyll

  • Porting Jekyll to Hugo

    Porting Jekyll to Hugo

    Importing content is always the bane of moving systems.

    Now one of the things Hugo has is a cool command called $ hugo import jekyll – and yes, it does exactly what you think it does. This was interesting to me since I wondered if I could switch my library from Jekyll to Hugo and yes, yes I can.

    The site I have on Jekyll has a few more posts than the first one I built on Hugo. This one has around 1500 pages. Excited, I ran the command:

    Importing...
    Congratulations! 0 posts imported!
    

    That’s not right. I spent a few hours trying to run it in various permutations, but I was never able to get it to run right. Thankfully, I didn’t need to since I could just copy my content over. There was no translation needed, as I was already using yaml headers in my .md files so that actually was a pretty painless transition.

    The theme on the other hand… Well. I had a complex site with data files and weird junk being thrown around. That was just learning how to translate for-loops for ranges, with some where clauses tossed in.

    Was it hard? Yes. But that’s not what you’re really asking.

    Was it worth it?

    Excuse me while I whip this out:

    Change detected, rebuilding site
    2015-12-11 21:42 -0800
    0 draft content
    0 future content
    1479 pages created
    0 paginator pages created
    16 categories created
    66 tags created
    in 4611 ms
    

    Yes. The site builds faster, which is a win. It also creates tags and categories that can automatically cross link. I can make ‘sections’ without having to define them in my config file, just by making folders. I can spin up templates quickly. I have a little more redundancy than I’d like, but as I master GoLang, this becomes less and less.

    Build time ranges from 11737 ms to 2116 ms. Milliseconds. They were into the minutes with Jekyll, even though Jekyll 3 was notably faster than version 2. It was still taking me about 2 minutes to rebuild the Jekyll site, even with incremental builds working. Plus I had to build and rsync every time, in addition to Git pushing. Now I just Git and done.

    Oh and JSON works remotely out of the box. I just have to get better at my range calls now.

    What’s Different?

    Making a ‘static front page’ with Hugo is harder. In fact there’s still an open trac ticket on it. I was able to use an idea I already had, a custom post param called “type” for tagging ‘index’ posts in the news pages so I didn’t get a list of my indexes when I wanted to list all news from 2002. I leveraged that and tagged my primary index ‘mainindex’ and put a quick check in my index.html in my theme:

    {{ range .Data.Pages }}
        {{if eq .Type "mainindex" }} 
            {{ partial "content.html" . }}
        {{end}}
    {{ end }}
    

    Instead of doing a normal loop where, like a blog it shows me posts in reverse order, it just showed that specific content.

    But…

    If there’s a file in that Section with the type of ‘Index’ then it shows that. Of course… While index.md doesn’t get used in the main content folder, it does in Sections. If I have a file named index.md in a section, that makes index.html like I expected. Since I still wanted lists in the majority of cases, I tweaked the content of my default list file (list.html) so that I could always show a ‘main’ file:

        {{ range .Data.Pages.ByTitle }}
            {{ if eq .Type "index" }}
                {{ .Content }}
            {{ end }}
        {{ end }}
    
        <ul>
        {{ range .Data.Pages.ByTitle }}
            {{ if ne .Type "index" }}
                <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
            {{ end }}
        {{ end }}
        </ul>
    

    Then I renamed all the index.md files in the Sections to main.md but this created another issue. Now I had two URLs that worked. I could have put this into the template for the section to avoid this, but I want to separate content and theme as much as humanly possible. WordPress habits. For now, I’ve left this alone. If someone is clever enough to go to a non-linked, non-sitemaped page instead of the index, I think my SEO will live. It’s more than I wanted to play around with loops.

    Speaking of the loops and lists, getting a list of a ‘sub section’ is not currently possible either. Rather, they do work, but there’s no default templates for sub-sections. This was a small problem since I structured my site like this:

    .
    └── content
        ├── news
        |   ├── index.md          // /news/
        |   ├── 2001
        |   |   ├── loch-ness.md  // /news/2001/loch-ness/
        |   |   └── monster.md    // /news/2001/monster/
        |   └── 2002
        |       ├── nessie.md     // /news/2002/nessie/
        |       └── spock.md      // /news/2002/spock/
        └── posts
    

    Now, I don’t need a custom template for each sub-section, but I did want to use my custom list template for each sub-section. To work around this, I made a template in /layout/section/news.html that had this:

    	{{ range .Data.Pages.ByTitle }}
    		{{ if and (eq .Type "index") (ne .Params.topic "index") }}
    			{{ .Content }}
    		{{ end }}
    	{{ end }}
    

    I know this is weird. The Type of index means “I am the main index file of the section” while the topic index means “I am an indexing file and not a normal news article. This gives me my main index of /news/ giving me a custom content page with information like I wanted, using the main.md format I use in all sections.

    Then in each sub-section, I use a very simple index.md file:

    ---
    title: News Articles (1992)
    author: Mika Epstein
    layout: news
    topic: index
    date: 1992-01-01
    permalink: /news/1992/
    categories: ["News"]
    tags: ["1992"]
    ---
    
    {{< news >}}
    

    That weird bit in the content is a shortcode ala Hugo, which calls the file /layouts/shortcode/news.html that has this:

    {{ $date := $.Page.Date.Format "2006" }}
    
    <table class="infobox">
    
        <thead><tr>
            <th>Date</th>
            <th>Source</th>
        </tr></thead>
    
        <tbody>
        {{ range where $.Page.Site.Pages.ByDate "Section" "news" }}
            {{ $thisdate := .Date.Format "2006" }}
    
            {{ if and (eq $date $thisdate) (ne .Params.topic "index") }}
    
                <tr>
                    <td>{{ .Date.Format "01 January" }}</td>
                    <td><a href="{{ .Permalink }}">{{ .Title }}</a></td>
                </tr>
    
            {{ end }}
        {{ end }}
        </tbody>
    </table>
    

    That spits out a table of all the pages in that section by date.

    What’s Next?

    It took a lot to get here, or so it may seem. This took me two nights to work out. That’s it. So now I have to figure out the next steps that have vexed me:

    1. How do I properly mimic a for-loop with range?
    2. Can I make a responsive gallery out of Hugo?
    3. Can I power a Hugo site with WordPress JSON?

    And that’s a whole ‘nother story.

  • Hugo

    Hugo

    I’ve been playing with Jekyll a lot. After WordCamp US, I started toying with the idea of a JSON powered Jekyll site, where WordPress output its posts as JSON and Jekyll pulled in the posts and converted them. This ran into many snags. It wouldn’t be ‘dynamic’ for one, but the biggest issue is that Jekyll’s JSON reading ability was terrible. It didn’t like the complex JSON that WordPress put out.

    That sent me hunting down other things like Hugo. Unlike Jekyll and it’s use of Liquid, Hugo uses Go (hence the Go in the name you see).

    Installation (on a Mac) is easy.

    brew install hugo

    Done. It’s harder on my server, but still easier than Jekyll, which started to become a ‘thing’ as I worked through all this.

    Using Hugo is remarkably similar to Jekyll except that it works faster and a little more smoothly. The site builds incredibly fast and it dynamically refreshes. So if I edit a post, the page refreshes itself. This let me tweak my theme and posts and sort out the new language incredibly fast. Edit a file, boom, I see what’s wrong.

    It’s about as logical as Jekyll too, so it took me one DayQuil addled afternoon to sort out how to make things work.

    The Basics

    The basic are simple. You have a basic structure like this:

    ▸ archetypes/ 
    ▸ content/
    ▸ data/
    ▸ layouts/
    ▸ static/
    ▸ themes/
    config.toml

    The config file is what you think it is. Your posts go in content and the html-ized version shows up a public folder that gets created on the fly. The data folder is for your static data like a .json file or a .yaml.

    Independant to your theme, you can put css and js in the static folder, and layouts in the layout folder. Ditto archetypes, which are post-types. So if you know you’re always going to have a post type of ‘musician’ and you want it to have special headers, then you can have an archetype called musician.md with all that pre-filled in. Then when you want to make a new entry for Clifford:

    $ hugo new musician/clifford.md

    You can also have those in your theme if you wanted, but generally I use the same theme and separate projects. At this point, I was impressed enough to be swayed from Jekyll. I’m not going to explain how to write a post, since it’s just markdown and a header, just like Jekyll or GitHub Pages.

    Building Your Site

    The commands are basic. Running $ hugo server will build your demo server. Of course, you’ll want to post your drafts, so you need to add the param --buildDrafts … Oh and you want a theme …

    $ hugo server --theme=utility-pro --buildDrafts

    That’s silly, right? Why do I have to define all that? Thankfully I can edit my config.toml file:

    baseurl = "http://example.com/videos"
    languageCode = "en-us"
    title = "My Super cool Video Library"
    theme = "utility-pro"
    buildDrafts = "true"
    [params]
    Subtitle = "Videos about cats, collected from the internet."
    

    Now every time I run the command ‘hugo’ it will build my drafts with my theme!

    $ hugo
    45 of 45 drafts rendered
    0 future content
    45 pages created
    42 paginator pages created
    14 tags created
    3 categories created
    in 254 ms

    That’s incredible fast seeing as it built everything. Of course the other site I have is a great many more pages.

    Theming

    Since I’d already mastered Jekyll theming, this was trivial. Go and Liquid are weirdly similar and most of it was transposing. There’s not much to say here except that there’s a Twenty Fourteen Theme for Hugo and it’s pretty much what you expect. For WordPressers, it’s a good place to start.

    Shortcodes

    The neat thing is that Hugo has shortcodes! They’re not like WordPress ones, but you can see the similarity between WordPress and Hugo.

    [video mp4="video.mp4" flv="video.flv"]

    vs.

    {{< video mp4="video.mp4" flv="video.flv" >}}

    Sadly there’s no oEmbed. And I had to write the shortcode on my own, but again, if you know the basics of logic all this stuff is easy. Here’s the magic behind the shortcode:

    <video class="video-js" width="{{ if .Get "width" }}{{ .Get "width" }}{{ else }}640{{ end }}" height="{{ if .Get "height" }}{{ .Get "height" }}{{ else }}385{{ end }}" controls>
    
    	{{ if .Get "mp4"  }}<source src="{{ .Get "mp4" }}" type="video/mp4">{{ end }}
    	{{ if .Get "ogg"  }}<source src="{{ .Get "ogg" }}" type="video/ogg">{{ end }}
    	{{ if .Get "webm" }}<source src="{{ .Get "webm" }}" type="video/webm">{{ end }}
    
    Your browser does not support the video tag.
    </video>
    

    Once you look at it, it’s remarkably like WordPress. Only I don’t need a plugin. Everything in /layouts/shortcodes/ are like mu-plugins.

    And So?

    And so Hugo won enough of my attention that I’m going to keep playing with it and see what’s next.

  • Octopress

    Octopress

    A brief history lesson. In the beginning there was Jekyll, a website generator that created static sites for you to deploy to your server. And then there was Octopress, a ‘framework’ for Jekyll that actually was a fork of one guy’s Jekyll site.

    Octopress is basically some guy’s Jekyll blog you can fork and modify.

    That’s a direct quote from Brandon Mathis, the creator and curator of Octopress. But it wasn’t a framework like WordPress people think of Frameworks. It wasn’t like Underscores, which is just a theme framework. It really was more like a one-click install for Jekyll, that had someone’s theme on it.

    Wisely, Mathis is working on changing this. Starting with Octopress 3 (currently 3.0.11) it’s a Jekyll add-on. While there is no ‘migration’ explanation yet, if you’ve never used Octopress, it’s a great time to start.

    How to Install

    Add this line to your application’s Gemfile:

    gem 'octopress', '~> 3.0'

    And then execute:

    $ bundle

    You can also install with bundler if you want, but it works out about the same in the end.

    How to Use

    I was stuck using bundler on my personal computer. That meant to use Octopress I had to do this:

    $ bundle exec octopress COMMAND

    Sucks, doesn’t it? After reading Ben Hamill’s post about ‘never typing bundle exec again’, it was fixed! I used the Ruby fix since it’s just me on the project.

    Now I can use octopress as my command prefix.

    What I Dig

    The deploy is way better than my own. Just put that out there.

    Also there’s a draft command!

    $ octopress new page _legal/terms/

    That will make the file /_legal/terms/index.html and I’m happy. If I want to use custom templates, I can do that too:

    $ octopress new draft "New Article" _news/2015/articlename --slug articlename --template _template/news --date now

    Sadly I can’t move the template folder. I wanted to store it in _jekyll/templates/ but that’s not an option. Also moving things to the _drafts folder is a little techy at best, since they assume you want to make posts and I’m making collection pages.

    Most of the time I do exactly what I was doing with MediaWiki, and that is to copy the content of an existing file into a new one. Most of the time I just copy the file, rename, and edit it. It’s not perfect, but it works and I know I get the right layout that way. I plan to look into why drafts is so touchy about where things are, and how to make it behave better with collections, but Octopress 3 is still in the early stages.

  • Quick Notes on Ruby and Jekyll

    Quick Notes on Ruby and Jekyll

    I feel like I should be writing about Once Upon A Time at this point…

    Let’s take a moment to talk about our stack here.

    • Ruby is a dynamic, reflective, object-oriented, general-purpose programming language.
    • Ruby libraries are bundled into gems.
    • Jekyll is a gem that can publish static websites.
    • Bundler lets you list all your dependencies required for the project you’re working on.
    • A Gemfile is a file in which we can list gems for the aforementioned dependencies.

    Still with me?

    This matters because you can use a Gemfile to define your standard libraries for a Jekyll site. The general idea is that you install Bundler:

    $ gem install bundler

    Then you make a Gemfile in your Jekyll folder:

    source 'https://rubygems.org'
    
    gem 'jekyll', '>= 3.0.0.pre.beta9'
    gem 'jekyll-oembed', :require => 'jekyll_oembed'
    gem 'jekyll-last-modified-at', :require => 'jekyll-last-modified-at'
    

    What this does is it defines what version of Jekyll I want to use and some of the gems I want to use. For example, if I wanted to add Jekyll Compose to all the users of my Git repository, I would add this:

    group :jekyll_plugins do
      gem 'jekyll_compose'
    end
    

    Now all they have to do is run bundle after their git pull, and they get the new requirement.

  • Mailbag: But You Can’t Post Mobile!

    Mailbag: But You Can’t Post Mobile!

    This has been marked as the biggest downside to using Jekyll. Once I started telling people I was moving the Wiki to Jekyll, a great many of them were cautionary about this issue.

    How do you post from your phone or iPad?

    The answer is that I don’t.

    I won’t lie. Mobile posting is a pain. Since I don’t have Jekyll running on my server, I can’t edit a file there and regenerate. If I had that it would all be a lot easy. In my case, since I’m using it as a non-blog it’s never the place I need to post mission critical things. Besides, if you’ve ever tried to keep your pretty formatted WordPress site updated when you want a custom crafted excerpt and a featured image, from your iPad, I gotta tell you … it sucks.

    And that’s WordPress, something that has a dedicated, usable, app for iOS. WordPress is also pretty okay in mobile. People like Ryan Boren spends a great deal of time caring about mobile usage. WordPress has gotten slower on the admin side in the last decade, but it’s gotten more responsive and agile at the same time.

    MediaWiki not so much. Editing should be a lot easier, seeing as there’s no ‘admin’ back end to mess with things, but for whatever reason MediaWiki was always terrible on my iPad. It was next to unusable on my iPhone. Even with their default themes (remember, with MediaWiki you see the front end theme on page edits) it was dodgy.

    Furthermore, what did I need to post? This is a wiki-type documentation site. It is rarely, if ever, updated on the fly. It houses long form news articles. There are recaps of TV episodes, explanations of humanitarian events, and reports of events. There is no live blogging. There is no quick off the cuff journaling. It’s storytelling.

    So here’s my ‘mobile’ workflow.

    1. Write the content in something, probably Byword
    2. Email it to myself
    3. Probably rewrite the whole thing in longer form, with design and fancy things
    4. Post

    I could probably streamline that better if I saved from Byword to Dropbox and had that automatically copy over (suggestions welcome), but I don’t really write from my iPad that much. I usually send myself an email with six or seven links and a note to ‘Import these things…’

  • Jekyll Table of Contents

    Jekyll Table of Contents

    One of the cool things about MediaWiki, about the only thing I missed, was the built in table of contents display. With Jekyll, since this was a static sort of site, you would have to tell it ‘When you build this page, include a table of contents.’

    And I found a brilliant Jekyll plugin, Jekyll ToC Generator, that added in a beautiful jquery based table of contents with a click back to top feature. But there was a problem. When I installed it and ran a build to test it, my Jekyll site took nine times as long to build.

    In order to generate a Jekyll site, you run the command jekyll build and, on Jekyll 3.0, that gives you the output “done in 8.493 seconds” or so on. Now, if I do a full build on a site I’ve cleaned (there’s a clean command you can run to scrub the site and ensure you get a clean rebuild), it generally takes about a minute. That’s to build a thousand files with a lot of weird trickery. If I’m just rebuilding the changed files, it takes about 10 seconds. Much more reasonable.

    With the ToC Plugin, it took 98 to 100 seconds, every single time. Right away, I knew why. I had included a plugin that had to check every single page on the site on that rebuild, see if it needed a table of contents, and then build the page. Of course that took a long time!

    I’m always talking about needs and wants when I work on websites. It’s a basic principle my high school drilled into me. Understand what you need and how it’s different from your wants. Don’t compromise on needs. Well, I knew that I didn’t need a table of contents, not on every page, so it clearly had to be a ‘mostly want.’

    By contrast, having my site build quickly was a need. A fast build ensured less overhead, less weight, and less time spent. Time is a massive factor in websites. The rendered site has to be fast for users, this much is obvious to everyone. But having your build be fast means you, the site maintainer, spends less time on the parts that don’t make the site better, freeing you to develop and write.

    Also speed is something Jekyll wants to work on. The build different between the 2.3 version of Jeykll and the 3.0-pre beta, is incredible. In 2013, a site with “362 articles with 660 words in average” took around 10 minutes for a full build. I have double the articles, about the same amount of words, and it’s a minute for a full build. It’s faster on my faster laptop (duh).

    The decision tree for Jekyll is more obvious on build than the same one is for WordPress (or MediaWiki) on render. The basic concept is simple. The more complex your site, the longer it takes to generate pages. For WordPress (or MediaWiki, or Drupal, or Joomla, etc etc), the render happens when someone visits your site. For Jekyll and other static site generators, the render occurs when you build the site. That means with Jekyll I can see right away, before I get close to deployment, which means I make the decisions well before the ‘stage’ step of my deployment process.

    What’s more important? The complexities that make your site personal or a fast build?

    Here’s an example from a Jekyll discussion on the matter. Someone had the following code in the templates, which made the date output rather pretty:

    <span>{% assign d = page.date | date: "%d" | plus:'0' %}
        {{ page.date | date: "%B" }} 
        {% case d %}
            {% when 1 or 21 or 31 %}{{ d }}st
            {% when 2 or 22 %}{{ d }}nd
            {% when 3 or 23 %}{{ d }}rd
            {% else %}{{ d }}th
        {% endcase %}, 
        {{ page.date | date: "%Y" }}
    </span>
    

    But that had to run on page builds, which naturally was going to make a site slower. One of the ways Jekyll has improve this was to introduce incremental updates. Only update the pages that need updating. That is a big “baboom!” moment and it let me run the plugin jekyll-last-modified-at (which spits out a last modified date on pages) without any performance hit except on the clean build. Since that only gets called when a page is built, and a page is only built when it changes, it’s a massive improvement for me.

    What does all this have to do with the table of contents?

    Once I pushed it into a ‘want’ and not a ‘need’ I opened my mind to other possibilities. I stopped looking for a Jekyll or Ruby or Liquid based table of contents, and I asked myself “Can Markdown make a table of contents?”

    Markdown is a ‘language’ like HTML that is actually faster to write in than raw HTML but can be read, rendered, and output as HTML. I’m a big fan of HTML and part of why I picked WordPress back in the beginning was that I stumbled on a post where Matt Mullenweg talked about how he didn’t like bbCode and didn’t want it in WordPress. HTML was something we knew. Why make people learn something new?

    It wasn’t until I started blogging more on my iPad and phone that Markdown made sense. Now I’m quite the fan. But I knew that I didn’t know a whole lot about Markdown. I did know that Jekyll used a flavor called ‘kramdown’ (all lowercase) so I read up on that and found that kramdown has a built in built in table of contents generator that was incredibly easy to implement.

    * TOC will be output here
    {:toc}
    

    It’s not something I want (or need) on every page, so I just put that on a few pages. No real overhead added and it’s easy enough to style with CSS. Suddenly I have my cake and I can eat it too.