I am Irvin Lim.

I make pretty and functional things on the web.

And... It's up!

So, I happened to be reading my CS3216 blog from last semester, and I realised that it was pretty beneficial to verbalize my thought processes as a software engineer.

Instead of going with Medium as the go-to service to pen down my thoughts, I recently became hooked on using Markdown + Git for pretty much everything - I’ve been using GitBook for note-taking for school for the past semester - and so here it is, a static site generated by Jekyll, and powered with GitLab CI.

Previously, on WordPress

My old WordPress-powered website really needed a revamp. I set up it quickly in about 2 nights last summer as part of my application for CS3216, but I’ve been itching to redesign it for quite some time now.

A preview of what my old site looked like.

A preview of what my old site looked like.

I must stress that for small, lazy projects, there’s really nothing wrong with using WordPress - it’s quick and easy to get things done because of how familiar I am with it, plus you get quite a lot of plugins for free so easily because of their ecosystem.

However, there are much greater benefits from decoupling your certain types of data from a database, and instead depend on version control tools to manage your workflow. My previous WordPress site was heavily dependent on custom post types and custom fields with Toolset Types and Advanced Custom Fields respectively.

I usually configure them in the WordPress dashboard (which saves to database) while simultaneously tweaking theme files in order to get a WordPress site up and running. This makes your code dependent on the contents of the database to work, and without proper schema management (which might be a pain if you wrote out a whole schema just for it), this can’t really scale well. We can do better (even for a personal website).

In comparison, posts in Jekyll depend on a schema implied by the template, which lives in version control, not the database. Furthermore, some types of data are much better off living within VCS, and I would say that I feel much more at ease knowing that my writings or blog posts can be given the same amount of priority as your written code. Just imagine writing all your code on an online editor :)

Setting up Docker for Jekyll

Motivations aside, now for the fun part! Partly inspired by Kent’s tech blog post, I decided to start learning to use Docker to manage and better compartmentalize my dependencies. By creating a Docker container of a Jekyll image, we can run Jekyll within a contained environment with no installations needed, with as simple as a docker-compose.yml:

jekyll:
    image: jekyll/jekyll:pages
    command: jekyll serve --watch --incremental --force_polling
    ports:
        - 4000:4000
    volumes:
        - .:/srv/jekyll

What this does is to bind the host’s port 4000 to the container’s listening port 4000, hence allowing us to run the contents of jekyll serve directly within your browser at localhost:4000. Then, creating/starting the container is as simple as:

docker-compose up

To run any commands within the container, such as gem install, you need to use docker exec. The syntax goes as follows:

docker exec -it <container_id> <command>

To get the container ID, you can use docker ps to get the list of container IDs.

In fact, we can bring this even further by integrating Docker actions directly within WebStorm, my current IDE of choice. (Thanks again Kent!) Make sure you have the Docker integration plugin installed, and then define a local Docker server under Preferences > Build, Execution and Deployment:

Screenshot of WebStorm preferences pane.

Screenshot of WebStorm preferences pane.

After that, press the Command key twice and click the Docker tab at the bottom of the screen, which gives you this wonderful interface for all your Docker needs:

Docker panel directly integrated into WebStorm!

Docker panel directly integrated into WebStorm!

For someone new to Docker like me, this definitely helps ease the learning curve of Docker whilst also picking up Jekyll at the same time.

Jekyll theming

I was pretty dissatisfied with the available Jekyll themes and couldn’t find a sleek-looking theme for a blog as well as portfolio/resume. I was also itching to get my hands dirty with Jekyll as well, so I decided to design mockups in Sketch first, before beginning to code up the theme. I also got to quickly pick up the Liquid template language created by Shopify, which is used internally by Jekyll.

All Jekyll sites/themes have a _config.yml file which contains essential config settings, such as site title, or which gems will be included during build time. You can also include custom settings which will be accessible by each template file included in the theme.

For example, my _config.yml includes the following:

navigation:
- title: Me
  url: /
- title: Portfolio
  url: /portfolio/
- title: Blog
  url: /blog/
- title: Resume
  url: /resume/

As you can see, I treat the _config.yml like a router, as each component can iterate through site.navigation to display the respective items, as follows:

{% for link in site.navigation %}
  <a href="{{ site.baseurl }}{{ link.url }}" {% if link.url == page.url %}class="current"{% endif %}>
    {{ link.title }}
  </a>
{% endfor %}

