DEV Community

Cover image for How Jekyll Works
Saran Siriphantnon
Saran Siriphantnon

Posted on

How Jekyll Works

NOTE: This post is a more concise version of the much longer version on my blog

Jekyll, the static site generator, although it is the older technology, only consists of about 6800 lines while can achieve many things: Theme, Layout, Markdown, Plugins, Live-Reload, and more.

Ever wonder how does it works internally? I hope what's am about to write can give you some ideas.

When serving the blog ($ jekyll serve), the internal calls look like this:

Jekyll Overview

In its heart, it's the Site class and its #new() and #process() method.

#new()

This loads plugins:

  • generators the plugins that receive the site information and generates additional content such as atom, sitemap.xml
  • converters the plugins that receive the site and contents (pages/posts you wrote and what generated from the generators)

The loading mechanism is especially interesting. Any plugin must inherit from Jekyll::Generator or Jekyll::Converter, so we can load them by tracking their descendants:

def instantiate_subclasses(klass)
  klass.descendants.select { |c| !safe || c.safe }.tap do |result|
    result.sort!
    result.map! { |c| c.new(config) }
  end
end
Enter fullscreen mode Exit fullscreen mode

The loading code:

self.converters = instantiate_subclasses(Jekyll::Converter)
self.generators = instantiate_subclasses(Jekyll::Generator)
Enter fullscreen mode Exit fullscreen mode

#process()

The code itself is very clean:

def process
  return profiler.profile_process if config["profile"]

  reset
  read
  generate
  render
  cleanup
  write
end
Enter fullscreen mode Exit fullscreen mode
  • reset resets site state into empty states (for example, site.pages = [])
  • read reads site and theme contents into site.pages, site.posts, site.static_files
  • generate uses loaded generators plugins to generate additional contents as mentioned
  • render renders contents using Liquid template, converters (such as Markdown converter), and put into layouts (layout is Liquid template that renders content variable)
  • cleanup removes obsolete files by comparing new set of generated files versus the current generated files
  • write writes outputs from render into the actual filesystem

Watching for File Changes

It uses listen gem underneath, any file changes will trigger the #new and #process steps again (unless incremental build is enabled) then notify the browser via LiveReload websocket communication.

The LiveReload.js on the pages got injected when serving files by manipulating <header> through custom WEBrick handler.

Code Worth Stealing

There are many good piece of code worth stealing:

Conclusion

The Jekyll code itself is very clean (though I would say it is more engineered than clean). I wrote more about it including caching, profiling, security, and more on my blog.

Hope you like this article. If you spot any mistakes or want to share feedback, please feel free to comment or DM me :)

Top comments (0)