Improve the workers/edge middleware support
Author: bepCreated Aug 16, 2026Updated Sep 10, 2026
LabelsProposal
I have been setting up a Google Analytics server proxy[^location] using Cloudflare workers, and I was pleasantly surprised about the smooth sailing.
My setup in Hugo for this outlined:
assets/workers/index.js
import analytics from './analytics.js';
export default {
async fetch(request, env, ctx) {
return (await analytics(request, env, ctx)) ?? env.ASSETS.fetch(request);
},
};
_layouts/partials/worker.html (loaded once with partialCached)
{{ $opts := dict
"targetPath" "_worker.js"
"format" "esm"
"minify" (not hugo.IsDevelopment)
"params" (dict "measurementID" site.Params.gaMeasurementID)
}}
{{ (resources.Get "workers/index.js" | js.Build $opts).Publish }}
{{ (resources.FromString ".assetsignore" "_worker.js\n").Publish }}
wrangler.toml
name = 'myapp'
main = './public/_worker.js'
compatibility_date = '2025-07-31'
[build]
command = './build.sh'
[assets]
directory = './public'
binding = 'ASSETS'
not_found_handling = '404-page'
The above is pretty nice, but there's some warts:
- Having the script that generates the worker script(s) in the middle of a rendering template (even if effectively run once with
partialCached) isn't great. - Also, writing these server functions to
/publicisn't great. It works out for Cloudflare Workers, but for e.g. Netlify you would need to do e.g.hugo && mv public/_edge/analytics.js .netlify/edge-functions/analytics.js. - There's no simple to compose handlers pulled in from modules.
[^location]: Recent updates to the protocol, most notably the user_location attribute, has made this a much more viable option. My take on this should be privacy/GPDR-friendly; no cookies and no localStorage usage. I will try to wrap this up in a Hugo Module once I get this fully tested.
Source: gohugoio/hugo