Nikola Internals

Nikola Internals

When try­ing to guide some­one in­to adding a fea­ture in Niko­la, it hit me that while the way it’s struc­tured makes sense to me it is far from ob­vi­ous.

So, this is a short doc­u­ment ex­plain­ing what each piece of Niko­la does and how it all fits to­geth­er.

Nikola is a Pile of Plugins

Most of Nikola is implemented as plugins using Yapsy. You can ignore that they are plugins and just think of them as regular python modules and packages with a funny little .plugin file next to them.

So, 90% of the time, what you want to do is ei­ther write a new plug­in or ex­tend an ex­ist­ing one.

There are several kinds of plugins, all implementing interfaces defined in nikola/plugin_categories.py and documented in Extending Nikola

If your plug­in has a de­pen­den­cy, please make sure it does­n’t make Niko­la throw an ex­cep­tion when the de­pen­den­cy is miss­ing. Try to fail grace­ful­ly with an in­for­ma­tive mes­sage.

Commands are plugins

When you use nikola foo you are using the plugin command/foo. Those are used to extend Nikola’s command line. Their interface is defined in the Command class. They take options and arguments and do whatever you want, so go wild.

The build command is special

The build command triggers a whole lot of things, and is the core of Nikola because it’s the one that you use to build sites. So it deserves its own section.

The Build Command

Niko­la’s goal is sim­i­lar, deep at heart, to a Make­file. Take sources, com­pile them in­to some­thing, in this case a web­site. In­stead of a Make­file, Niko­la us­es doit

Doit has the con­cept of “tasks”. The 1 minute sum­ma­ry of tasks is that they have:

actions

What the task does. For ex­am­ple, con­vert a mark­down doc­u­ment in­to HTM­L.

dependencies

If this file changes, then we need to re­do the ac­tion­s. If this con­fig­u­ra­tion op­tion changes, re­do it, etc.

targets

Files that the ac­tion gen­er­ates. No two ac­tions can have the same tar­get­s.

basename:name

Each task is iden­ti­fied by ei­ther a name or a base­name:­name pair.

So, what Nikola does, when you use the build command, is to read the configuration conf.py from the current folder, instantiate the Nikola class, and have it generate a whole list of tasks for doit to process. Then doit will decide which tasks need doing, and do them, in the right order.

The place where the tasks are generated is in Nikola.gen_tasks, which collects tasks from all the plugins inheriting BaseTask, massages them a bit, then passes them to doit.

So, if you want things to happen on build you want to create a Task plugin, or extend one of the existing ones.

Posts and Stories

Nikola has a concept of posts and stories. Both are more or less the same thing, except posts are added into RSS feeds and stories are not. All of them are in a list called “the timeline” formed by objects of class Post.

When you are creating a task that needs the list of posts and/or stories (for example, the RSS creation plugin) on task execution time, your plugin should call self.site.scan_posts() in gen_tasks to ensure the timeline is created and available in self.site.timeline. You should not modify the timeline, because it will cause consistency issues.

Your plug­in can use the time­line to gen­er­ate “stuff” (tech­ni­cal ter­m). For ex­am­ple, Niko­la comes with plug­ins that use the time­line to cre­ate a web­site (sur­prised?).

The work­flow in­clud­ed with niko­la is as fol­lows (in­com­plete!):

  1. The post is as­signed a com­pil­er based on its ex­ten­sion and the COM­PIL­ERS op­tion.

  2. The com­pil­er is ap­plied to the post da­ta and a “HTML frag­men­t” is pro­duced. That frag­ment is stored in a cache (the posts plug­in).

  3. The con­fig­ured theme has tem­plates (and a tem­plate en­gine), which are ap­plied to the post’s HTML frag­ment and meta­da­ta (the pages plug­in).

  4. The orig­i­nal sources for the post are copied to some ac­ces­si­ble place (the sources plug­in).

  5. If the post is tagged, some pages and RSS feeds for each tag are up­dat­ed (the tags plug­in).

  6. If the post is new, it’s in­clud­ed in the blog’s RSS feed (the rss plug­in).

  7. The post is added in the right place in the in­dex pages for the blog (the in­dex­es plug­in).

  8. CSS/JS/Im­ages for the theme are put in the right places (the copy­_as­sets and bun­dles plu­g­in­s).

  9. A File de­scrib­ing the whole site is cre­at­ed (the sitemap plug­in).

You can add what­ev­er you want to that list: just cre­ate a plug­in for it.

You can al­so ex­pand Niko­la’s ca­pa­bil­i­ties at sev­er­al points:

compilers

Nikola supports a variety of markups. If you want to add another one, you need to create a Compiler plugin.

templates

Nikola’s themes can use Jinja2 or Mako templates. If you prefer another template system, you have to create a TemplateSystem plugin.

themes

To change how the gen­er­at­ed site look­s, you can cre­ate cus­tom themes.

And of course, you can al­so re­place or ex­tend each of the ex­ist­ing plug­ins.

Nikola Architecture

https://getnikola.com/images/architecture.thumbnail.png