* Fix serviceworker output file and misc improvements - Fix output file location for production build - Cache more asset types: fonts and worker variants - Parallelize a few tasks during initalization - Only invalidate caches starting with our prefix - Remove public/serviceworker.js before building - Remove font preloads, they cause strange cors issues - Misc eslint config adjustments * remove webpack output files on watch-frontendtags/v1.13.0-rc1
Tribute: false | Tribute: false | ||||
overrides: | overrides: | ||||
- files: ["web_src/**/*.worker.js"] | |||||
- files: ["web_src/**/*.worker.js", "web_src/js/serviceworker.js"] | |||||
env: | env: | ||||
worker: true | worker: true | ||||
rules: | rules: | ||||
no-restricted-syntax: [0] | no-restricted-syntax: [0] | ||||
no-return-await: [0] | no-return-await: [0] | ||||
no-shadow: [0] | no-shadow: [0] | ||||
no-underscore-dangle: [0] | |||||
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}] | no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}] | ||||
no-use-before-define: [0] | no-use-before-define: [0] | ||||
no-var: [2] | no-var: [2] |
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f) | WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f) | ||||
WEBPACK_CONFIGS := webpack.config.js | WEBPACK_CONFIGS := webpack.config.js | ||||
WEBPACK_DEST := public/js/index.js public/css/index.css | WEBPACK_DEST := public/js/index.js public/css/index.css | ||||
WEBPACK_DEST_DIRS := public/js public/css public/fonts | |||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/serviceworker.js | |||||
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go | BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go | ||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) | BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) | ||||
.PHONY: clean-all | .PHONY: clean-all | ||||
clean-all: clean | clean-all: clean | ||||
rm -rf $(WEBPACK_DEST_DIRS) $(FOMANTIC_DEST_DIR) | |||||
rm -rf $(WEBPACK_DEST_ENTRIES) $(FOMANTIC_DEST_DIR) | |||||
.PHONY: clean | .PHONY: clean | ||||
clean: | clean: | ||||
.PHONY: watch-frontend | .PHONY: watch-frontend | ||||
watch-frontend: node_modules | watch-frontend: node_modules | ||||
rm -rf $(WEBPACK_DEST_ENTRIES) | |||||
NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress | NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress | ||||
.PHONY: test | .PHONY: test | ||||
webpack: $(WEBPACK_DEST) | webpack: $(WEBPACK_DEST) | ||||
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules | $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules | ||||
rm -rf $(WEBPACK_DEST_DIRS) | |||||
rm -rf $(WEBPACK_DEST_ENTRIES) | |||||
npx webpack --hide-modules --display-entrypoints=false | npx webpack --hide-modules --display-entrypoints=false | ||||
@touch $(WEBPACK_DEST) | @touch $(WEBPACK_DEST) | ||||
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/gitea-safari.svg" color="#609926"> | <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/gitea-safari.svg" color="#609926"> | ||||
<link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}"> | <link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}"> | ||||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"> | <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"> | ||||
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||||
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||||
{{if .RequireSimpleMDE}} | {{if .RequireSimpleMDE}} | ||||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css"> | <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css"> | ||||
{{end}} | {{end}} |
const {UseServiceWorker, AppSubUrl, AppVer} = window.config; | const {UseServiceWorker, AppSubUrl, AppVer} = window.config; | ||||
const cacheName = 'static-cache-v2'; | |||||
const cachePrefix = 'static-cache-v'; // actual version is set in the service worker script | |||||
async function unregister() { | async function unregister() { | ||||
for (const registration of await navigator.serviceWorker.getRegistrations()) { | |||||
const serviceWorker = registration.active; | |||||
if (!serviceWorker) continue; | |||||
registration.unregister(); | |||||
} | |||||
const registrations = await navigator.serviceWorker.getRegistrations(); | |||||
await Promise.all(registrations.map((registration) => { | |||||
return registration.active && registration.unregister(); | |||||
})); | |||||
} | } | ||||
async function invalidateCache() { | async function invalidateCache() { | ||||
await caches.delete(cacheName); | |||||
const cacheKeys = await caches.keys(); | |||||
await Promise.all(cacheKeys.map((key) => { | |||||
return key.startsWith(cachePrefix) && caches.delete(key); | |||||
})); | |||||
} | } | ||||
async function checkCacheValidity() { | async function checkCacheValidity() { | ||||
// invalidate cache if it belongs to a different gitea version | // invalidate cache if it belongs to a different gitea version | ||||
if (cacheKey && storedCacheKey !== cacheKey) { | if (cacheKey && storedCacheKey !== cacheKey) { | ||||
invalidateCache(); | |||||
await invalidateCache(); | |||||
localStorage.setItem('staticCacheKey', cacheKey); | localStorage.setItem('staticCacheKey', cacheKey); | ||||
} | } | ||||
} | } | ||||
if (!('serviceWorker' in navigator)) return; | if (!('serviceWorker' in navigator)) return; | ||||
if (UseServiceWorker) { | if (UseServiceWorker) { | ||||
await checkCacheValidity(); | |||||
try { | try { | ||||
await navigator.serviceWorker.register(`${AppSubUrl}/serviceworker.js`); | |||||
// normally we'd serve the service worker as a static asset from StaticUrlPrefix but | |||||
// the spec strictly requires it to be same-origin so it has to be AppSubUrl to work | |||||
await Promise.all([ | |||||
checkCacheValidity(), | |||||
navigator.serviceWorker.register(`${AppSubUrl}/serviceworker.js`), | |||||
]); | |||||
} catch (err) { | } catch (err) { | ||||
console.error(err); | console.error(err); | ||||
await invalidateCache(); | |||||
await unregister(); | |||||
await Promise.all([ | |||||
invalidateCache(), | |||||
unregister(), | |||||
]); | |||||
} | } | ||||
} else { | } else { | ||||
await invalidateCache(); | |||||
await unregister(); | |||||
await Promise.all([ | |||||
invalidateCache(), | |||||
unregister(), | |||||
]); | |||||
} | } | ||||
} | } |
} | } | ||||
}); | }); | ||||
// parallel init of lazy-loaded features | |||||
// parallel init of async loaded features | |||||
await Promise.all([ | await Promise.all([ | ||||
highlight(document.querySelectorAll('pre code')), | highlight(document.querySelectorAll('pre code')), | ||||
attachTribute(document.querySelectorAll('#content, .emoji-input')), | attachTribute(document.querySelectorAll('#content, .emoji-input')), |
const cacheName = 'static-cache-v2'; | const cacheName = 'static-cache-v2'; | ||||
// disable workbox debug logging in development, remove when debugging the service worker | |||||
self.__WB_DISABLE_DEV_LOGS = true; | |||||
// see https://developer.mozilla.org/en-US/docs/Web/API/RequestDestination for possible values | |||||
const cachedDestinations = new Set([ | const cachedDestinations = new Set([ | ||||
'font', | |||||
'manifest', | 'manifest', | ||||
'paintworklet', | |||||
'script', | 'script', | ||||
'sharedworker', | |||||
'style', | 'style', | ||||
'worker', | 'worker', | ||||
]); | ]); |