mirror of
https://github.com/jbowdre/runtimeterror.git
synced 2024-12-27 05:02:18 +00:00
update draft
This commit is contained in:
parent
d1f2ac7536
commit
1ecdc884b0
2 changed files with 102 additions and 17 deletions
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
title: "Configuring a Custom Font in Hugo"
|
||||
title: "Using a Custom Font with Hugo"
|
||||
date: 2024-04-23
|
||||
# lastmod: 2024-04-23
|
||||
draft: true
|
||||
description: "This is a new post about..."
|
||||
description: "Installing a custom font on a Hugo site, and taking steps to protect the paid font files from unauthorized distribution. Plus a brief exploration of a pair of storage CDNs, and using Tailscale in a GitHub Actions workflow."
|
||||
featured: false
|
||||
toc: true
|
||||
comments: true
|
||||
categories: Tips # Backstage, ChromeOS, Code, Self-Hosting, VMware
|
||||
categories: Backstage
|
||||
tags:
|
||||
- bunny
|
||||
- cloudflare
|
||||
|
@ -17,10 +17,10 @@ tags:
|
|||
---
|
||||
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://scribbles.jbowdre.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
|
||||
|
||||
Long story short, you're looking at a slick new font here. Long story long: I'm about to tell you how I added the font both to the site and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
|
||||
Well, you're looking at the slick new font here, and I'm about to tell you how I added the font both to the site itself and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
|
||||
|
||||
### Web Font
|
||||
The [risotto theme for Hugo](https://github.com/joeroe/risotto/tree/main) upon which this site is based defines the default font face(s) as the variable `--font-monospace` in `themes/risotto/static/css/typography.css`, and then that variable is inserted wherever the font may need to be set:
|
||||
This site's styling is based on the [risotto theme for Hugo](https://github.com/joeroe/risotto/tree/main). Risotto uses the CSS variable `--font-monospace` in `themes/risotto/static/css/typography.css` to define the font face, and then that variable is inserted wherever the font may need to be set:
|
||||
|
||||
```css
|
||||
/* torchlight! {"lineNumbers":true} */
|
||||
|
@ -36,7 +36,7 @@ body {
|
|||
}
|
||||
```
|
||||
|
||||
This makes it easy to override the theme's font by referencing my preferred font in `static/custom.css`:
|
||||
This makes it easy to override the theme's font by inserting my preferred font in `static/custom.css`:
|
||||
|
||||
```css
|
||||
/* font overrides */
|
||||
|
@ -54,7 +54,7 @@ And that would be the end of things if I could expect that everyone who visited
|
|||
}
|
||||
```
|
||||
|
||||
That gives me a few more fallback fonts to fall back to if my preferred font isn't available. But let's see about making that font available.
|
||||
That provides a few more options to fall back to if the preferred font isn't available. But let's see about making that font available.
|
||||
|
||||
#### Hosted Locally
|
||||
I can use a `@font-face` rule to tell the browser how to find the `.woff2`/`.woff` files for my preferred web font, and I could just set the `src: url` parameter to point to a local path in my Hugo environment:
|
||||
|
@ -65,18 +65,20 @@ I can use a `@font-face` rule to tell the browser how to find the `.woff2`/`.wof
|
|||
font-family: 'Berkeley Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
/* use the installed font with this name if it's there... */
|
||||
src: local('Berkeley Mono'),
|
||||
/* otherwise look at these paths */
|
||||
url('/fonts/BerkeleyMono.woff2') format('woff2'),
|
||||
url('/fonts/BerkeleyMono.woff') format('woff')
|
||||
}
|
||||
```
|
||||
|
||||
And that would work just fine... but it *would* require storing those web font files in the GitHub repo which powers my site, and I'd rather not host any paid font files in such a way.
|
||||
And that would work just fine... but it *would* require storing those web font files in the (public) [GitHub repo](https://github.com/jbowdre/runtimeterror) which powers my site, and I'd rather not store any paid font files there.
|
||||
|
||||
So instead, I opted to store the web font files in a CDN, where I could exercise some degree of access control, learn more about a web technology I haven't played with a whole lot, and make use of a cool `cdn.runtimeterror.dev` subdomain in the process.
|
||||
So instead, I opted to try using a [Content Delivery Network (CDN)](https://en.wikipedia.org/wiki/Content_delivery_network) to host the font files. This would allow for some degree of access control, help me learn more about a web technology I hadn't played with much, and make use of a cool `cdn.*` subdomain in the process.
|
||||
|
||||
{{% notice note "Double the CDN, double the fun" %}}
|
||||
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://scribbles.jbowdre.lol/post/i-just-hopped-to-bunny-net). So I'm going to briefly describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
|
||||
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://scribbles.jbowdre.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
|
||||
{{% /notice %}}
|
||||
|
||||
#### Cloudflare R2
|
||||
|
@ -125,9 +127,9 @@ I *eventually* discovered that sometimes you need to clear Cloudflare's cache so
|
|||
### Bunny Storage
|
||||
After migrating my domain to Bunny.net, the CDN font setup was pretty similar - but also different enough that it's worth mentioning. I started by creating a new Storage Zone named `runtimeterror-storage`, and selecting an appropriate-seeming set of replication regions. I then uploaded the same `fonts/` folder as before.
|
||||
|
||||
To be able to access the files in Bunny Storage, I then connected a new Pull Zone (called `runtimeterror-pull`) and linked that Pull Zone with the `cdn.runtimeterror.dev` hostname. I also made sure to enable the option to automatically generate a certificate for this host.
|
||||
To be able to access the files in Bunny Storage, I connected a new Pull Zone (called `runtimeterror-pull`) and linked that Pull Zone with the `cdn.runtimeterror.dev` hostname. I also made sure to enable the option to automatically generate a certificate for this host.
|
||||
|
||||
Rather than needing me to understand CORS and craft a viable policy file, Bunny provides a clean UI with easy-to-understand options for configuring the pull zone security. I enabled the options to block root path access, block `POST` requests, and block direct file access, and also added the same trusted referrers as before:
|
||||
Rather than needing me to understand CORS and craft a viable policy file, Bunny provides a clean UI with easy-to-understand options for configuring the pull zone security. I enabled the options to block root path access, block `POST` requests, block direct file access, and also added the same trusted referrers as before:
|
||||
|
||||
![Bunny CDN security configuration](bunny-cdn-security.png)
|
||||
|
||||
|
@ -146,12 +148,14 @@ I made sure to use the same paths as I had on Cloudflare so I didn't need to upd
|
|||
}
|
||||
```
|
||||
|
||||
I again tested locally with `hugo server` and confirmed that the font loaded from Bunny CDN without any CORS or other errors.
|
||||
|
||||
So that's the web font for the web site sorted (twice); now let's tackle the font in the OpenGraph share images.
|
||||
|
||||
### Image Filter Text
|
||||
My [setup for generating the share images](/dynamic-opengraph-images-with-hugo/) leverages the Hugo [images.Text](https://gohugo.io/functions/images/text/) function to overlay text onto a background image, and it needs a TrueType font in order to work. I was previously just storing the required font directly in my GitHub repo so that it would be available during the site build, but I definitely don't want to do that with a paid font file. So I needed to come up with some way to provide the TTF file to the builder without making it publicly available.
|
||||
My [setup for generating the share images](/dynamic-opengraph-images-with-hugo/) leverages the Hugo [images.Text](https://gohugo.io/functions/images/text/) function to overlay text onto a background image, and it needs a TrueType font in order to work. I was previously just storing the required font directly in my GitHub repo so that it would be available during the site build, but I definitely don't want to do that with a paid TrueType font file. So I needed to come up with some way to provide the TTF file to the GitHub runner without making it publicly available.
|
||||
|
||||
I recently figured out how I could [use a GitHub Action to easily connect the builder to my Tailscale environment](/gemini-capsule-gempost-github-actions/#publish-github-actions:~:text=name%3A%20Connect%20to%20Tailscale), and I figured I could re-use that idea here - only instead of pushing something to my tailnet, I'll need to pull something out.
|
||||
I recently figured out how I could [use a GitHub Action to easily connect the runner to my Tailscale environment](/gemini-capsule-gempost-github-actions/#publish-github-actions:~:text=name%3A%20Connect%20to%20Tailscale), and I figured I could re-use that idea here - only instead of pushing something to my tailnet, I'll be pulling something out.
|
||||
|
||||
#### Tailscale Setup
|
||||
So I SSH'd to the cloud server I'm already using for hosting my Gemini capsule, created a folder to hold the font file (`/opt/fonts/`), and copied the TTF file into there. And then I used [Tailscale Serve](/tailscale-ssh-serve-funnel/#tailscale-serve) to publish that folder internally to my tailnet:
|
||||
|
@ -165,7 +169,9 @@ https://node.tailnet-name.ts.net/fonts/
|
|||
|-- path /opt/fonts
|
||||
```
|
||||
|
||||
Last time, I set up the Tailscale ACL so that the GitHub Runner (`tag:gh-bld`) could talk to my server (`tag:gh-srv`) over SSH:
|
||||
The `--bg` flag will run the share in the background and automatically start it with the system (like a daemon-mode setup).
|
||||
|
||||
When I set up Tailscale for the Gemini capsule workflow, I configured the Tailscale ACL so that the GitHub runner (`tag:gh-bld`) could talk to my server (`tag:gh-srv`) over SSH:
|
||||
|
||||
```json
|
||||
"acls": [
|
||||
|
@ -234,7 +240,11 @@ Here's the image-related code that I was previously using in `layouts/partials/o
|
|||
{{ $img = resources.Copy (path.Join $.Page.RelPermalink "og.png") $img }}
|
||||
```
|
||||
|
||||
All I need to do is get it to pull the font resource from a web address rather than the local file system, and I'll do that by loading an environment variable instead of hardcoding the path here:
|
||||
All I need to do is get it to pull the font resource from a web address rather than the local file system, and I'll do that by loading an environment variable instead of hardcoding the path here.
|
||||
|
||||
{{% notice note "Hugo Environent Variable Access" %}}
|
||||
By default, Hugo's `os.Getenv` function only has access to environment variables which start with `HUGO_`. You can [adjust the security configuration](https://gohugo.io/functions/os/getenv/#security) to alter this restriction if needed, but I figured I could work just fine within the provided constraints.
|
||||
{{% /notice %}}
|
||||
|
||||
```jinja-html
|
||||
{{ $img := resources.Get "og_base.png" }}
|
||||
|
@ -279,5 +289,80 @@ All I need to do is get it to pull the font resource from a web address rather t
|
|||
{{ $img = resources.Copy (path.Join $.Page.RelPermalink "og.png") $img }} <!-- [tl! collapse:end ] -->
|
||||
```
|
||||
|
||||
I can test that this works by running a build locally from a system with access to my tailnet. I'm not going to start a web server with this build; I'll just review the contents of the `public/` folder once it's complete to see if the OpenGraph images got rendered correctly.
|
||||
|
||||
```shell
|
||||
HUGO_REMOTE_FONT_PATH=https://node.tailnet-name.ts.net/fonts/BerkeleyMono.ttf hugo
|
||||
```
|
||||
|
||||
Neat, it worked!
|
||||
|
||||
![OpenGraph share image for this post](og-sample.png)
|
||||
|
||||
#### GitHub Action
|
||||
All that's left is to update the GitHub Action to handle the build for me.
|
||||
All that's left is to update the GitHub Actions workflow I use for [building and deploying my site to Neocities](/deploy-hugo-neocities-github-actions/) to automate things:
|
||||
|
||||
```yaml
|
||||
# torchlight! {"lineNumbers": true}
|
||||
# .github/workflows/deploy-to-neocities.yml
|
||||
name: Deploy to Neocities
|
||||
# [tl! collapse:start]
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 13 * * *
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: deploy-to-neocities
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
# [tl! collapse:end]
|
||||
jobs:
|
||||
deploy:
|
||||
name: Build and deploy Hugo site
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Hugo setup
|
||||
uses: peaceiris/actions-hugo@v2.6.0
|
||||
with:
|
||||
hugo-version: '0.121.1'
|
||||
extended: true
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Connect to Tailscale # [tl! ++:10 **:10]
|
||||
uses: tailscale/github-action@v2
|
||||
with:
|
||||
oauth-client-id: ${{ secrets.TS_API_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.TS_API_CLIENT_SECRET }}
|
||||
tags: ${{ secrets.TS_TAG }}
|
||||
- name: Build with Hugo
|
||||
run: hugo --minify # [tl! -- **]
|
||||
run: HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} hugo --minify # [tl! ++ ** reindex(-1) ]
|
||||
- name: Insert 404 page
|
||||
run: |
|
||||
cp public/404/index.html public/not_found.html
|
||||
- name: Highlight with Torchlight
|
||||
run: |
|
||||
npm i @torchlight-api/torchlight-cli
|
||||
npx torchlight
|
||||
- name: Deploy to Neocities
|
||||
uses: bcomnes/deploy-to-neocities@v1
|
||||
with:
|
||||
api_token: ${{ secrets.NEOCITIES_API_TOKEN }}
|
||||
cleanup: true
|
||||
dist_dir: public
|
||||
```
|
||||
|
||||
This uses the [Tailscale GitHub Action](https://github.com/tailscale/github-action) to connect the runner to my tailnet using the credentials I created earlier, and passes the `REMOTE_FONT_PATH` secret as an environment variable to the Hugo command line. Hugo will then be able to retrieve and use the TTF font during the build process.
|
||||
|
||||
### Conclusion
|
||||
Configuring and using a custom font in my Hugo-generated site wasn't hard to do, but I had to figure some things out on my own to get started in the right direction. I learned a lot about how fonts are managed in CSS along the way, and I love the way the new font looks on this site!
|
||||
|
||||
This little project also gave me an excuse to play with first Cloudflare R2 and then Bunny Storage, and I came away seriously impressed by Bunny (and have since moved more of my domains to bunny.net). Expect me to write more about cool Bunny stuff in the future.
|
BIN
content/posts/using-custom-font-hugo/og-sample.png
Normal file
BIN
content/posts/using-custom-font-hugo/og-sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Loading…
Reference in a new issue