skip to content
Adam Coates
Table of Contents

I enjoy using Quarto

I cannot deny that Quarto is a great way to create scientific documents and truly is a wonderful way to create coding notebooks including R and python, create articles and presentations and to create websites, blogs, and dashboards. I will continue to use Quarto for a lot of my everyday needs. It has served me well and continues to serve me well for creating coding notebooks (as opposed to Jupyter notebooks) and journal articles (since I can write in Markdown inside my favourite text editor, Neovim, also checkout one of my first blog posts about configuring Neovim for Quarto here: whats-the-best-notebook)). I also find Quarto to be brilliant for rendering to RevealJS presentations.

What Quarto is and what Quarto isn’t?

When sticking to what is offered by Quarto and not pushing the boundaries by adding your own customisations, then Quarto works fine. It works great. And why shouldn’t it? You specify what document type to render to, type some markdown in the Quarto document, type Quarto render, and you’re done. Executing r and python along the way and producing output within 1 single document. Basically, you can have a beautifully crafted blog/ website in under a few minutes. You don’t need to mess with configuration or adjustments, just take the stock defaults and this alone is very good. Even so, if you wanted to tweak some of the yaml options a bit to get the settings that you want, or you want to add some custom CSS rules, you can!

I cannot deny, this is amazing. It makes something as complicated and in-depth as creating a website take literally minutes and that is the point. Let me say it again, that is the point.

The point of Quarto is for low-overhead, accessible creation with a low barrier to entry. There is minimal need to learn JavaScript or LaTeX (for PDF creation). In the world of science and research we barely have enough time to do so. Quarto ultimately saves time. This is the main point and reason why I love using and will keep using it. But only for certain things.

I wanted to customise my blog beyond what Quarto offered

Quarto isn’t meant for deep customisation. You can inject custom JavaScript in a blog website for example. However, Quarto has different rendering stages and this makes it nearly impossible to preemptively inject custom JavaScript to target an HTML element using the DOM. This is because, Quarto HTML elements by ID’s can be non-intuitive and are generated at different stages of the rendering process. This means that, if I wanted to target an HTML element:

  1. I don’t exactly know what the ID will be
  2. I don’t know precisely within the render process when the element will be rendered.

As such, I would have to run Quarto render once. Inspect the HTML in the browser. Then go back to Neovim and make the edits I need for this custom JavaScript code that I want to inject in Quarto. Then re-render again Quarto render. Then check. Then repeat for mistakes and so on…

Already, you can see that this is not just a one step Quarto render, and you’re done but instead becomes a multi-step (and oftentimes) trial-and-error process. This ends up being counterproductive and takes more time than if I were to write the HTML from scratch using IDs that I know exist already and then target those IDs in JavaScript.

This brings me to the first point of why I switched to Astro from Quarto for my blog. I wanted to customise my blog beyond what Quarto offered. For some time, the customisations that I was using were working successfully, but over so many iterations of write a new blog post then the iterative render process Quarto render -> check -> repeat. I felt like writing blog posts was becoming more and more of debugging the JavaScript code than actually writing, which is basically the main purpose of a blog. Additionally, I started to fall into the trap of finding convoluted workarounds simply because certain things were just not possible in Quarto. This meant that the JavaScript code that I did have was quite embarrassingly crap to say the least. It worked for some time, but it was just not worth the hassle any longer.

Astro on the other hand, is a JavaScript web framework out of the box this means that I am able to manipulate elements that I know what they do and what they’re for without going through the iterative render-correct process. Not only this, Astro, is open to use CSS libraries, different JavaScript plugins, themes integrations and a lot more that I’m still exploring. Moreover, you can implement strict rules for the yaml of each post. For example:

const post = defineCollection({
loader: glob({ base: "./src/content/post", pattern: "**/*.{md,mdx}" }),
schema: ({ image }) =>
baseSchema.extend({
description: z.string().optional(),
coverImage: z
.object({
alt: z.string(),
src: image(),
})
.optional(),
draft: z.boolean().default(false),
ogImage: z.string().optional(),
tags: z.array(z.string()).default([]).transform(removeDupsAndLowerCase),
date: z
.string()
.or(z.date())
.optional()
.transform((val, ctx) => {
if (val) {
return new Date(val);
}
// Use file modification time as fallback
try {
const fs = require('fs');
const stats = fs.statSync(ctx.path);
return stats.mtime; // modification time
} catch {
return new Date(); // ultimate fallback to current time
}
}),
updatedDate: z
.string()
.optional()
.transform((str) => (str ? new Date(str) : undefined)),
pinned: z.boolean().default(false),
}),
});

This means that, all blog posts must abide by these yaml rules and as a result there is much more consistency in each blog post compared to Quarto. For example, Quarto has about 1000 different yaml options available meaning that there is much less consistency between blog posts. By having strict rules in Astro for what should be in the yaml of a blog post, means that for each blog post you know exactly what each element will be rendered as in the HTML.

