fix(assets): rewrite service worker with two-strategy caching (#774)

- Replace legacy service-worker.js (imported from DoIt) with a clean
  rewrite using Hugo's ExecuteAsTemplate for fingerprinted URL injection
- Cache-first for static assets (immutable/fingerprinted), network-first
  for HTML pages with LRU eviction (max 100 entries)
- Fix LRU eviction to protect precached URLs using absolute URL comparison
- Add Fingerprint param to js-build.html partial to reduce boilerplate
- Extract to-css.html partial for reusable SCSS-to-CSS pipeline
- Support pre-built Resource param in script.html and style.html
- Store mainCSS and mainJS in Site.Store to avoid duplicate builds
- Remove explicit scope from serviceWorker.register() (defaults to /)

Closes #298
This commit is contained in:
Cell
2026-05-31 17:54:02 +08:00
committed by GitHub
parent 03d81f0785
commit 17164f42d0
11 changed files with 278 additions and 332 deletions
+12 -11
View File
@@ -290,12 +290,16 @@
{{- /* PWA */ -}}
{{- if not hugo.IsServer | and .Site.Params.enablePWA | and hugo.IsProduction -}}
{{- $serviceWorker := dict "Resource" (resources.Get "js/service-worker.js") "Build" true | partial "function/js-build.html" -}}
{{- with $fingerprint -}}
{{- $serviceWorker = $serviceWorker | fingerprint . -}}
{{- $offlineURL := "" -}}
{{- with .Site.Home.OutputFormats.Get "offline" -}}
{{- $offlineURL = .RelPermalink -}}
{{- end -}}
{{- $serviceWorkerURL := $serviceWorker.RelPermalink -}}
{{- $config = dict "PWA" (dict "enable" .Site.Params.enablePWA "serviceWorkerURL" $serviceWorkerURL) | merge $config -}}
{{- $mainCSS := .Site.Store.Get "mainCSS" -}}
{{- $mainJS := .Site.Store.Get "mainJS" -}}
{{- $swBuildCtx := dict "mainCSSURL" $mainCSS.RelPermalink "mainJSURL" $mainJS.RelPermalink "offlineURL" $offlineURL "relURL" (relURL "") "Page" . -}}
{{- $serviceWorker := resources.Get "js/service-worker.template.js" | resources.ExecuteAsTemplate "js/service-worker.template.js" $swBuildCtx -}}
{{- $serviceWorker = dict "Resource" $serviceWorker "Build" (dict "targetPath" "sw.js") "Fingerprint" $fingerprint | partial "function/js-build.html" -}}
{{- $config = dict "PWA" (dict "enable" .Site.Params.enablePWA "serviceWorkerURL" $serviceWorker.RelPermalink) | merge $config -}}
{{- end -}}
{{- /* Auto Bookmark */ -}}
@@ -366,10 +370,7 @@
{{- $layoutLoaders := $mermaid.layoutloaders | default slice -}}
{{- $options := dict "format" "esm" -}}
{{- $mermaidModule := dict "Resource" (resources.Get "js/lib/mermaid.ts") "Build" $options | partial "function/js-build.html" -}}
{{- with $fingerprint -}}
{{- $mermaidModule = $mermaidModule | fingerprint . -}}
{{- end -}}
{{- $mermaidModule := dict "Resource" (resources.Get "js/lib/mermaid.ts") "Build" $options "Fingerprint" $fingerprint | partial "function/js-build.html" -}}
{{- $mermaidModuleURL := $mermaidModule.RelPermalink -}}
{{- $bootstrapJS := dict
@@ -384,8 +385,8 @@
{{- dict "Content" $bootstrapJS "Path" "js/lib/mermaid-bootstrap.js" "Minify" hugo.IsProduction "Attr" `type="module"` "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
{{- end -}}
{{- /* Theme main bundle */ -}}
{{- dict "Source" "js/main.ts" "Build" true "Fingerprint" $fingerprint "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
{{- /* Theme main bundle (built once in head/index.html) */ -}}
{{- dict "Resource" (.Site.Store.Get "mainJS") "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
{{- /* Custom assets block */ -}}
{{- block "custom-assets" . }}{{ end -}}