Simplifying and extending Jekyll CLI capabilities using Jtasks

When I started using Jekyll, serving a site was as simple as short jekyll serve command. After creating a few first posts I discovered drafts feature. Now serving a site command became jekyll serve --drafts . Then Jekyll 3 was released and I have figured out that GitHub Pages not necessarily switched to building hosted sites using the latest Jekyll release (now GitHub Pages supports Jekyll 3, but migration took a few months). I’m hosting this blog at GitHub, so I had to keep my development environment in align with environment used by GitHub. Otherwise, developing with Jekyll 3 locally and then pushing results to GitHub’s build server on Jekyll 2.4 may result in compatibility issues. Luckily, keeping environment in alignment with GitHub can be easily achieved by using gh-pages gem.

This adds another layer of complexity. Now we need a Bundler to manage our environment. Commands inside a given bundle are launched using bundle exec . Now to serve a site including drafts, we have to type:

$ bundle exec jekyll serve --drafts

Not so convenient as in the beginning, huh?

In my previous post I have showed set up steps and discussed advantages of using Vagrant to build development environment for Jekyll projects. In spite of advantages, Vagrant brings another layer of complexity. For me this resulted in creation of the Makefile with the shortcuts for something like:

$ bundle exec jekyll serve --host 0.0.0.0 --drafts --force-polling

This includes various combinations for different jekyll subcommands and options (basic usage is: jekyll <subcommand> [options] ). Obviously make is not the best way to manage this. It is very easy to get confused with different make tasks.

So, I decided to write my own tool which will wrap common Jekyll commands, providing corresponding set of tasks easily modifiable via both long and short CLI flags. And if I’m writing my own tool, of course it will contain some advanced features 😉.

Meet Jtasks

Jtasks (Jekyll tasks) is a collection of configurable Invoke tasks that provide simple, but powerful, interface to run both common and advanced routines in your Jekyll projects.

With jtasks you can:

$ inv --list Available tasks: build Build the site. clean Clean the site. doctor Search site and print specific deprecation warnings. list List all posts. notify Notify various services about sitemap update. post Create a new post. preview Launches default browser for previewing generated site. serve Serve the site locally.

Basically it’s a collection of configurable tasks which are launched via inv or invoke command:

# using jtasks: $ invoke serve -bd # common way: $ bundle exec jekyll serve -d ./dist/ --host 0.0.0.0 --port 5000 --drafts

--destination , --host and --port are configured as a global variables at the settings part of the script:

# === Settings === # Project directories _site_dest = "./dist/" # Dir where Jekyll will generate site _posts_dest = "./_posts/" # Dir with posts _drafts_dest = "./_drafts/" # Dir with drafts # Global options _hostname = '0.0.0.0' # Listen given hostname _port = '5000' # Listen given port _bundle_exec = False # Run commands with Bundler _fpolling = False # Force watch to use polling _incremental = False # Enable incremental build (Jekyll 3) # Post settings _post_ext = '.md' # Post files extension # Notification settings (your sitemap location) _sitemap_url = 'http://www.example.com/sitemap.xml'

This allows flexible setup of jtasks on per-project basis eliminating the need to explicitly specify your Jekyll project’s constant values every time.

Jtasks also contains help documentation for each task:

$ inv --help serve Docstring: Serve the site locally. jekyll serve [options] Options: -b, --bundle-exec Run Jekyll development server via Bundler. -d, --drafts Process and render draft posts. -f, --force-polling Force watch to use polling. -i, --incremental-build Rebuild only posts and pages that have changed.

For more details and usage examples check project’s page at GitHub.

Previous post: Jekyll development environment via Vagrant and PuPHPet

Next post: A better PostgreSQL CLI experience with few psqlrc tweaks