blogs by Gio

Gio Flavoured Markdown

  • Posted in ๐Ÿ‘จโ€๐Ÿ’ป dev

“How can I show someone how my blog articles actually render?”

It sounds like it should be super easy, but it turns out it really isn’t. I write in Markdown (and attach the source to all my posts if you’re interested) that then gets rendered as HTML on-demand by Pelican. (More on this on the thanks page.) But that means there’s no quick way to demo what any given input will render as: it has to run through the markdown processor every time. Markdown is a fairly standard language, but I have a number of extensions I use — some of which I wrote myself — which means to get an authoritative rendering, it has to actually render.

But I want to be able to demo the full rendered output after all the various markdown extensions process. I want a nice simple way to render snippets and show people how that works, like a live editor does. The CSS is already portable by default, but the markdown rendering is done with python-markdown, which has to run server-side somewhere, so that’s much less portable.

So I spent two evenings and wrote up, which does exactly that. You can view the live source code here if you want to follow along.


Glitch is a fantastic service for running all kinds of websites. They have an editor for simple static websites (they specifically advertise “Glitch in Bio” as a replacement for something like carrd, for instance) but they’ll also host more complex websites like Node and React that require server-side processing.

It’s pretty buried in their documentation, but Glitch can be convinced to run Flask, which is a Python webserver. That’s perfect, because my rendering code is all in Python, so it and Flask can understand each other. That’s just enough to put together something approaching a live editor.

I’m trying to make as thin a wrapper as possible for this, which means no copy-pasting code from my local configuration to the app. The logic needs to be super simple. It is, essentially:

  • Set up the requirements for vanilla flask and python-markdown
  • Get the latest version of my peliplugins and mdexts repos, which contain the custom logic for my pelican plugins and markdown extensions
  • Run a flask server that does two things
    • Respond to requests on /render by parsing the markdown code passed, rendering it into HTML, and returning that rendered HTML. (The main logic)
    • Sets up a page with a code editor on the left for code input and an iFrame on the right that’ll contain the rendered code

There is a file I have to synchronize from my local (private) repo if I need to change the configuration, but that’s it.

That iframe business might sound a bit fishy. I should probably be doing something like sending a fetch request to the /render endpoint and updating an iframe’s srcdoc with the response. Instead, all I’m doing is

function updateiframe() {
  const value = view.state.doc.toString();
  const uri_component =
  try {
    iframe.setAttribute("src", "/render?q=" + uri_component);
  } catch {}

I’m only doing this because it’s super-simple reused logic from another project that had to deal with CORS. CORS shouldn’t be an issue here, but this works well enough.

The only tricky thing is that there’s a hard limit on how long the encoded query argument can be in the URL, which is why I’m compressing it with pieroxy / lz-string in the browser and decompressing with eduardtomasek / lz-string-python in Flask. The first time around I tried using marcel-dancak / lz-string-python but it appears to be unapologetically broken. Oh well.

The editor formats the output like an article by templating it like a very simple article and loading the css directly from the blog’s main production link.

What I’m not doing is actually using Pelican for this process. It’s a good static site generator, but it’s totally superfluous for this. I just had to move the pelican import to register() so I could import the file without issue. (I was also bamboozled the first time around because I was using a walrus operator, but it turns out Glitch only supports Python 3.7, so I had to rewrite that.) In you can see I also have a few dummy objects I use so I can do things like call pelican_init on a pelican extension and have it properly update the settings object even without a real pelican installation.

x This is especially useful for these fun little widgets, for instance

The main logic, meanwhile, outsources as much as possible to the various dependencies it pulls in. Again, this is in order to make sure the editor doesn’t have to be updated along with the main blog code; it needs to keep itself working. python-markdown handles the main logic of markdown rendering, with extensions pulled in from other dependencies and repos. Essentially, I’ve scooped the guts of the logic out and I’ve put it back together very generically and with a very, very thin wrapper.

Originally I just had a simple <textarea> as the left-hand side’s editor, but I decided to polish it up and use Codemirror, which is slightly harder to interface with for something this simple but does provide some nice QOL editing features that turned out to be worth it.

Again on the polish side, I copied over some of my markdown test cases as text files and added quick templating buttons to populate the live editor with that code.

And that’s the long and short of it so far! I may keep tinkering with it but for now you can mess around with if you’re interested. I may end up using it myself for a few things.

Howdy! If you found my writing worthwhile, the best thing you can do to support me is to share an article you found interesting somewhere you think people will appreciate it. Thanks as always for reading!