feat: pwa auto-update; fix WS hijack, DM names, tap reactions
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"messenger/internal/api"
|
"messenger/internal/api"
|
||||||
@@ -72,13 +73,26 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer index.Close()
|
defer index.Close()
|
||||||
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
http.ServeContent(w, r, "index.html", time.Time{}, index)
|
http.ServeContent(w, r, "index.html", time.Time{}, index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
setStaticCache(w, path)
|
||||||
http.ServeContent(w, r, path, time.Time{}, f)
|
http.ServeContent(w, r, path, time.Time{}, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setStaticCache lets hashed assets be cached forever while forcing the app
|
||||||
|
// shell, service worker and manifest to revalidate on every load.
|
||||||
|
func setStaticCache(w http.ResponseWriter, path string) {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(path, "/assets/"):
|
||||||
|
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||||||
|
case path == "/index.html" || path == "/sw.js" || path == "/manifest.webmanifest":
|
||||||
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func writeJSON(w http.ResponseWriter, status int, body any) {
|
func writeJSON(w http.ResponseWriter, status int, body any) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
|
|||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
import { StrictMode } from 'react'
|
import { StrictMode } from 'react'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import { registerSW } from 'virtual:pwa-register'
|
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import { AuthProvider } from './auth/AuthContext'
|
import { AuthProvider } from './auth/AuthContext'
|
||||||
|
import { setupPWA } from './pwa'
|
||||||
|
|
||||||
registerSW({ immediate: true })
|
setupPWA()
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
@@ -13,4 +13,4 @@ createRoot(document.getElementById('root')!).render(
|
|||||||
<App />
|
<App />
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { registerSW } from 'virtual:pwa-register'
|
||||||
|
|
||||||
|
let refreshing = false
|
||||||
|
|
||||||
|
const UPDATE_CHECK_INTERVAL_MS = 30 * 60 * 1000
|
||||||
|
|
||||||
|
// setupPWA registers the service worker and keeps the installed app fresh:
|
||||||
|
// it polls for updates and reloads once when a new worker takes control.
|
||||||
|
export function setupPWA(): void {
|
||||||
|
if (typeof navigator === 'undefined' || !('serviceWorker' in navigator)) return
|
||||||
|
|
||||||
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||||
|
if (refreshing) return
|
||||||
|
refreshing = true
|
||||||
|
window.location.reload()
|
||||||
|
})
|
||||||
|
|
||||||
|
registerSW({
|
||||||
|
immediate: true,
|
||||||
|
onRegisteredSW(_swUrl, registration) {
|
||||||
|
if (!registration) return
|
||||||
|
const check = () => {
|
||||||
|
void registration.update().catch(() => {})
|
||||||
|
}
|
||||||
|
// Installed PWAs stay open for days without navigation, so trigger
|
||||||
|
// update checks on a timer, on focus and when connectivity returns.
|
||||||
|
window.setInterval(check, UPDATE_CHECK_INTERVAL_MS)
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.visibilityState === 'visible') check()
|
||||||
|
})
|
||||||
|
window.addEventListener('online', check)
|
||||||
|
check()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user