Hi. This was actually a fairly trivial project to setup, as you might expect with it just being a simple portfolio website, but I had a few constraints which spiced it up a little:

  • The smaller the project (or at least, the simpler), the less time I want to spend baking in features that would take me weeks. For example, I really did not want to spend a month rolling my own parser for markdown, or having to deal with a dynamically sizing routers etc. This had to be quick and easy.
  • I wanted to be able to work with obsidian. The graph view is awesome, markdown is great and it just works. I’ve too many notes to count, and being able to collate them in a vault is useful and a clean approach.
  • The updates had to be as frictionless and automatic as possible. No having to copy notes over, just one push/publish and it would appear. The hosting had to be cheap, reliable and simple.

With those constraints in mind, here’s what I did.


PixelArt Image credits: Glassirok on PixelArt.com

So what should this be built with? I had a few different options, and some back and forth with gemini led me to picking quartz, a fast and “batteries included” SSG that would mimic an obsidian layout in the browser. Why?

  • Simple setup? Goal met ✅
  • Works with Obsidian? Goal met ✅
  • Is well maintained and can deploy markdown with relative ease? ✅
  • Open source and well supported? ✅

I considered some other options, such as 11ty, which is one of the most widely used frameworks for content generation, with notable sites like the V8 Project being documented on here, extremely fast build + deploy times owing to the super compact rendering engine used, is super stable and supports as many template languages as I needed. As a bonus, it’s also open source and very well documented.

I knew I’d want to utilise the note taking system within my workflow that I’m so used to, and having a graph view would be amazing to have, and that’s what really pushed me over the edge to use Quartz.

Keeping Notes Synchronised.

One of the aims I listed earlier was frictionless deployment of new posts and content, with minimal pushing/syncing required. How on earth do we achieve that? Git submodules!

Diagram

I created a new Obsidian vault, and along with it, created a remote repository (all on Github!) to keep the notes stored, and to utilise github actions. The actual creation of the site itself was fairly simple, I simply pulled the repo down, added my new remote (to allow for my own pages deployment) and pushed up the new site framework! I created a new git submodule in the /content folder to allow me to track changes in the content and make updates/redeploys with this!

Now for the slightly trickier part - automating the deployments! I chatted with Gemini about how best to go about this, and put together a skeleton for the YAML file used in the workflow. I knew I’d need two pipelines (One for triggering a rebuild on push, one for the actual redeploy). I created a new pipeline and got to work:

name: Trigger Quartz Website Build
 
on:
  push:
    branches:
      - develop
 
jobs:
  trigger_build:
    runs-on: ubuntu-latest
    steps:
      - name: Repository Dispatch
        uses: peter-evans/repository-dispatch@v2 
        with:
          token: ${{ secrets.QUARTZ_REPO_TOKEN }}
          repository: PaulDavidTucker/Quartz
          event-type: content-updated 

A couple of things to note here - I’m using the repository-dispatch action here to trigger a redeploy, which sends a remote_dispatch event to a given remote repo. Another pipeline can be waiting to trigger based on this event, which is perfect for my use case (when notes get updated, trigger a redeploy in the website! 😁). The documentation for this does also list extra options you can send in the event payload, so maybe I could split the pipelines into “semantic” and “content” in the future to change different things?

NOTE

If attempting to send an event to a remote repository, you’ll need a Personal Access Token with “Repo” access scope!

The Quartz repo itself that I was using for my Github pages just needed to listen for that event to be dispatched and then deploy when received. I did have a couple of options for how to trigger the pages redeploy, but Github themselves maintains a pretty stable package for redeploys that also can be toggled from the webUI itself.

name: Build and Deploy Quartz Site
 
on:
  repository_dispatch:
    types: [content-updated] 
  workflow_dispatch:
 
  push:
     branches:
       - develop 
 
jobs:
  build-deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write 
      pages: write    
      id-token: write 
 
    steps:
      - name: Checkout main repository
        uses: actions/checkout@v4 
        with:
          token: ${{ secrets.QUARTZ_REPO_TOKEN }}
          submodules: 'recursive'
          persist-credentials: true
          
      - name: Ensure submodule is at latest commit
        run: |
          cd content
          git fetch origin
          git checkout $(git rev-parse --abbrev-ref HEAD)
          git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)
          cd ..
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20' 
          cache: 'npm'
 
      - name: Install Dependencies
        run: npm ci
 
      - name: Build Quartz Site
        run: npx quartz build 
 
      - name: Upload GitHub Pages artifact
        uses: actions/upload-pages-artifact@v3 
        with:
          path: ./public
      
      - name: Deploy to GitHub Pages (official)
        id: deployment
        uses: actions/deploy-pages@v4

Whilst I didn’t really mind if we didn’t have every dependency at the absolute latest, what I did care about was always having my content up to date! Also I would be extremely frustrated if I’d just spent ages writing a new blog and it vanished into smoke because of some annoying git issue…

The solution was pretty simple, just fetch the latest changes in the submodule folder, checkout the default branch, then reset to whatever that was and discard any residual changes. Awesome! I gave it a test run, and it looked pretty good!

Some future expansions:

  • A donation button! If you never ask, you shall never receive…
  • Some kind of Github widget with my most recent commit stats or something?
  • Change up the theme a little? Would be as simple as adding a new environment variable into the quartz build steps!