I was also pleasantly surprised to find out that the Liquid templating language supports control flow and iteration semantics, as seen in the above example as well.

Sass and Jekyll

I love using Sass (SCSS), and I was happy to know that Sass is supported out of the box in Jekyll. Just add the following to your _config.yml:

sass:
  add_charset: true
  sass_dir: assets/sass
  style: :compressed
  
exclude:
  - assets/sass

Then, create a root SCSS file called main.scss at assets/css. If you’re wondering why the file is under css/ instead of scss/, it’s because any SCSS file interpreted by Jekyll will be compiled with the same filename at the same directory path, so you get assets/css/main.css, which is what we want.

Finally, your root SCSS file must start with two lines of three dashes, as follows:

---
---

/* Sass imports here... */

For more information, see the official documentation for Jekyll assets.

Templating

Jekyll allows you to create powerful templates using Front Matter variables. These are defined at the top of your HTML/Markdown pages between the two lines of three dashes. We’ll look at the 1our portfolio page markup as an example.

---
layout: portfolio
year: 2016
title: 1our
tagline: Earn good money in NUS for 1 hour or less!
device: desktop
orientation: landscape
banner: 1our.png
images:
  - 1our.png
tags:
  - React
  - Material-UI
  - Koa.js
  - Bookshelf
  - Knex
demo_url: https://1our.today
---

Content here...

These variables are accessible in the portfolio.html layout as page.tagline and so on, which is pretty neat.

Variables are also automatically passed into inclusions, so if page.images is available in a template, it is also available in children templates. For example:

In portfolio.html:

<div class="browser-mockup">
  {% include carousel.html %}
</div>

In carousel.html:

{% for image in page.images %}
  ...
{% endfor %}

Alternatively, you can use the capture or assign tags to dynamically create new Liquid variables.

Start writing!

With all of that out of the way, it’s finally time to start writing! By default posts in Jekyll should be placed under _posts/, with the following format: YYYY-MM-DD-blog-post-title.md.

Alternatively, drafts can be placed under _drafts, and will be hidden from the site unless the --drafts flag is set during jekyll serve.

To help with this workflow, I found jekyll-compose which allows you to create posts and drafts with automatically formatted dates with simply jekyll post "My New Post".

Since we are running Jekyll in a Docker container, we need to use docker exec to execute a command within the container.

GitLab CI

Now we’re only left with deployment and then we’re good to go! Being a fan of GitLab since 2015, I’ve been dabbling with my own GitLab CE instance on my Linode VPS, initially mainly to get around the lack of free unlimited private repositories and team sizes on GitHub and BitBucket. I’ve been using my GitLab for a variety of purposes, including hosting my server configuration files with a post-receive webhook using my Git deployment system created in 2015 as well.

GitLab recently brought Pages to its Community Edition, and I got around to enabling and configuring it in the last few weeks. It’s the same as GitHub Pages, except that you get to be in control of the whole CI/CD pipeline, using a .gitlab-ci.yml file.

For the purposes of this Jekyll site though, there isn’t much difference between GitHub and GitLab Pages. Except that GitHub Pages doesn’t let you choose your dependencies and versions. Like jekyll-archives here.

So, with all of the abovementioned reasons I decided to go with GitLab CI. We just need to check in a .gitlab-ci.yml file into your GitLab repo as follows:

image: ruby:2.3

variables:
  JEKYLL_ENV: production

before_script:
- bundle install

pages:
  stage: deploy
  script:
  - bundle exec jekyll build -d public
  artifacts:
    paths:
    - public
  only:
  - master

The artifacts field specifies paths matching the pattern public to be stored on disk even after the pipeline stage completes. This is used by GitLab pages, which depends on the artifacts produced by a pages job.

The site will then be available at the GitLab pages URL once the job completes. For my setup, because the repo is called irvinlim.com and my username is irvin, the site can be found at http://irvin.pages.irvinlim.com/irvinlim.com. That’s a whole lot of narcissism right there, so I set the CNAME to point to that URL instead.

The final step would be to set up an SSL certificate, which can be easily created with auto-renewal using Let’s Encrypt.

Done!

Phew! And that’s it for the first blog post, which should pretty much have been split up into smaller posts.

I’ll try my best to be disciplined enough to write in this blog every once in a while, so do come back again soon to find out what’s going on in my geeky life! :)