Astro, Obsidian, Github and me
Every so often I like to update and / or completely redo my website. The motivation usually is a changed taste, new tech and other things I’ve picked up over the years. This time, the main factors were Astro, Every Layout, Obsidian and an urge to redesign my website. More minimal, bolder, while still portraying different aspects of myself.
I might write a different post about the design (and Every Layout) at some point. Today I’ll focus on Astro and the way this website is build and content updated.
Using Astro
In short, Astro is a static site generator. It’s very new but delightful to use. Their main selling point is the ability to add (JS-framework-of-your-choice)-components to the pages and render / load them based on certain criteria, like async or when they enter the viewport. I don’t have any of these at the moment.
It’s based on snowpack, and developed by the same guys, which provides certain benefits, like a really easy integration of Typescript and different CSS Preprocessors. This and their very own .astro
Syntax, which is very similar to JSX and the component architecture is what made it a joy to build my website with it.
.astro
Files
A short note about the astro files, because I really enjoy everything they do.
- They are completely typeable and support Typescript out of the box.
- They have a “frontmatter” JS section. Everything you do there is certain to run during the build process.
- You can use them like Single File Components (similar to the Vue ones). You can add tags to your
<head>
component from any other components. All in all a lot of built in features, that just make development joyful and easy, while still not giving me the “Black Box Magic” feel that Gatsby gave me. - It’s pretty easy to fetch content and render Markdown.
With all this praise, there are a few downsides. This mostly comes down to the relative young age of the framework and I’m looking forward to future release of it. I’m curious to how this post will age over the next months or years. I might revisit it in a year or so. Anyways, these are things I’m missing or are frustrating:
- No image pipeline and no way to interact with Node. The no node interaction thing is a design decision to allow it to run and build on as many environments as possible. I can get behind that idea and would like to see more Deno, but I’d also like a way to generate image source sets.
- No way to implement components in your markdown files (yet). This is also being worked on. You can extend the markdown renderer, but that seems a little cumbersome.
- Bugs and changing syntax. I mean, this is not really an issue. It’s just alpha / beta, so it’s to be expected. If you want to use it for a commercial product, be aware though. Maintenance might be slightly higher than with other projects. Then again, I’ve run into similar issues with Gatsby over the years.
Enough of this. Check it out. It’s fun and I whole-heartedly recommend it.
Setting up
So after setting up the project with Astro and laying some groundwork with CSS and writing some .astro
components and pages, I’ve come up with a few decisions and ideas I’d like to share. I’m not going to write out the base structure. Go read the fairly decents documentation for all the details on how to set up a page or lay out your project. I’d like to keep this post in a readable length.
Using a Layout
Ok, ok, here I go contradicting myself. I’m using a layout component, as it’s documented somewhere in the docs. It looks like this at the moment:
---
import MainHead from '../components/MainHead.astro';
import Header from "../components/Header.astro"
import Footer from "../components/Footer.astro"
const { content, title, description, canonical } = Astro.props;
---
<html lang="de">
<head>
<MainHead title={title} description={description} canonical={canonical} />
</head>
<body>
<Header></Header>
<a href="#content-start" class="text-assistive" id="content-start">Hier fängt der Inhalt an</a>
<main class="relative">
<slot />
</main>
<Footer></Footer>
</body>
</html>
Few things to note:
- Astro Components support
<slot/>
, which is a fairly well known concept and almost crucial for templating. - I’m setting the title, description and canonical URL from each page. I think they’ve just changed it so you can get the current page URL in every component. I might refactor that later.
- It’s nice to have a skip-link for assistive technology.
- Look at the syntax. It’s great.
Collections
Collections are the bread and butter of this page. You fetch files and Astro allows you to iterate over that content, transform it, render pages with it or create an RSS feed. It even supports pagination. I’m using all of it.
I’m using it for my blog (the listing and individual pages, tags filters coming soon) and my projects. They are all Markdown files with frontmatter. Said frontmatter is easily accessible in the collection functions.
This is the frontmatter for this post, for example:
---
title: "Astro, Obsidian, Github and me"
tags:
- Tech
- Web Development
date: 2021-08-05
lang: en-US
---
All you have to do is provide a path, build out the props you want to use and of course, write the content. This is all very transparent and you can use your plain old JS map/filter/whatever functions, which I love. It’s a lot of JS with very minimal custom syntax.
The rest is pretty much handled by Astro. It returns your rendered Markdown, your frontmatter, your pagination and paths. It’s easy. How I manage my content is what I want to talk about next.
Astro, Github and Obsidian
For now, a lot of texts on the more general pages are “hardcoded”, i.e. managed in the templates. Everything else is handled through collections.
My projects and Blogposts live in a different repository. All my markdown is written in Obsidian. It’s a great tool for building a a personal wiki / knowledgebase. I like to have all my Markdown files at one place. Makes it easy to move around and find things. Now to get the Markdown files from one repo into the pages’s repo is the “tricky” part (it’s not that tricky).
To facilitate this I’m using good old Github Actions.Take a look at my file. Look at it.
name: Build and deploy
on:
push:
branches: [master]
workflow_dispatch:
jobs:
Build-and-Deploy:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
repository: JSHSJ/flow
path: content
token: ${{ secrets.REPO_PAT }}
- name: Install lftp
run: sudo apt install lftp
- run: mkdir -p src/content/Projekte
- run: mkdir -p src/content/Blog
- run: mkdir -p public/assets/attachments
- run: mv content/flow/Projekte/attachments/* public/assets/attachments/
- run: mv content/flow/Blog/attachments/* public/assets/attachments/
- run: mv content/flow/Projekte/*.md src/content/Projekte/
- run: mv content/flow/Blog/*.md src/content/Blog/
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache .pnpm-store
uses: actions/cache@v1
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-node${{ matrix.node-version }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install pnpm
run: curl -f https://get.pnpm.io/v6.7.js | node - add --global pnpm@6
- run: pnpm install
- name: Build
run: |
pnpm build
touch ./dist/.nojekyll
- name: Deploy to FTP
run: lftp -e "open ${{ secrets.FTP_USERNAME }}.kasserver.com; user ${{ secrets.FTP_USERNAME }} ${{ secrets.FTP_PASSWORD }}; mirror -X .* -X .*/ --reverse --verbose --delete ./dist/ /joshuastuebner.com/; bye"
It’s not that complicated and it does a whole lot of things:
- Checkout both repos. You need a Private Access Token for that, that you generate on Github. Please put it in your secrets, not in your public repo.
- Create the directories and move the contents to the correct places. In my content repo, every directory has an
attachments
directory, where images and other assets go. I have to manually change the syntax a bit, because Obsidian does it a little differently, but that’s ok. They are then moved to the public directory, as per Astro’s structure. - Then you can build your artefact. It’s as simple as running install and build. Oh yea, I’m using PNPM, which is a lot faster and more resource friendly than good old
npm
. It works just fine with Astro. - Last step is to move it to my FTP. It’s a lovely German hosting provider. The page is then run through Cloudflare.
- That’s it.
Wrapping up
Enough of the many words. It’s become quite lengthy already. I might go into details on a few things later. Let me know, if you want to know about anything. Easiest way is to send me an email, but at the moment I’m also hanging around the Discord community quite a bit. I made my first real open source contribution by adding something to the docs. Feels great.
One last thing
Oh yea, before you go. Check out how fast and tiny this page it. It’s amazing. By far the largest thing to load is the giant variable font file (~ 150kb), which is loaded using preload
and font-display: optional;
, which basically means: If you can load it now and load it fast, do it. Otherwise, let it be. I’m quite happy how everything turned out and there are still a few more things to do.
But for now, thanks for reading and see you, maybe.
Source Code is available on Github