Skip to content

Instantly share code, notes, and snippets.

@ghstahl
Created November 15, 2025 17:51
Show Gist options
  • Select an option

  • Save ghstahl/0e082ae6f65822518700cd4bd6ab79af to your computer and use it in GitHub Desktop.

Select an option

Save ghstahl/0e082ae6f65822518700cd4bd6ab79af to your computer and use it in GitHub Desktop.
go-app wasm cache busting resolver
package ResourceResolvers
import (
"mime"
"net/http"
"path/filepath"
"strings"
"github.com/maxence-charriere/go-app/v10/pkg/app"
)
func ResourceResolverWithCacheBustingVersion(base app.ResourceResolver, version string, paths ...string) app.ResourceResolver {
pathMap := make(map[string]struct{}, len(paths))
for _, p := range paths {
if strings.HasPrefix(p, "/web/") {
pathMap[p] = struct{}{}
}
}
return versionedCacheBustingResourceResolver{
ResourceResolver: base,
version: version,
paths: pathMap,
}
}
type versionedCacheBustingResourceResolver struct {
app.ResourceResolver
version string
paths map[string]struct{}
}
func (r versionedCacheBustingResourceResolver) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
path := request.URL.Path
if idx := strings.Index(path, "?"); idx != -1 {
path = path[:idx]
}
if strings.HasPrefix(path, "/web/") {
filePath := filepath.FromSlash(strings.TrimPrefix(path, "/"))
ext := filepath.Ext(filePath)
if ext != "" {
switch ext {
case ".wasm":
writer.Header().Set("Content-Type", "application/wasm")
default:
if contentType := mime.TypeByExtension(ext); contentType != "" {
writer.Header().Set("Content-Type", contentType)
}
}
}
http.ServeFile(writer, request, filePath)
return
}
if handler, ok := r.ResourceResolver.(http.Handler); ok {
handler.ServeHTTP(writer, request)
return
}
http.NotFound(writer, request)
}
func (r versionedCacheBustingResourceResolver) Resolve(path string) string {
switch path {
//case "/web/app.wasm":
// path = "/web/versions/app-" + r.version + ".wasm"
case
"/web/app.wasm",
"/web/styles.css",
"/app.js",
"/app-worker.js",
"/wasm_exec.js",
"/manifest.webmanifest",
"/app.css",
"/vi.css":
path = path + "?v=" + r.version
default:
if _, resolvable := r.paths[path]; resolvable {
extension := filepath.Ext(path)
if extension == "" {
return r.ResourceResolver.Resolve(path)
}
path = strings.Replace(path, "/web/", "/web/versions/", 1)
path = strings.TrimSuffix(path, extension) + "-" + r.version + extension
}
}
return r.ResourceResolver.Resolve(path)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment