Nanoc needs file paths to be known before compilation starts
In Nanoc, routing strictly happens before compilation. This prevents an output filename from depending on the compiled content.
Example: Fingerprinting
This is limiting particularly for stylesheet fingerprinting. Ideally, each stylesheet contains the hash of its own compiled content in the filename, but Nanoc is only able to calculate a hash from the raw, uncompiled input.
As an example, here is how the Nanoc web site web site handles fingerprinting for stylesheets:
compile '/assets/style/*' do
filter :sass, syntax: :scss
write item.identifier.without_ext + '-' + fingerprint('/assets/style/*') + '.css'
end
def fingerprint(pattern)
contents = @items.find_all(pattern).map do |i|
i.binary? ? File.read(i[:filename]) : i.raw_content
end
Digest::SHA1.hexdigest(contents.join(''))[0..15]
end
The implementation of #fingerprint
looks icky, but there is a bigger issue.
If multiple stylesheets exist (e.g. /assets
Causes
For each item, Nanoc runs several outdatedness rules, which determine whether or not the item is outdated and thus needs to be recompiled. These outdatedness rules answer questions such as these:
- Was the content modified?
- Were the attributes modified?
- Did the routing rule(s) change for this item?
- Does the corresponding file in the output directory exist?
If none of these outdatedness rules respond with “yes,” the item is not considered to be outdated, and will not be recompiled.
The last mentioned outdatedness rule in the list above is of interest: if the corresponding output file does not exist, Nanoc will consider the item as outdated, and compile it.
This is why Nanoc needs to know the file path before compiling the item.
Workaround
A dependency-querying API would help for generating fingerprints that are taken from only the necessary items. In the stylesheet fingerprinting example above, the fingerprint(glob)
call would become fingerprint(item)
, and @items.find_all(pattern)
would become something like item.dependencies
.
Such a dependency-querying API wouldn’t solve the underlying problem of not being able to generate a fingerprint from the compiled content, however.
Resolution
To do: Probably solvable if Nanoc uses an internal output databases that relies on item identifiers (or arbitrarily-assigned UUIDs) rather than paths. CoW would then help with reducing filesystem usage.
References
GitHub. “Cache Fingerprinting Doesn’t Take Account of Change to Non-Partial · Issue #251 · nanoc/nanoc.ws.” Accessed January 12, 2021. https://github.com/nanoc/nanoc.ws/issues/251.