You’re sitting there, tinkering with your Quartz wiki.

Check public/ - each HTML page is already 50-60 KB. Not to mention index.css bloated to 40 KB.

Quartz itself isn’t that fat out of the box.

But in the process of “improving” it piles up:

Fonts:                ~2.5 MB
JS + CSS:             ~150 KB
HTML:                 ~1.6 MB

Hello, motherfuckingwebsite.com!

With this setup I won’t make it into 14kbclub.com.

not that I wanted to, but at least I can try to get closer


What to do?

Fonts - fat you’re better off without

Custom fonts are always extra weight. Every @font-face is a request, rendering blocks until the font loads, and the user gets FOUT or FOIT.

Best solution - don’t use custom fonts at all. System fonts (system-ui, sans-serif) are already on the device, nothing to download.

If you really want them - fonts should live only in @font-face via fontOrigin: "local", no Google Fonts duplication.


Inline scripts

Quartz shoves inline scripts straight into every page’s HTML:

<script>/* callout collapse - 8 KB */</script>
<script>/* contentIndex fetch */</script>

On one hand, inline isn’t bad: if the script is tiny, it rides in the first TCP packet (1460 bytes) and doesn’t block rendering.

But when these scripts pile up to tens of KB on every page - it’s all duplicated, not cached, and the browser re-parses the same thing on every navigation.

Quartz bundles all afterDOMLoaded hooks from components into postscript.js, which does get cached. Callout didn’t make it there - it was added via externalResources() from the ObsidianFlavoredMarkdown plugin as inline.

Fix - stitch the scripts into afterDOMLoaded of any component so they end up in postscript.js.


Mermaid

Mermaid - a diagram library. The CDN version weighs 2.3 MB, the loader script is 4.7 KB, CSS is another 9 KB.

Problem: Quartz adds them to EVERY page by default. Even if you don’t have a single diagram.

It just. Sits there. Dead weight.

just there, but why?

Solution - check for mermaid blocks at build time and add only where needed:

if (opts.mermaid) {
  plugins.push(() => {
    return (tree, file) => {
      visit(tree, "element", (node) => {
        if (...) file.data.hasMermaid = true
      })
    }
  })
}

And in contentPage.tsx:

if (fileData.hasMermaid) {
  externalResources.js.push({ script: mermaidScript, ... })
  externalResources.css.push({ content: mermaidStyle, ... })
}

Now mermaid doesn’t hang on pages that don’t need it. Which is probably most of them.

KaTeX

KaTeX - a formula rendering library. 600 KB CSS and 300 KB JS.

Quartz bundles it on every page out of the box. Even if you don’t have a single formula.

The right approach - load KaTeX optionally, only on pages with formulas: Scan HTML for $...$ or $$...$$, and if found - add the scripts. If not - don’t load.

It’s trickier than mermaid because formulas can be inline ($x^2$) - you can’t catch them at the remark stage, you need regex or a rehype plugin. But it’s worth it: 900 KB per page that doesn’t cache well because KaTeX is CSS + fonts + JS.


Images

Giving them up can be really hard.

If you really need them:

The simplest way - loading="lazy".

Adds with one rehype plugin:

plugins.push(() => {
  return (tree) => {
    visit(tree, "element", (node) => {
      if (node.tagName === "img" && !node.properties?.loading) {
        node.properties.loading = "lazy"
      }
    })
  }
})

Now the browser doesn’t block waiting for all images to load before showing text. It renders the page and loads images later.


Explorer

Rendered server-side, and as the number of pages grows, its HTML becomes noticeable.

Every folder, every level of nesting - divs, wrappers, attributes. On a site with deep structure the tree can take up tens of KB just in markup.

If the site is big - either disable the Explorer and use graphs instead, or refine it: strip unnecessary wrappers, limit depth, lazy-load subfolders.


Quartz indexes all pages for fast site search and better SEO crawling.

Whether you need it or not - up to you.


Does this even help?

ComponentBeforeAfter
Google Fonts~2.5 MB0
KaTeX~900 KB/page0
Inline scripts~600 KBpostscript.js 102 KB
Mermaidon every pageonly where needed
ImagesA lot.loading="lazy"
Explorermany divssomewhat lighter

A page without mermaid and without images now weighs ~10 KB HTML + 41 KB index.css + 102 KB postscript.js.

All cached. When jumping between pages, only the lightweight HTML needs to be fetched.