repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

1.6 KB · 57 lines · Go Raw History
 1package main
 2
 3import (
 4	"crypto/sha256"
 5	"encoding/hex"
 6	"io/fs"
 7	"sync"
 8)
 9
10// Cache busting for the hand written assets.
11//
12// The Vite sites here get content hashed filenames, so `immutable` on their
13// static handler is safe. This site writes app.css and app.js by hand at fixed
14// paths, and `immutable` on a fixed path means Cloudflare holds the old file for
15// a year and a stylesheet change is invisible at the edge while being correct in
16// the container. A hash of the bytes in the query string gives the same
17// guarantee without a build step, since Cloudflare keys its cache on the whole
18// url.
19
20var (
21	assetOnce sync.Once
22	assetVers map[string]string
23)
24
25// assetURL is the template function. A missing file falls through to the bare
26// path rather than failing the render, since a broken stylesheet link is easier
27// to read than a blank page.
28func assetURL(path string) string {
29	assetOnce.Do(loadAssetVersions)
30	if v, ok := assetVers[path]; ok {
31		return "/" + path + "?v=" + v
32	}
33	return "/" + path
34}
35
36func loadAssetVersions() {
37	assetVers = map[string]string{}
38	_ = fs.WalkDir(assets(), "static", func(p string, d fs.DirEntry, err error) error {
39		if err != nil || d.IsDir() {
40			return nil
41		}
42		b, err := fs.ReadFile(assets(), p)
43		if err != nil {
44			return nil
45		}
46		sum := sha256.Sum256(b)
47		assetVers[p] = hex.EncodeToString(sum[:])[:10]
48		return nil
49	})
50}
51
52// resetAssetVersions is what the development reload path calls, so editing CSS
53// off disk still changes the url rather than serving the version read at boot.
54func resetAssetVersions() {
55	assetOnce = sync.Once{}
56}