Home |
Last modified: 18-05-2024 |
Nanoc is a Ruby application that can turn a bunch of web pages into a static site, ready to be uploaded to any web server without the complexity and lower performance of PHP and MySQL. Pages can be written in HTML, Markdown (kramdown), Textile, or Haml.
Note that Nanoc uses the term "items" instead of "pages", because a web site can contain pages, pictures, stylesheets, etc. All of those are "items".
Here's how to install Ruby and Nanoc on a Windows host:
gem update nanoc
If it fails with eg. "ERROR: While executing gem ... (Errno::EACCES) Permission denied - C:/Ruby193/bin/nanoc.bat", make sure it's not an antivirus application blocking the update.
Note: If you see strange characters, ????
After first compiling a site, Nanoc creates the following files and directories:
Source HTML pages must be located in ./content. Here's how to add a page to the site:
Nanoc created ./output/my_page/index.html. Anytime you add/edit an item, you must run "nanoc compile" to regenerate the site in ./output.
WYSIWYG HTML editors may be unhappy of this, so YMMV.
Input files are located in ./content. The sample ./content/index.html contains a bit of YAML metadata at the top:
If you'd rather keep the actual web page and the YAML metadata separate, move the YAML metadata in a file that has the same name as the HTML page but with the .yaml extension, eg. content/about.html matches content/about.yaml.
It is possible to apply multiple filters to input files. Here's an example:
compile '/docs/*' do
filter :erb #"Embedded Ruby": processes embedded Ruby within HTML pages
filter :rdiscount #processes Markdown markup into HTML
filter :rubypants #performs some cosmetics (replace -- with a long dash etc)
layout 'post' #contains some layout elements specifically for the blog part of the site
layout 'default' #contains the general layout
end
The default template that Nanoc uses to format web pages is layouts/default.html. If you open this file, you'll notice it contains a bit of Ruby embedded code such as "<title>A Brand New nanoc Site - <%= @item[:title] %></title>".
If you wish to add your own data, edit the metadata in either the input HTML or YAML file, and add some embedded Ruby code in the layout file:
... followed by this change in layouts/default.html anywhere within the BODY:
The Rules file contains instructions to process all items, such as web pages written in kramdown.
"Compilation rules determine the actions that should be executed during compilation (filtering, layouting), routing rules determine the path where the compiled files should be written to, and layouting rules determine the filter that should be used for a given layout.
A rule consists of a selector, which identifies which items the rule should be applicable to, and an action block (except for layouting rules), which contains the actions to perform.
Each item has exactly one compilation rule and one routing rule. Similarly, each layout has exactly one layouting rule. The first matching rule that is found in the rules file is used."
type: compile (filters and layouts to use), route (where the compile page will be written), layout (which layout file to use)
selector: which items or layouts this rule applies to (*, or a specific item)
instructions: code between do...end
You can write your own functions that will be run by Nanoc before compiling the pages. They should be placed in files in ./lib and be referenced in the layout page.
Nanoc comes with default helpers that you can use. Here's how to display tags instead of using one's own function:
Here's the link to the API section.
In case your WYSIWYG HTML editor doesn't like having YAML infos in the document, you can tell Nanoc to read the meta-datas from the HEAD section: In the preprocess block, parse HTML (e.g. with Nokogiri) and assign metadata from HTML meta tags to nanoc item attributes.
Here's how to install Nokogiri and use it in Nanoc:
By default, each new page will be created in its sub-directory, eg. ./output/my_page/index.html.
config.yaml:
data_sources:
# The path where items should be mounted (comparable to mount points in
# Unix-like systems). This is “/†by default, meaning that items will have
# “/†prefixed to their identifiers. If the items root were “/en/â€
# instead, an item at content/about.html would have an identifier of
# “/en/about/†instead of just “/about/â€.
items_root: /
.\tutorial\Rules
Adjust the routing rule from "item.identifier + 'index.html'" to "item.identifier.chop + '.html'" (you just need to be careful for the item with identifier /, because that one needs to be routed to /index.html still).
Alternatively, add metadata (item[:force_output_path] = "/about.html") to the item and use a routing rule that detects this rather than changing the default rule and moving your items ("content/about.txt" by default goes to "output/about/index.html", but could be changed to "content/about/index.txt" to still go to the same place under the example above.)
Yet a third solution is to use this rule:
item[:mtime] will be filled in by the filesystem data source.
You can get the children and parent of an item using the #children and #parent methods on Nanoc::Item. For nanoc, there is only one root (item with identifier “/”) and you can therefore get all pages below the root using @items.find { |i| i.identifier == '/' }.children. This way, you could also "dynamically" create second-level navigation for each page below the root.
Note that nanoc's parent / child relationships are based off of the content file structure. So, if you have, for example, a blog sructure were posts are filed under "content/blog/year/month/day/article.txt" and will never have any actual pages in year or month, your articles will be orphans.
I've previously posted some code that can be used to calculate "true relationships" (based on path, pages are given a parent that is the closest page in a higher level) and linked those below. It's structured as a nanoc helper that could be dropped into your site's lib directory: https://gist.github.com/1132866
Just edit its YAML infos, and write the relevant loop to create different sections in the home page.
... or can I just add my own pages in ./content?
Yes. If you save your pages/items/articles as normal html files, they'll work just fine. Make sure your compilation rules don't add markdown or haml filters, and you'll be set.
When creating content pages for use with nanoc, normally the top of these pages has YAML metadata like so:
---
title: How to Generate a Table of Contents
kind: article
created_at: 2012-07-13
---
[body text here in HTML, Markdown, Textile, etc.]
Komposer or other HTML editor doesn't understand this heading as it's not HTML. In general this might not be a problem unless you use a feature to reformat HTML but if it is, you can put this medadata in a new file with the same base name as the content file but an extension of .yaml.
Somewhere there was a nanoc filter that scanned an HTML5 page using nokogiri and generated a table of contents based on the type and level of tags used but I can't find it at present. Thought Denis might have written it.
Yes. In practice this can be a bit more complicated than just was this page modified since the last compile, but for the most part, yes.
Yes. Typically you'll have a template for your overall page layout and you could have custom layouts for different page types (blog post, link post, project page, about, etc.). You can even do things like embed a sub-layout within the master layout so you get the most out of code re-use.
So, it'd be easy enough to have a layout that generates a table of contents from the pages that will be generated from that layout. You could also probably do this on a page by page basis, but that seems less nanoc-y to me.
"compile '/foo/' do
filter :markdown
snapshot :without_toc
filter :add_toc
end"
"Embedded Ruby", ie. items that contain Ruby code within.