My blog website rendered differently for different Quarto updates

Okay, so I admit that I wanted to essentially create something a little more unique than the Quarto defaults. I wanted a blog that didn’t look like Quarto but looked like what I wanted it to look like. This brings me onto the second reason as to why I switched to Astro. Quarto is continuously updating and this in itself is not a bad thing. In actual fact, it is a very good thing. But there were a few times in the previous blogs lifespan where I would update Linux, and in the process of doing so, update to a new version of Quarto. This new would then change the rendering of the blog site resulting in a slightly different, off-looking, blog that didn’t look how I wanted it to look. Elements on the page would shift around. This would happen, and I would wonder why, only to realise that there was a new release of Quarto. I would then have to check the release notes on GitHub to see what had changed. Then I would download an older release of Quarto that did work and that would keep the HTML elements the same. This is not so good. Whether this was because I had customised my Quarto blog beyond what you should be doing or whether this was truly on Quarto’s side is yet to be known. But still, I don’t expect my blog to look different every time Quarto updates. This also meant that I was stuck on rendering my blog using Quarto 1.4.557 and meant that certain new features I could not use.

While I can see that this is not a big deal because you can download an old release of Quarto and just stick to using that. But ultimately this meant that I had a Quarto version specifically for the rendering of my blog website. I had another version that I would use for rendering to RevealJS, I’d have the most up-to-date version globally installed in /usr/bin/Quarto. To me, it seemed a bit crazy. If HTML elements were going to change on every new Quarto release then I would have thought that Quarto would also mention somewhere about how best to carry out version controlling on their website. But there’s no mention of this. Admittedly though, version controlling for Quarto isn’t too much of a pain, but when you add up all the download sizes (since Quarto is a self-contained programme) my 3 or 4 different versions of Quarto were approaching 2 or 3 GBs (each install is around 300-500MBs).

Astro on the other hand, has had many version releases that have not changed how my blog site looks at all. Through experimentation with Astro over the past 6 months or so every single time I come back to Astro, my blog site looks consistently the same, despite the different Astro versions. Moreover, since this is all handled by npm I can lock a specific version of Astro for each project and this is a superior way of version control.

Quarto’s rendering process is cumbersome

Quarto offers a way to preview (quarto preview) the website and to render (quarto render) a website. These commands are actually very very different to one another. What this means is that when it came time for me to publish a new blog post, if I had made changes to the JavaScript code that ended up appearing in most of the blogs pages, the result would be that I would have to re-render the whole site again from scratch. This in itself would take time. This is because of the design of the Quarto rendering process, which is basically a 2-step process (unless you also have some additional post-rendering scripts). The first step is an execution engine process that renders the code blocks to create an intermediate Markdown file. Then in the second stage of rendering Pandoc converts this intermediate Markdown file and converts it to the desired output. As a result, if you have a lot of code blocks this means that the rendering process can take quite a loooooong time.

Astro on the other hand handles this rendering better. Currently, I write the markdown blog post. I then preview this using npm run dev which starts a localhost server showing the rendered page. Once I’m ready to publish the site I just push to GitHub and then the hosting provider is automatically triggered to run npm run build which will automatically rebuild the site. This means that I don’t actually have to do any rendering at all!

Quarto isn’t lightweight

When rendering to HTML there is an option that allows you to embed-resources. What this essentially means is that all resources on a page get dumped into an HTML document, and not so neatly I might add, resulting in an HTML file that you can’t change or open unless you have quite a beefy PC, with a lot of RAM in which to open the rendered HTML document. This is all very fine. It is probably not too often that you would want to make any changes to the rendered HTML file after the rendering process. But what it does mean is that if you wanted to make changes you would have to re-render again anyway. Moreover, even if you were not to embed all the resources into a single HTML document, there is a lot of “low-hanging fruit”. Essentially Quarto will render to HTML and include EVERYTHING needed to render the HTML even if you are not using it. For example, callouts. If I wasn’t going to use callouts then I shouldn’t have to import the CDN for it, or create styling for it in the CSS sheet, or have JavaScript included to create the effect of having them collapsible or not. This is wasted storage space.

Astro on the other hand, is extremely lightweight. In terms of what the rendered HTML pages look like, only the bare minimum is included and better, yet there is a choice in what JavaScript you want to include or which plugins you want to include. The result is that HTML pages load incredibly fast!

I use Quarto but not for everything

I am still going to use Quarto. It still saves me and all other users a great deal of time. I still think it creates excellent websites without minimal effort. But again that’s the exact point of Quarto. It isn’t meant for you to really be tinkering around too much. Me on the other hand, I am a tinkerer!!! I can’t help it, sometimes. I end up going deep into rabbit holes and as a result I end up making things harder for myself instead of easier. This is why I have switched to Astro (for now). I just wanted to make, making blog posts easier, without being deep in a rabbit hole.

Reactions

Comments

Loading comments...