h1. Jekyll
Jekyll is a simple, blog aware, static site generator. It takes a template
directory (representing the raw form of a website), runs it through Textile or
Markdown and Liquid converters, and spits out a complete, static website
suitable for serving with Apache or your favorite web server. Visit
"http://tom.preston-werner.com":http://tom.preston-werner.com to see an
example of a Jekyll generated blog.
To understand how this all works, open up my
"TPW":http://github.com/mojombo/tpw repo in a new browser window. I'll be
referencing the code there.
Take a look at
"index.html":http://github.com/mojombo/tpw/tree/master/index.html. This file
represents the homepage of the site. At the top of the file is a chunk of YAML
that contains metadata about the file. This data tells Jekyll what layout to
give the file, what the page's title should be, etc. In this case, I specify
that the "default" template should be used. You can find the layout files in
the "_layouts":http://github.com/mojombo/tpw/tree/master/_layouts directory.
If you open
"default.html":http://github.com/mojombo/tpw/tree/master/_layouts/default.html
you can see that the homepage is constructed by wrapping index.html with this
layout.
You'll also notice Liquid templating code in these files.
"Liquid":http://www.liquidmarkup.org/ is a simple, extensible templating
language that makes it easy to embed data in your templates. For my homepage I
wanted to have a list of all my blog posts. Jekyll hands me a Hash containing
various data about my site. A reverse chronological list of all my blog posts
can be found in site.posts
. Each post, in turn, contains various
fields such as title
and date
.
Jekyll gets the list of blog posts by parsing the files in any
"_posts":http://github.com/mojombo/tpw/tree/master/_posts directory found in
subdirectories below the root.
Each post's filename contains (by default) the publishing date and slug (what shows up in the
URL) that the final HTML file should have. Open up the file corresponding to a
blog post:
"2008-11-17-blogging-like-a-hacker.textile":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile.
GitHub renders textile files by default, so to better understand the file,
click on the
"raw":http://github.com/mojombo/tpw/tree/master/_posts/2008-11-17-blogging-like-a-hacker.textile?raw=true
view to see the original file. Here I've specified the post
layout. If you look at that file you'll see an example of a nested layout.
Layouts can contain other layouts allowing you a great deal of flexibility in
how pages are assembled. In my case I use a nested layout in order to show
related posts for each blog entry. The YAML also specifies the post's title
which is then embedded in the post's body via Liquid.
Posts are handled in a special way by Jekyll. The date you specify in the
filename is used to construct the URL in the generated site. The example post,
for instance, ends up at
http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html
.
Categories for posts are derived from the directory structure the posts were
found within. A post that appears in the directory foo/bar/_posts is placed in
the categories 'foo' and 'bar'. By selecting posts from particular categories
in your Liquid templates, you will be able to host multiple blogs within a
site.
Files that do not reside in directories prefixed with an underscore are
mirrored into a corresponding directory structure in the generated site. If a
file does not have a YAML preface, it is not run through the Liquid
interpreter. Binary files are copied over unmodified.
Jekyll is still a very young project. I've only developed the exact
functionality that I've needed. As time goes on I'd like to see the project
mature and support additional features. If you end up using Jekyll for your
own blog, drop me a line and let me know what you'd like to see in future
versions. Better yet, fork the project over at GitHub and hack in the features
yourself!
h2. Example Proto-Site
My own personal site/blog is generated with Jekyll.
The proto-site repo
("http://github.com/mojombo/tpw":http://github.com/mojombo/tpw) is converted
into the actual site
("http://tom.preston-werner.com/":http://tom.preston-werner.com)
h2. Install
The best way to install Jekyll is via RubyGems:
$ sudo gem install mojombo-jekyll -s http://gems.github.com/
Jekyll requires the gems `directory_watcher`, `liquid`, `open4`,
and `maruku` (for markdown support). These are automatically
installed by the gem install command.
Maruku comes with optional support for LaTeX to PNG rendering via
"blahtex":http://gva.noekeon.org/blahtexml/ (Version 0.6) which must be in
your $PATH along with `dvips`.
(NOTE: the version of maruku I am using is `remi-maruku` on GitHub as it
does not assume a fixed location for `dvips`.)
h2. Run
$ cd /path/to/proto/site
$ jekyll
This will generate the site and place it in /path/to/proto/site/_site. If
you'd like the generated site placed somewhere else:
$ jekyll /path/to/place/generated/site
And if you don't want to be in the proto site root to run Jekyll:
$ jekyll /path/to/proto/site /path/to/place/generated/site
h2. Run Options
There is an autobuild feature that will regenerate your site if any of the
files change. The autobuild feature can be used on any of the invocations:
$ jekyll --auto
By default, the "related posts" functionality will produce crappy results.
In order to get high quality results with a true LSI algorithm, you must
enable it (it may take some time to run if you have many posts):
$ jekyll --lsi
For static code highlighting, you can install Pygments (see below) and then
use that to make your code blocks look pretty. To activate Pygments support
during the conversion:
$ jekyll --pygments
By default, Jekyll uses "Maruku":http://maruku.rubyforge.org (pure Ruby) for
Markdown support. If you'd like to use RDiscount (faster, but requires
compilation), you must install it (gem install rdiscount) and then you can
have it used instead:
$ jekyll --rdiscount
When previewing complex sites locally, simply opening the site in a web
browser (using file://) can cause problems with links that are relative to
the site root (e.g., "/stylesheets/style.css"). To get around this, Jekyll
can launch a simple WEBrick server (works well in conjunction with --auto).
Default port is 4000:
$ jekyll --server [PORT]
By default, the permalink for each post begins with its date in 'YYYY/MM/DD'
format. If you do not wish to have the date appear in the URL of each post,
you can change the permalink style to 'none' so that only the 'slug' part of
the filename is used. For example, with the permalink style set to 'none' the
file '2009-01-01-happy-new-year.markdown' will have a permalink like
'http://yoursite.com/happy-new-year.html'. The date of the post will still be
read from the filename (and is required!) to be used elsewhere in Jekyll.
Example usage:
$ jekyll --permalink none
h2. Data
Jekyll traverses your site looking for files to process. Any files with YAML
front matter (see below) are subject to processing. For each of these files,
Jekyll makes a variety of data available to the pages via the Liquid
templating system. The following is a reference of the available data.
h3. Global
site
Sitewide information.
page
For Posts, this is the union of the data in the YAML front matter and the
computed data (such as URL and date). For regular pages, this is just the
YAML front matter.
content
In layout files, this contains the content of the subview(s). In Posts or
Pages, this is undefined.
h3. Site
site.time
The current Time (when you run the jekyll command).
site.posts
A reverse chronological list of all Posts.
site.related_posts
If the page being processed is a Post, this contains a list of up to ten
related Posts. By default, these are low quality but fast to compute. For
high quality but slow to compute results, run the jekyll command with the
--lsi (latent semantic indexing) option.
site.categories.CATEGORY
The list of all Posts in category CATEGORY.
h3. Post
post.title
The title of the Post.
post.url
The URL of the Post without the domain.
e.g. /2008/12/14/my-post.html
post.date
The Date assigned to the Post.
post.id
An identifier unique to the Post (useful in RSS feeds).
e.g. /2008/12/14/my-post
post.categories
The list of categories to which this post belongs. Categories are
derived from the directory structure above the _posts directory. For
example, a post at /work/code/_posts/2008-12-24-closures.textile
would have this field set to ['work', 'code'].
post.topics
The list of topics for this Post. Topics are derived from the directory
structure beneath the _posts directory. For example, a post at
/_posts/music/metal/2008-12-24-metalocalypse.textile would have this field
set to ['music', 'metal'].
post.content
The content of the Post.
h2. YAML Front Matter
Any files that contain a YAML front matter block will be processed by Jekyll
as special files. The front matter must be the first thing in the file and
takes the form of:
--- layout: post title: Blogging Like a Hacker ---Between the triple-dashed lines, you can set predefined variables (see below for a reference) or custom data of your own. h3. Predefined Global Variables layout If set, this specifies the layout file to use. Use the layout file name without file extension. Layout files must be placed in the
_layouts
directory.
h3. Predefined Post Variables
permalink
If you need your processed URLs to be something other than the default
/year/month/day/title.html then you can set this variable and it will
be used as the final URL.
h3. Custom Variables
Any variables in the front matter that are not predefined are mixed into the
data that is sent to the Liquid templating engine during the conversion. For
instance, if you set a title
, you can use that in your layout to
set the page title:
h2. Filters, Tags, and Blocks In addition to the built-in Liquid filters, tags, and blocks, Jekyll provides some additional items that you can use in your site. h3. Date to XML Schema (Filter) Convert a Time into XML Schema format. {{ site.time | date_to_xmlschema }} becomes 2008-11-17T13:07:54-08:00 h3. XML Escape (Filter) Escape some text for use in XML. {{ post.content | xml_escape }} h3. Number of Words (Filter) Count the number of words in some text. {{ post.content | number_of_words }} becomes 1337 h3. Array to Sentence String Convert an array into a sentence. {{ page.tags | array_to_sentence_string }} becomes foo, bar, and baz h3. Include (Tag) If you have small page fragments that you wish to include in multiple places on your site, you can use the{{ page.title }}
include
tag.
{% include sig.textile %}Jekyll expects all include files to be placed in an
_includes
directory at the root of your source dir. So this will embed the contents of
/path/to/proto/site/_includes/sig.textile
into the calling file.
h3. Code Highlighting (Block)
Jekyll has built in support for syntax highlighting of over "100
languages":http://pygments.org/languages/ via "Pygments":http://pygments.org/.
In order to take advantage of this you'll need to have Pygments installed, and
the pygmentize binary must be in your path. When you run Jekyll, make sure you
run it with Pygments support:
$ jekyll --pygments
To denote a code block that should be highlighted:
{% highlight ruby %} def foo puts 'foo' end {% endhighlight %}The argument to
highlight
is the language identifier. To find the
appropriate identifier to use for your favorite language, look for the "short
name" on the "Lexers":http://pygments.org/docs/lexers/ page.
There is a second argument to highlight
called
linenos
that is optional. Including the linenos
argument will force the highlighted code to include line numbers. For
instance, the following code block would include line numbers next to each
line:
{% highlight ruby linenos %} def foo puts 'foo' end {% endhighlight %}In order for the highlighting to show up, you'll need to include a highlighting stylesheet. For an example stylesheet you can look at "syntax.css":http://github.com/mojombo/tpw/tree/master/css/syntax.css. These are the same styles as used by GitHub and you are free to use them for your own site. If you use linenos, you might want to include an additional CSS class definition for
lineno
in syntax.css to distinguish the line
numbers from the highlighted code.
h2. Categories
Posts are placed into categories based on the directory structure they are
found within (see above for an example). The categories can be accessed from
within a Liquid template as follows:
{% for post in site.categories.foo %}