This document describes some of the internal workings of Nanoc. The audience of this document is potential contributors to Nanoc. You do not need to read or understand this document to use Nanoc.

This document is a work in progress. It’s highly incomplete, but will gradually be expanded to include more detail.

Outdatedness checking

Nanoc is a smart static-site generator; it avoids recompiling items unless necessary.

Nanoc will recompile an item if it is deemed to be outdated. The class responsible for determining whether or not an item is outdated is the OutdatednessChecker. An item is considered as outdated if any of the following conditions hold:

  • The item’s content has changed
  • The item’s attributes have changed
  • The site configuration has changed
  • The rule for this item has changed
  • Some output files for this item do not exist
  • New items or layouts have been added
  • A dependent item or layout is considered as outdated

The last condition is necessary, because an item might use data of another item or layout.

Dependency tracking

If an item uses data from another entity, Nanoc will record a dependency from the former item onto the latter entity. This type of dependency is used to infer the outdatedness of an item, and is called a soft dependency. Nanoc records a dependency in the following cases:

  • The raw content of an item or layout is accessed
  • The compiled content of an item is accessed
  • An attribute of an item or layout is accessed
  • An attribute of the site configuration is accessed
  • An item representation’s path is accessed
  • The collection of items or layouts is accessed

For example, the following code snippet will generate dependencies:

<!-- Creates a dependency on the /about.* page -->
See the <%= link_to @items['/about.*'] %> page.

<!-- Creates a dependency on every item -->
See the <%= link_to { |i| i[:title] =~ /About/ }.first %> page.

<!-- Creates a dependency on any item whose identifier matches /gallery/* -->
<% @items['/gallery/*'].each do |i| %>
  <li><%= link_to i %></li>
<% end %>

For every dependency, Nanoc remembers which of the following properties are affected by the dependency:

  • the raw content
  • the attributes, and which
  • the compiled content
  • the path

An item will only be considered as outdated due to dependencies when the dependencies’ properties match the outdatedness reason of the targets of the dependency.

For example, if an item B is marked as outdated due to an attribute title being changed, and another item A has a dependency on the title attribute of former item B, then the item A will be considered as outdated:

Outdated, because item A depends on item B’s title attribute, which has changed

If item B’s tagline attribute were changed, rather than the title attribute, then the item A would not be considered as outdated:

Not outdated, because no dependency triggers outdatedness

If the dependency were a dependency on the raw content rather than the attributes, the source of the dependency would not be considered as outdated:

Not outdated, because no dependency triggers outdatedness

Similarly, an item that depends on a certain configuration attribute will be considered as outdated when this configuration attribute has changed.

Compilation order

The order in which item representations are compiled, depends on the dependencies on compiled content between individual item representations.

Dependencies on compiled content

An item representation can depend on the compiled content of another item representation. For example, blog archive pages typically tend to contain (snippets of) the content of individual blog posts. An item representation which contains the compiled content of another item representation cannot be compiled until the compiled content of the dependent item representation is available. If this compiled content is not available and Nanoc tries to compile the item representation, then the compilation is suspended.

It is normal for the compilation for an item to be suspended. It merely indicates that the dependent item representation should be compiled first. The dependencies of an item representation are not known until Nanoc has finished compiling the item representation, and so Nanoc cannot make an accurate estimation of what a proper order of compilation is. For that reason, compilation suspensions are not only expected, but commonplace.

A dependency from one item representation onto another item representation’s compiled content is called a hard dependency, as opposed to a soft dependency, which is used in outdatedness checking. A compilation suspension always indicates a hard dependency.

Compilation selection

Once Nanoc has selected the items representations that it deems are outdated (see the Outdatedness checking section), it will compile these item reps in the best possible order. The class responsible for determining this order is the ItemRepSelector.

Nanoc will attempt to compile every outdated item representation sequentially. If an item representation cannot be compiled due to a compilation suspension, Nanoc will attempt to compile the item rep that is depended on. If the item rep that is depended on is also suspended, Nanoc will raise an error, informing the user of a dependency cycle.

The term “compile” or “recompile” does not always mean that the item will be recompiled from scratch; Nanoc keeps a cache of compiled content and will reuse cached compiled content if possible.