I’ve just done a first pass porting my blog to Zola (see corte.si for the current version - the Zola version is not up yet). The previous version of the site was rendered using a static site generator I wrote myself in Python, and it’s remarkable how similar its approach was to Zola’s. Maybe there’s some ideal solution we’re all converging on.
Overall, the experience was great, and I’m very confident Zola was the right choice. That said, there were a few hitches and places where things could be improved - or perhaps, areas where I missed the right approach.
- Many of my posts are code and image heavy, or include a self-contained web app as an asset that is linked to in the post. These have to be kept in a directory, ideally co-located with the post. There’s a tracking issue for this, so it’s already on the radar. I also have assets co-located with posts that I don’t want rendered. One simple way to handle this would be to copy all files/directories, except for those named with a leading underscore. So,
images
get copied, _render.py
does not (I often have a render step for posts).
- Many of my posts contain some HTML. A really serious issue for me is that there is no way to link to co-located assets from HTML using something like the Markdown @-path expansion. This in turn means that asset links are totally broken in the RSS feed (where absolute paths are required), unless I hard-code an absolute link for every reference in the HTML. I don’t think parsing the HTML to correct this is at all feasible, but perhaps there could be a flag on pages that does a first-pass render of the page using the template engine. So, if the frontmatter has
template=true
, we render the page content as a template, which would let me expand paths wherever needed with get_url
. We then take the rendered output, and render the markdown just as we would for an ordinary post. This would also be wonderful for more complicated posts that include a render step, for instance when generating a table of assets (here’s an example of such a post from my blog.
- I feel that the ergonomics of @-path expansion could be improved. At the moment, these are a full path from the content base, but there’s no reason why they couldn’t be just a unique suffix. So, say we have paths
/content/dirone/postone/index.md
and
/content/dirtwo/posttwo/index.md
. To link from one to two right now, we need a path
like @/dirrone/postone/index.md
. But we have a complete index of all pages, and there’s no reason not to just use a unique suffix. So @/posttwo/index.md
would link to posttwo, but @/index.md
would be an error, because it’s not a unique suffix. That way, posts can be moved around within the site without breaking all links, and you don’t have to continually type out long complete paths to cross-link between posts. As a corollary, I’d like to be able to cross-link between assets as well, to embed images from one post to another - so @/posttwo/index.md/image.png
.
Let me know if I’ve missed solutions to some of these issues. If features like the above seem like something that would fit Zola, I’d be happy to create some tracking issues and work up implementations.
Thanks for the quick response.
- I need this feature, so if no-one else is working on this, I’ll work up a PR for you to look at soon.
- You can’t use relative links in an RSS feed, unfortunately - they have to be absolute. Finding a solution to link expansion in HTML is critical - all options at the moment are bad. I’m considering either not providing a full RSS feed, or having my own post pre-processor outside Zola. To clarify what I’m proposing: the first pass template expansion would have to produce a valid Markdown post. So the embedded HTML would still be HTML by the time the Markdown renderer sees it, the post would just have been pre-expanded in Tera. This would solve the URL problem, but also be hugely useful in rendering complicated posts in-place. The shortcode syntax clash is an issue, but that can be solved by having a shortcode syntax variant that isn’t ambiguous:
{$ shortcode() $}
or similar. We can turn this on only if a page is marked as “template” so there’s no backwards-compatibility issue. I’m hoping to convince you on this, but if I can’t, I think there are alternatives that would do at a pinch: perhaps a shortcode that renders and includes an external Tera template, or the ability to specify an external command to transform content before passing it to the Markdown engine.
- This is a “nice to have” for me, so I’m not really pushing you to reconsider. But… the suffix lookup could be a binary search with
O(log(n))
lookups in a static array. I’d bet there’s no impact on performance (and probably even an improvement for small sites!). You can cast this feature differently - for instance, say that you can use @#slug
as a special syntax to link to a page IF the slug is unique, else it’s a render error. It’s just a bit tedious to type out full paths when the terminal segments are already unique.
I can’t speak for RSS feeds because they’re such an unspecified mess, but any compliant Atom reader must handle xml:base
properly, so it’s not necessary to use absolute paths everywhere:
<entry xml:base="{{ page.permalink }}">
If you’re dealing with RSS instead (which I recommend against unless you’re dealing in podcasts), adding the xml:base
attribute to the <item>
tags might help. (I mean, in XML vocabulary it should work with the obvious meaning, but RSS was kinda… only slightly XML, not properly XML.) Feed readers also sometimes try to be a bit clever about relative links, especially intra-document links, because so many people make a hash of them.
(It occurs to me now that I didn’t put xml:base in the default atom.xml template for Zola when I upstreamed that, which I should have done; but you can see the concept applied on my own site’s feeds.)
I wouldn’t trust that warning to be relevant at all. RSS is an implementation disaster, and all of those sorts of resources come from strictly no later than 2007, mostly 2002–2004 if they don’t deal with Atom. Yet even though validation tooling and mainstream documentation has stagnated completely, the state of the art in actual feed handling has progressed somewhat since then, especially in areas where Atom improved things. Atom definitely changed how some RSS parsers behaved. I haven’t tested things at all, but it wouldn’t surprise me if xml:base
worked properly in most parsers and feed readers even on RSS.
Yes, I should have emphasised this: I’m speaking specifically about RSS in the strictest sense here. I have sacrificed many, many hours to the gods of RSS while implementing feed parsers and consumers over the years, so I’m well aware of its awfulness. In this case, though, I’m migrating a blog that is older than the Atom standard, and has a surprisingly substantial number of subscribers for an existing, ancient RSS feed. My first post is basically me examining my options for coping with this - my preference would be to be able to just render RSS conservatively and correctly, without making hopeful assumptions about feed readers stepping outside the spec to correctly handle relative links. The broader issue is that Zola’s dynamic features aren’t accessible at all from HTML at the moment - filling in this gap would not just let me help myself in this case, but also make other excellent things possible.