Biggest problem of mdBook is the lack of the good PDF and ePub export[1]. This is why Quarto[2] (based on pandoc) is a better choice if you need both online and offline rendered documentation/text. And Typst (or LaTeX for more conservative folks) for the offline documentation/articles/books.
I have maintained a pandoc filter in Haskell for a while. Pandoc is written in Haskell, and so takes a similar approach: JSON API for arbitrary languages, but with a library for trivially parsing that JSON back into the same Haskell datatype that Pandoc uses under the hood.
When you sit down to write the filter for the first time, it’s amazing. You’re using a typed IR that’s well documented, a language that catches you when you’re making mistakes, etc. You have to do very little boring grunt work and focus only on what the filter needs to do.
Over time, the filter became feature complete, so I didn’t want to have to touch it anymore, but the library for parsing JSON releases a new version for every new feature in the AST, and the parsing function checks that the version your filter was compiled with is at least as new as the pandoc that produced the JSON. It has to, because if the pandoc is newer, your older filter won’t know how to parse some of the nodes.
My filter is feature complete, and shouldn’t need to look at those nodes or their new fields: needing to upgrade is just toil. But over time, pandoc releases new versions, and I’d need to recompile the filter to build the new version. At those points, I also found myself having to deal with library, build tool, OS, or compiler upgrades, all to recompile a filter that should need to be.
Eventually I switched to Pandoc lua filters, which eliminated the toil while also being platform agnostic (and not requiring any sort of notarization or executable quarantine on enterprise systems) at the expense of having to tolerate Lua the language. Now, new versions of Pandoc don’t require me to boop a version number in my filter. If that wasn’t an option, for any future filters I write, I’d write my own JSON parser that only parses as much of the JSON as I needed, leaving the rest untouched—that way it wouldn’t matter if new changes came along. I could even tolerate backwards incompatible changes as long as they didn’t alter the contract of the narrow focus of that one filter!
There are of course other ways to deal with problems like these (protocol buffers, JSON parsing with an option to throw away unrecognized JSON, etc. etc.)
I have not looked at how mdBook plugins handle this. But if I were writing such a plugin, it’s the first thing I’d look at, and be sure to program around.
I already think that markdown is barely ok for writing documentation, and the experience of plugins in mdBook is why I tell people not to use it (edit: it = mdBook). The base flavor of mdBook is minimalistic. Maybe that’s a good thing, that you’re given a minimalistic markdown as a starting point? But if it’s minimalistic, then it’s certainly missing some things that I’d want to use in the documentation I write, and the experience of using plugins is, well, not very good.
My current recommendations are MkDocs (material theme), Jekyll, and Docusaurus. Hugo gets a qualified recommendation, and I only recommend mdBook for people who are doing Rust stuff.
What is missing from markdown?
mdbook also uses in some parts the GH flavored one, so you can create notes [1] and similar. On top of that, you can add support for Mermaid.
Personally, I don't think you need more than that for 90% of the documentation, but I'm happy to hear more about your use case.
[1] https://github.com/rust-lang/mdBook/issues/815
[2] https://quarto.org/
When you sit down to write the filter for the first time, it’s amazing. You’re using a typed IR that’s well documented, a language that catches you when you’re making mistakes, etc. You have to do very little boring grunt work and focus only on what the filter needs to do.
Over time, the filter became feature complete, so I didn’t want to have to touch it anymore, but the library for parsing JSON releases a new version for every new feature in the AST, and the parsing function checks that the version your filter was compiled with is at least as new as the pandoc that produced the JSON. It has to, because if the pandoc is newer, your older filter won’t know how to parse some of the nodes.
My filter is feature complete, and shouldn’t need to look at those nodes or their new fields: needing to upgrade is just toil. But over time, pandoc releases new versions, and I’d need to recompile the filter to build the new version. At those points, I also found myself having to deal with library, build tool, OS, or compiler upgrades, all to recompile a filter that should need to be.
Eventually I switched to Pandoc lua filters, which eliminated the toil while also being platform agnostic (and not requiring any sort of notarization or executable quarantine on enterprise systems) at the expense of having to tolerate Lua the language. Now, new versions of Pandoc don’t require me to boop a version number in my filter. If that wasn’t an option, for any future filters I write, I’d write my own JSON parser that only parses as much of the JSON as I needed, leaving the rest untouched—that way it wouldn’t matter if new changes came along. I could even tolerate backwards incompatible changes as long as they didn’t alter the contract of the narrow focus of that one filter!
There are of course other ways to deal with problems like these (protocol buffers, JSON parsing with an option to throw away unrecognized JSON, etc. etc.)
I have not looked at how mdBook plugins handle this. But if I were writing such a plugin, it’s the first thing I’d look at, and be sure to program around.
My current recommendations are MkDocs (material theme), Jekyll, and Docusaurus. Hugo gets a qualified recommendation, and I only recommend mdBook for people who are doing Rust stuff.
Personally, I don't think you need more than that for 90% of the documentation, but I'm happy to hear more about your use case.
[1]: https://github.com/orgs/community/discussions/16925