Skip to content

Obsidian Enveloppe: Discussion on Zensical migration path from Material for MkDocs

Upstream publish: Zensical migration path (from MkDocs, Material for MkDocs) [preview!] · Enveloppe · Discussion #420

Follow-up on https://github.com/Enveloppe/obsidian-enveloppe/issues/419#issuecomment-4852161195 @Mara-Li

Oh, I would like to try with Zensical ! Do you have any issue?

I have a bunch of Mkdocs plugin and not sure if I should migrate them or wait for a full migration guide (maybe I could use Claude for that?)

Notably the callout, some css styles, etc.


That's a tough question as of now (Zensical v0.0.46), because:

Does it Zensical work out-of-the-box with your MkDocs repository?

Yes, you can even keep the mkdocs.yml exactly as it is.

Do you have issues?

Yes, there are tons of caveats right now when it comes to details.

Main migration steps

Without going into details, give it a try now, even with version 0.x, if you

  • don't need the blog feature
  • don't rely on taxonomy (tag pages, category pages) browsing
  • don't want to heavily customize something (like own theme or hacking the navigation)

My own testing with Enveloppe and Zensical is done in https://github.com/codeshell/docs

I started by adding the https://github.com/Enveloppe/mkdocs template, see https://github.com/codeshell/docs/commit/c4b6737e1626623fe39741d39ed398f5be80d7dc

Then migrated the config to the new zensical.toml in https://github.com/codeshell/docs/commit/60f126aaf8698a797b8537cf21d6b30ba1450130 (for now, this is optional, but in my opinion there is no point in keeping the legacy config file unless you are building both, a MkDocs page and a Zensical page for testing, both from the same repository)

After that I threw out all dependencies with https://github.com/codeshell/docs/commit/f32a6d646eb666a2d7ab0bb9d428db14f3d2d186 because Zensical is pre-compiled and doesn't use them.

At that point, you will have a modern looking site resembling the beloved Material for MkDocs up and running.

See https://codeshell.on.state.ovh/ as example.

Issues

Disclaimer: Keep in mind that Zensical is not released as finished product yet. Things will break and change.

Personal comment

There is one conceptual flaw I expect to hit back on them when they release version 1:

  • Goal 1: Zensical is built to overcome shortcomings experienced with MkDocs (the most obvious result being the move from Python to Rust).
  • Goal 2: At the same time, the devs want to maintain maximum compatibility with MkDocs (the most obvious result being throwing Python modules on top of the Rust app again).

Both goals cannot be achieved at the same time and I really hope they change this (by making the migration from MkDocs to Zensical a separate, on-time step) before the final release.

Back to issues

Most important things to consider with the current state:

Markdown parser

Zensical currently uses Python-Markdown (because MkDocs used it too, see goal 2). However, Python-Markdown was never meant to be used as parser for documents using modern implementations (flavours) of the Markdown syntax. It's a dead end.

I'm glad that the devs already gave up on that one and will replace it with CommonMark in one of the next releases.

That being said, don't bother with Markdown syntax details as of now. Wait for CommonMark and then migrate your documents from the non-sensical Python-Markdown hacks (looking at you, "admonitions") to commonly used Markdown.

I expect Obsidian and Github callouts to work out of the box with Zensical after that move

Templating

Zensical currently uses MiniJinja (because MkDocs used Jinja2, see goal2), which is a light port of Jinja2 to Rust.

As of now, I do not know of a public statement to revise this decision. But templating is a crucial aspect of a SSG, therefore I really don't understand why you would bind yourself to a solution that is not even fully supported in your chosen programming language.

Your basic templates from MkDocs will work, but more sophisticated features will break. One example from the Enveloppe template: There is no implementation for append() on lists in MiniJinja like used with `valid_pages.append(pg)'.

I found a workaround for that one but overall, it's a PITA (read: it does not feel good "fixing" things in templates that should just work out of the box with full fledged templating engine).

https://github.com/codeshell/docs/blob/e12d0034f89288c8da94a7a5aa7efeb7f5e0f058/overrides/partials/post-list-min.html#L46

If you wonder, you cannot add a custom append() function (as you would normally do to keep your Jinja2 template as is), because you cannot "hook" into MiniJinja with Zensical.

Speaking of "hooks", Enveloppe makes heavy use of them to add filters like time and date formatting.

Zensical added a new feature for Macros recently which supposedly adds full Python Jinja2 support back to templates. Or so I thought.

I even converted all Enveloppe hooks into the dedicated https://github.com/codeshell/docs/tree/main/python/tmw-macros python module needed to use that macros feature.

Well, as it turns out, it does not work on the template files in overrides. Instead, you could now enable "macros" in your Markdown frontmatter and add the Jinja2 template code directly to your Markdown note (no kidding, like writing it in the note text in Obsidian.)

As a result, your Markdown note is first rendered with Jinja2 in Python for in-note-template-syntax, then rendered with Pyhon-Markdown in Rust, then templated and rendered with your normal templates with MiniJinja in Rust.

If writing SSG template code directly into notes did not put you off, take note of the fact that the "render context!" that is made available to Jinja2 vs MiniJinja is unrelated. Example you might be able to access {{ pages }} in only one while {{ nav }} might only be available in the other.

My takeaway, I recompiled Zensical with fixing the MiniJinja context to allow me to build index pages with a list of page links / tags whatever rather than hacking template code into my docs/notes. See https://github.com/codeshell/zensical/releases/tag/v0.0.46-patch-1

Example: https://codeshell.on.state.ovh/blog/

However, that does not solve the proplem of getting the custom Enveloppe filters to work directly in the overrides/templates where they should be.

https://github.com/codeshell/docs/blob/main/overrides/partials/post-list-min.html is an example how far I could get in migrating something like the https://github.com/Enveloppe/mkdocs/blob/main/overrides/partials/post-list.html

That's it for now.