Important note, 2023-06-19: There has been a breaking change in how Embedded Dart Sass is packaged, and Hugo 0.114.0 is the first version that supports the new packaging, which uses the Dart Sass package. I have revised this post’s instructions for Hugo 0.114.0 and newer. If forced to use an older version of Hugo, you must continue with the older, archived Embedded Dart Sass packaging and the former versions of the instructions, which you can find in this page’s history.
Update, 2022-07-05: If you’re running a Hugo site on Vercel, be aware that the method described herein may have an adverse effect on the speed of your deployments. For more details, see “Using Dart Sass with Hugo: some data on using Github Actions.”
Note: For a much more thorough discussion of recent Sass-on-Hugo issues, please see my two previous posts on this subject. This follow-up assumes you’ve already read them.
Thought we were done with workarounds to make the Hugo static site generator (SSG) and Dart Sass play nicely together, did you? Ah, well, so did I. But, as I reconsidered the two end runs about which I wrote previously, I had concerns.
Regarding the first approach: some people simply don’t want to use Sass’s Node.js package, or any other Node.js package. In a similar vein, some purists might reject such a way of incorporating Sass because they think it doesn’t make properly efficient use of the Hugo Pipes asset pipeline. While I don’t share such attitudes, I respect that they exist in the Hugo community and may be more prevalent than I’d previously considered.
But that one didn’t trouble me a whole lot.
It was a different story when I kept mulling over the second, somewhat trickier approach. It enables Hugo to use Embedded Dart Sass from within the Dart Sass binary, through shell scripting that tells one of three hosting vendors — Netlify, Vercel, or Cloudflare Pages — to install the binary within the proper build-image PATH
. As a result, the binary is “visible” to Hugo during the build, and all goes on smoothly from there.
This had been working fine for me ever since Hugo’s Bjørn Erik Pedersen first proposed the idea, so what was my more recent problem with it? Just this: whether it can keep working depends upon those three hosting vendors’ not shutting down that particular workaround, perhaps for understandably security-related reasons, by simply (further) limiting one’s ability to adjust the respective build environment.
In the end, I figured, assuming they’d continue to let that slip by was too big a gamble; so I started trying to think of something with a better chance of surviving until there’s a more permanent solution.1
One morning this week, I awoke from an impromptu nap2 and came up with the answer I’m going to describe below: a GitHub Action (GHA). It wouldn’t be new ground, since I’ve written before about using GHAs to deploy static websites:
- “O say can you CI/CD?” (June, 2020) — Deploying to Netlify. This GHA served as a workaround for the 300-minutes-a-month build limit on Netlify’s free tier.
- “Ignition sequence start” (September, 2020) — Deploying to Firebase.
- “Forward PaaS” (October, 2020) — Deploying to a Cloudflare Workers site, the precursor to Cloudflare Pages.
However, this GHA wouldn’t be quite as straightforward as the ones in those posts. It would have to install not only the SSG (the Hugo binary, in this case) but also the Dart Sass binary. Furthermore, it would have to make sure the latter binary was in the build process’s PATH
.
You may be wondering why this would be any better than the shell-scripting approach. I had to convince myself, too; but I came up with two advantages, one major and the other a nice-to-have:
- The primary gain was that the build process would happen entirely on GitHub. This would allow using GitHub-approved code and variables to identify and adjust the build
PATH
on GitHub. With the shell-scripting method, we were adjusting thePATH
on the vendor’s platform in ways that, reiterating my earlier comments, might be okay a week from now but, then again, might not. It’s kinda like the difference between (A.) getting into a ballpark by buying a ticket and (B.) getting in by sneaking past an overly busy, preoccupied ticket-seller. Either way, you’re inside; but Option A is always suitable, while Option B works only until you get caught. (Okay, maybe that analogy is pushing it somewhat, but you understand what I’m saying.) - The minor happy point, at least for me, was that this would eliminate having to go into each vendor’s GUI and change the
HUGO_VERSION
environment variable every time there’s a new Hugo release.3 This way, I’d be providing that specification, as well as theDART_SASS_VERSION
spec, with a file that I can easily and conveniently update within my local project.4
Suitably inspired, I got to work. After a few hours of research, experimentation, and occasional gnashing of teeth, I had a working GHA for each of the three hosting vendors in question.5
Anyway, that’s more than enough preface. Now, let’s move on to the good stuff.
What’s ahead
Before I get to the vendor-specific instructions and GHAs, here are some general notes:
- Every GHA exists as a YAML file which must live in a
.github/workflows/
folder at your project’s top level. And, of course, that folder and its content must be committed in Git so GitHub will see them! - Since this will bypass most of the usual deployment pipeline for each hosting vendor, you’ll have to supply within the GHA all the environment variables that you’d normally provide via the vendor’s GUI.
Because of that . . . - You’ll need to add each such environment variable to the GitHub repo’s GHA-accessible secrets. You’ll also have to add vendor-specific credentials to these secrets. The instructions for each vendor will tell you how.
- You’ll notice, in each GHA below, that we’re referring to something called
secrets.GITHUB_TOKEN
. That secret already exists within the repo, and the GHA will automatically access it; it’s not something you have to create or store. - We’ll also refer to your local Hugo project’s
.env
file, a plain-text file where you’ll be storing the aforementioned environment variables and credentials for your own future reference (including during this process, as you’ll see). If your project doesn’t already have a.env
file, create it now at the project’s top level — and be sure it’s an entry in your project’s.gitignore
file, because this will contain sensitive information you never want to commit in Git even locally, much less allow it to appear on GitHub. And please don’t presume just making the GitHub repo private is sufficient protection for an inadvertently committed.env
file, because it’s definitely not. - The versions shown for Hugo and Dart Sass in each GHA are the current ones (0.114.0 and 1.63.4, respectively) as of the 2023-06-19 update of this post. You can always see which releases are up-to-date by checking the release pages for Hugo and Dart Sass.
Finally, because you don’t want to have to scroll-scroll-scroll through instructions for vendors you don’t even use, I’m using the <details>
and <summary>
HTML elements to keep things nice and compact. Just click/tap on a section to toggle it as either open or closed.
Netlify
Click/tap here to toggle open/close.
Note: You can set certain parameters with a netlify.toml
file, but herein we’ll be making all Netlify changes through its GUI.
Disabling automatic builds on Netlify
Make sure you have disabled automatic builds from the GitHub repository. To do this:
- Log into Netlify.
- Click Sites.
- Click the site you wish to modify.
- Click Deploys.
- Click Deploy settings.
- Under Build setting, click Edit settings.
- In the Builds setting, select Stop builds, then click Save at the bottom of the Build settings section.
- While still on the Deploy settings page, scroll down to the Post processing section.
- Under Asset optimization, click Edit settings.
- Select Disable asset optimization (if it’s not already selected) and, if this is a change from the current setting, click Save within the Asset optimization block.
Note: While steps 8–10 aren’t utterly necessary, I recommend them to avoid any potential glitches in the process.
Credentials for Netlify
For Netlify, you must supply:
- An authorization token.
- The site ID.
To get these credentials:
- In your code editor, open your site’s
.env
file so you’ll be ready to store the appropriate variables for later referral. - Log into Netlify.
- In the upper-right corner, click your avatar (it might be just an initial in a circle) and select User settings from the dropdown menu.
- In the left side of the resulting screen, click Applications.
- Go down to Personal access tokens.
- Click New access token. Give it an identifying name for your benefit. If you wish, name it
NETLIFY_AUTH_TOKEN
(just to follow along in the GHA below). - Click Generate token to generate the authorization variable BUT DON’T CLOSE THE GENERATED TOKEN BEFORE YOU PERFORM THE NEXT THREE STEPS!
- Copy the token and then paste it (as
NETLIFY_AUTH_TOKEN=
followed by the token value) into that.env
file you opened in the first step. This is critical because you won’t be able to access the token again. (You can create a new one, of course, but you can’t edit or even view an existing personal access token after it’s generated. That’s for your own protection.) - Save the
.env
file but keep it open for the time being. - Now you can click Done to save the newly created token.
- Click the Netlify icon in the upper left to return to your main settings.
- Click Sites.
- Click the site you want to deploy through the GHA.
- Click Site settings.
- Under Site information, copy the value shown for Site ID and paste it into the same
.env
file, noting that it’s yourNETLIFY_SITE_ID
value. (While you can see this one whenever you want, it’s more convenient to do it this way since you’ll be adding this to GitHub shortly.) - As before, save the
.env
file but keep it open for now.
If you wish, you now can log off from Netlify. - Log into your GitHub account.
- Access your site’s repo.
- Near the top of the screen, click Settings.
- In the resulting Settings screen, click Secrets, then Actions.
- In the resulting Actions secrets screen, click New repository secret.
- Name this secret
NETLIFY_AUTH_TOKEN
and, using the.env
file, copy/paste in the value from theNETLIFY_AUTH_TOKEN
you generated earlier. - Click Add secret. This will save the new secret and return you to the Actions secrets screen.
- Once again, click New repository secret.
- Name this secret
NETLIFY_SITE_ID
and copy/paste in theNETLIFY_SITE_ID
value from the.env
file. - Click Add secret.
If you wish, you now can close the.env
file and log out of your GitHub account.
The GitHub Action for Netlify
netlify-deploy.yaml
name: Deploy to Netlify
on:
push:
branches:
- main # or whatever you call your production branch
env:
HUGO_VERSION: 0.114.0 # will get Extended Version below
DART_SASS_VERSION: 1.62.4
# if you have other environment variables,
# enter them here in similar fashion
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout default branch
uses: actions/checkout@v3
- name: Download Hugo v${{ env.HUGO_VERSION }}
run: wget https://github.com/gohugoio/hugo/releases/download/v${{ env.HUGO_VERSION }}/hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb -O hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb
- name: Install Hugo v${{ env.HUGO_VERSION }}
run: sudo dpkg -i hugo*.deb
- name: Download Dart Sass v${{ env.DART_SASS_VERSION }}
run: curl -LJO https://github.com/sass/dart-sass/releases/download/${{ env.DART_SASS_VERSION }}/dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
- name: Unpack Dart Sass v${{ env.DART_SASS_VERSION }}
run: |
tar -xvf dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
dart-sass/sass --embedded --version
- name: Add to the PATH
run: echo "$GITHUB_WORKSPACE/dart-sass" >> $GITHUB_PATH
- name: Build site with Hugo
run: hugo --gc --minify
- name: Publish to Netlify
uses: nwtgck/actions-netlify@v1.2
with:
publish-dir: './public'
production-branch: 'main'
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: "Deploy from GitHub Actions"
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID}}
Vercel
Click/tap here to toggle open/close.
Disabling automatic builds on Vercel
Make sure you have disabled automatic builds from the GitHub repository. To do this:
- Log into Vercel.
- Click the project you wish to modify.
- Click Settings.
- Under Build & Development Settings:
- Set FRAMEWORK PRESET to Other.
- Set BUILD COMMAND to OVERRIDE and then leave the field blank.
- For each of the following, leave the field blank and make sure the item is not set to OVERRIDE:
- OUTPUT DIRECTORY.
- INSTALL COMMAND.
- DEVELOPMENT COMMAND.
Credentials for Vercel
For Vercel, you must supply:
- An authorization token.
- Your organization ID.
- The project ID.
To get these credentials:
- In your code editor, open your site’s
.env
file so you’ll be ready to store the appropriate variables for later referral. - Log into Vercel.
- In the upper-right corner, click your avatar (it might be just an initial in a circle) and select Settings from the dropdown menu.
- In the left side of the resulting screen, click Tokens.
- Click Create.
- In the resulting pop-up window:
- Under TOKEN NAME, enter
VERCEL_TOKEN_hugo-site
. - Under SCOPE, select Full Account.
- Click CREATE TOKEN.
- Copy the value from the resulting Token Created pop-up and immediately paste it into the
.env
file (which you should save immediately thereafter) asVERCEL_TOKEN_hugo-site=
followed by the value. As the pop-up notes, Vercel won’t show you this value again. - Click DONE to close the Token Created pop-up.
- Under TOKEN NAME, enter
- Keep the
.env
file open for the time being. - In the left-side menu, click General.
- Scroll down to Your ID.
- Copy/paste this value into the
.env
file and name itVERCEL_ORG_ID
; save the.env
file but keep it open. - Back in the Vercel window, at the top of the page, click Overview.
- Click the site you want to set up for deploy through the GHA.
- Click Settings. You’ll then be in the Project Settings screen.
- Scroll down to Project ID.
- Copy/paste this value into the
.env
file and name itVERCEL_PROJECT_ID
; save the.env
file but keep it open.
If you wish, you now can log off from Vercel. - Log into your GitHub account.
- Access your site’s repo.
- Near the top of the screen, click Settings.
- In the resulting Settings screen, click Secrets, then Actions.
- In the resulting Actions secrets screen, click New repository secret.
- Name this secret
VERCEL_TOKEN_hugo-site
and, using the.env
file, copy/paste in the value from theVERCEL_TOKEN_hugo-site
you generated earlier. - Click Add secret. This will save the new secret and return you to the Actions secrets screen.
- Once again, click New repository secret.
- Name this secret
VERCEL_ORG_ID
and copy/paste in theVERCEL_ORG_ID
value from the.env
file. - Click Add secret. This will save the new secret and return you to the Actions secrets screen.
- Once again, click New repository secret.
- Name this secret
VERCEL_PROJECT_ID
and copy/paste in theVERCEL_PROJECT_ID
value from the.env
file. - Click Add secret.
If you wish, you now can close the.env
file and log out of your GitHub account.
The GitHub Action for Vercel
vercel-deploy.yaml
name: Deploy to Vercel
on:
push:
branches:
- main # or whatever you call your production branch
env:
HUGO_VERSION: 0.114.0 # will get Extended Version below
DART_SASS_VERSION: 1.63.4
# if you have other environment variables,
# enter them here in similar fashion
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout default branch
uses: actions/checkout@v3
- name: Download Hugo v${{ env.HUGO_VERSION }}
run: wget https://github.com/gohugoio/hugo/releases/download/v${{ env.HUGO_VERSION }}/hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb -O hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb
- name: Install Hugo v${{ env.HUGO_VERSION }}
run: sudo dpkg -i hugo*.deb
- name: Download Dart Sass v${{ env.DART_SASS_VERSION }}
run: curl -LJO https://github.com/sass/dart-sass/releases/download/${{ env.DART_SASS_VERSION }}/dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
- name: Unpack Dart Sass v${{ env.DART_SASS_VERSION }}
run: |
tar -xvf dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
dart-sass/sass --embedded --version
- name: Add to the PATH
run: echo "$GITHUB_WORKSPACE/dart-sass" >> $GITHUB_PATH
- name: Build site with Hugo
run: hugo --gc --minify
- name: Publish to Vercel
uses: BetaHuhn/deploy-to-vercel-action@v1
with:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN_hugo-site }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID}}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID}}
WORKING_DIRECTORY: 'public'
Cloudflare Pages
Click/tap here to toggle open/close.
Disabling automatic builds on Cloudflare Pages
Make sure you have disabled automatic builds from the GitHub repository. To do this:
- Log into Cloudflare.
- Select Pages.
- Click the project you wish to modify.
- Click Settings.
- Click Builds & deployments.
- Under Branch deployments, click Configure Production deployments.
- Make sure Enable automatic production branch deployments is not checked and, if this is a change, click Save. Otherwise, click Cancel to return to the regular Branch deployments choices.
- Click Configure Preview deployments.
- Select None (Disable automatic branch deployments) and, if this is a change, click Save. Otherwise, click Cancel to return to the regular Branch deployments choices.
Credentials for Cloudflare Pages
For Cloudflare Pages, you must supply:
- An API token.
- Your account ID.
To get these credentials:
- In your code editor, open your site’s
.env
file so you’ll be ready to store the appropriate variables for later referral. - Log into Cloudflare.
- In the upper-right corner, click your avatar (probably a “person” icon) and select My Profile from the dropdown menu.
- In the left side of the resulting screen, click API Tokens.
- Click Create Token.
- In the resulting screen, in the Custom token section, click Get started.
- In the resulting section:
- Under Token name, enter
CFP_API_TOKEN
. - Under Permissions:
- In the first dropdown, select Account.
- In the second dropdown, select Cloudflare Pages.
- In the third dropdown, select Edit.
- Under Account Resources:
- In the first dropdown, select Include.
- In the second dropdown, select All accounts.
- Ignore the remaining items.
- Click Continue to summary.
- In the resulting screen, click Create Token.
- Copy the value from the resulting token-creation-success screen and immediately paste it into the
.env
file (which you should save immediately thereafter) asCFP_API_TOKEN=
followed by the value. As the screen notes, Cloudflare won’t show you this value again.
- Under Token name, enter
- Keep the
.env
file open for the time being. - In the upper-right corner, click your avatar and select Account Home.
- In the resulting screen, click the website you wish to deploy with the GHA.
- In the right side of the screen, scroll down to the API section.
- Copy/paste this value under Account ID into the
.env
file and name itCF_ACCOUNT_ID
; save the.env
file but keep it open.
If you wish, you now can log off from Cloudflare. - Log into your GitHub account.
- Access your site’s repo.
- Near the top of the screen, click Settings.
- In the resulting Settings screen, click Secrets, then Actions.
- In the resulting Actions secrets screen, click New repository secret.
- Name this secret
CFP_API_TOKEN
and, using the.env
file, copy/paste in the value from theCFP_API_TOKEN
you generated earlier. - Click Add secret. This will save the new secret and return you to the Actions secrets screen.
- Once again, click New repository secret.
- Name this secret
CF_ACCOUNT_ID
and copy/paste in theCF_ACCOUNT_ID
value from the.env
file. - Click Add secret.
If you wish, you now can close the.env
file and log out of your GitHub account.
The GitHub Action for Cloudflare Pages
cfp-deploy.yaml
name: Deploy to Cloudflare Pages
on:
push:
branches:
- main # or whatever you call your production branch
env:
HUGO_VERSION: 0.114.0 # will get Extended Version below
DART_SASS_VERSION: 1.63.4
# if you have other environment variables,
# enter them here in similar fashion
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout default branch
uses: actions/checkout@v3
- name: Download Hugo v${{ env.HUGO_VERSION }}
run: wget https://github.com/gohugoio/hugo/releases/download/v${{ env.HUGO_VERSION }}/hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb -O hugo_extended_${{ env.HUGO_VERSION }}_Linux-64bit.deb
- name: Install Hugo v${{ env.HUGO_VERSION }}
run: sudo dpkg -i hugo*.deb
- name: Download Dart Sass v${{ env.DART_SASS_VERSION }}
run: curl -LJO https://github.com/sass/dart-sass/releases/download/${{ env.DART_SASS_VERSION }}/dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
- name: Unpack Dart Sass v${{ env.DART_SASS_VERSION }}
run: |
tar -xvf dart-sass-${{ env.DART_SASS_VERSION }}-linux-x64.tar.gz
dart-sass/sass --embedded --version
- name: Add to the PATH
run: echo "$GITHUB_WORKSPACE/dart-sass" >> $GITHUB_PATH
- name: Build site with Hugo
run: hugo --gc --minify
- name: Publish to CFP
uses: cloudflare/pages-action@v1.0.0
with:
apiToken: ${{ secrets.CFP_API_TOKEN }}
accountID: ${{ secrets.CF_ACCOUNT_ID }}
projectName: 'hugo-site'
# use **your** CFP project's name above
directory: 'public'
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
Safer, but not bulletproof
So, you may be wondering, does all this truly solve the problems I imagined for the shell-scripting method?
The simple answer is: I think so, but even the method I’m proposing today could run afoul of ever-biting Reality. Let me spin some possibilities from within my occasionally paranoid skull.
When I was searching for how you tell a GHA to add something to the build path ($GITHUB_PATH
), I found a lot of pre-2020 advice about using an add-path
command. However, fortunately for me, I then also found that this command and another, set-env
, were deprecated in 2020. That’s how I ended up using the echo [thing] >> $GITHUB_PATH
-kinda line in each GHA. As of now, that works just fine; but GitHub could decide to change that, again, at any time.
Then, for that matter, GitHub could change any of the key GHA variables, such as $GITHUB_WORKSPACE
and $GITHUB_PATH
, at any time. Yeah, they’d break a whole [bleep]-ton of GHAs out there in the process, and that alone would probably prevent GitHub from doing so without giving folks a lot of advance warning; but it’s a possible gotcha worth keeping in mind.
And, let’s not forget the most obvious possible gotcha of all: one or more of these vendors could act to make it impossible for GHAs to work with their builds, which would be the ol’ ballgame right there.6
Still: while I thus concede this approach isn’t truly bulletproof, I’d also suggest that, compared to the shell-scripting method, it has a better chance than did its predecessor of surviving the hosting vendors’ various potential changes — not to mention GitHub’s, which didn’t even figure into the shell-scripting method since it was building on the vendors’ platforms rather than on GitHub’s.
We Shall See, as always. In the meantime: happy GHA’ing, folks.
To be precise, that permanent solution would be for each vendor to allow adding the Dart Sass binary to the build image (perhaps via an environment variable), much as you now can specify the desired version of Hugo. There have been occasional rumblings that one or more of the vendors might do this, but at this writing ETA = TBD in each case. I doubt it’s high on their collective radar. Update, 2023-05-09: I have learned this will be possible with Cloudflare Pages in the near future. ↩︎
In my defense, it was after having had roughly three hours of sleep the night before. I tend not to take naps, period, much less unplanned ones — contrary to what you young ’uns imagine about old, retired coots such as I. ↩︎
I push the site to multiple vendors for a variety of reasons (e.g., safety in case one vendor and/or its content delivery network happens to have an outage); but, even if you stick with only one vendor, changing environment variable(s) in the GUI-only method can be a nuisance. Besides, this site has a lot of environment variables, so multiply that nuisance by about 8x per vendor and you’ll see my point, here. ↩︎
For Vercel, you used to be able to do this sort of thing more simply — at least where
HUGO_VERSION
was concerned — via thevercel.json
file. However, now, Vercel documentation calls it a “legacy method” and counsels setting environment variables in the GUI, instead. I will give Vercel this much, though: at least its GUI lets you set each environment variable only once for both production and “preview” environments. By comparison, the Cloudflare Pages GUI makes you set each environment variable twice (once for each environment). When you have to add and/or edit a lot of environment variables in a hurry, the CFP approach is a major pain in the wazoo. ↩︎I looked for a way to do this with Render, too, but it appears the GHA ecosphere hasn’t yet come up with a suitable Action. As for other static hosting vendors, each wasn’t worth the trouble — yours or mine — for reasons into which I won’t delve here (but have mentioned in previous posts). If you want specifics, let me know. ↩︎
Indeed, while trying to find an appropriate Action for deploying to Vercel, I found at least one GitHub Discussion in which Vercel’s Lee Robinson was asking, essentially, “Um, why are you guys doing it this way instead of going through our GUI, as we’d prefer?” Fortunately, it appeared he was convinced by the answers he received. Nonetheless: as long as vendors are wont to raise such questions (since, as one would imagine, they worry about potential support issues arising from not-quite-kosher ways of doing stuff on their platforms), I have to be realistic and concede that GHA-assisted builds might get the side-eye from Those Who Decide Things. ↩︎
Latest commit (ddfbbdb6
) for page file:
2023-09-22 at 10:57:57 AM CDT.
Page history