Nanoc Project Structure

In the previous part of the series we created a simple hello world application and fixed problems with the encoding. This part guides you through the nanoc project structure and gives you better understanding how the web site is linked together.

There are multiple files and folders in the project structure.

|- content/
|- layouts/
|- lib/
|- output/
|- tmp/
|- nanoc.yaml (config.yaml)
|- crash.log
|- Rules
content/
contains uncompiled data for your web site
layouts/
all your templates are placed here
lib/
helper functions, extensions and all your custom ruby code
output/
compiled web site prepared for deploying to server
tmp/
temporary files used for speeding up the compilation
nanoc.yaml
site configuration, in the older versions this file is called config.yaml
crash.log
if your compilation fails the error is logged in this file
Rules
contains a set of rules how to treat your content files

Let’s take a closer look to the important items in the hierarchy.

Rules

This file is the most essential file in the nanoc generator. Rules are used for two different important purposes - compilation and routing. To be technically precise there is a preprocessing before compilation. It can be used for advanced techniques like pagination but we are going to skip this process to keep it simple.

Compilation

Compilation determines how specified files should be treated when compiled by nanoc. You can set filters and assign layouts.

Filters are used for content transformation. You can chain multiple filters together. Typical example is to compile your pages written in markdown with the kramdown filter.

compile 'posts/*' do
    filter :kramdown
end

In this example all the files in the posts directory are compiled with the kramdown filter.

You can use advanced code in the compile body. For example you can compile your files based on extension.

compile '*' do
    if item.binary?
        # don’t filter binary items
    else
        case item[:extension]
            when 'md'
                filter :kramdown
                layout 'default'
            when 'erb'
                filter :erb
                layout 'default'
        end
    end
end

No filter is set for binary items. Items with *.md extension are compiled with kramdown filter and items with *.erb extension are treated as erb files.

The layout property is used for choosing proper template. Templates are stored in the layout folder and this is how they are assigned to items from the content folder. You can use special template for all your blog posts and default template for normal pages. Next example shows you how to do it.

compile 'posts/*'
    layout: 'post'
end

compile '*'
    if item.binary?
        # don’t filter binary items
    else
        layout: 'default'
    end
end

Keep in mind that you should start with the most specific rules. Rules ordering matters. If you put general rule for ‘*’ to the top of your file all other rules are skipped.

compile '*' do 
    ...
end

compile 'post/**' do 
    // this rule won't be applied because it is 
    // placed in this file after more general one
end

Filters can be also very useful for binary files and your resources. Imagine that you can create thumbnails from your images for your custom gallery. Or you want to write your CSS with LESS and then use minification. All these things are possible with nanoc.

Routing

The second important part of the Rules file is routing. These rules are used to determine the physical representation of the output of compiled content. In other words it says where the file would be placed on your web server.

As with the compilation rules routing ordering also matters so you should keep the general ones at the bottom.

Routing can be used for ignoring output from specific folders. Let’s say we have a draft folder. If you don’t set the route body the output is ignored.

route 'posts/drafts/*' do 
end

Another usage of routing is the way to create cleaner URLs for non binary items.

route '*' do
    if item.binary?
        # Write item with identifier /foo/ to /foo.ext
        item.identifier.chop + '.' + item[:extension]
    else
        # Write item with identifier /foo/ to /foo/index.html
        item.identifier + 'index.html'
    end
end

Layout

We already discussed how the layout files are assigned with Rules file. The file with the assigned name (without extension) must exist in the layout folder. Layout file is a HTML template with special tag <%= yield %>. After compilation the tag is replaced by current content.

<html>
<head>
    <title>Hello World</title>
</head>
<body>
    <%= yield %>
</body>
</html>

You can create partial views. They can be nested together. This feature is very useful especially when you have a global view and few special nested views like gallery, post or project view.

<% render "default" do %>
    <h2>Other view</h2>
    <div>
        <%= yield %>
    </div>        
<% end %>

In the example above the view is placed in the file called default.erb instead of the yield and current compiled content is placed instead of the yield in this partial view.

Configuration

The global configuration of your web site is located in the nanoc.yaml or config.yaml in older version of nanoc. In our default hello world application it contains information about supported text extensions, automatic watcher and some other global settings.

You can change output directory of your site by modifying the output_dir: output to another value.

It is not necessary to change those settings for creating basic applications but you can add your own.

title: 'My Blog'
author_name: 'Jakub Chodounsky'
author_uri: 'https://www.chodounsky.com'
base_url: 'https://www.chodounsky.com'

Helpers and Custom Functions

Helpers are pieces of ruby code that you can use in your layouts and items. Location for your custom helpers is in the lib folder.

By default there is a file called default.rb. Nanoc comes with a set of integrated helpers but they need to be activated before using. This can be done very easily.

include Nanoc3::Helpers::Blogging
include Nanoc3::Helpers::Tagging
include Nanoc3::Helpers::Rendering
include Nanoc3::Helpers::LinkTo

If you want to write custom code you can do it in the default.rb or you can create new files and link modules together in the default.rb.

Conclusion

After reading this article you don’t have to search anymore where to put your content and where to modify necessary files. Now you should have a good starting point for creating custom web site with nanoc.

In the next article we will focus on the blogging features and how nanoc can be an effective tool that won’t stand in your way.


Would you like to get the most interesting content about programming every Monday?
Sign up to Programming Digest and stay up to date!