[{"data":1,"prerenderedAt":286},["ShallowReactive",2],{"navigation":3,"/blog/blooper-vite-pwa-ssr-redirects":130,"surround-blooper-vite-pwa-ssr-redirects":274},[4],{"title":5,"path":6,"stem":7,"children":8,"page":129},"Blog","/blog","blog",[9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":10,"path":11,"stem":12},"How to Increase Free Tier Memory on AWS EC2","/blog/aws-ec2-ram","blog/aws-ec2-ram",{"title":14,"path":15,"stem":16},"Blooper: The Disappearing Cloudflare Variables","/blog/blooper-cloudflare-env-vars","blog/blooper-cloudflare-env-vars",{"title":18,"path":19,"stem":20},"Blooper: Hardcoded Content Links cause 404s","/blog/blooper-hardcoded-nuxt-content-links","blog/blooper-hardcoded-nuxt-content-links",{"title":22,"path":23,"stem":24},"Blooper: The Invisible SEO","/blog/blooper-nuxt-seo-env","blog/blooper-nuxt-seo-env",{"title":26,"path":27,"stem":28},"Blooper: The SSR Crash of Doom","/blog/blooper-ssr-feedback-form","blog/blooper-ssr-feedback-form",{"title":30,"path":31,"stem":32},"Blooper: The YouTube Crawl Budget Killer","/blog/blooper-video-crawl-budget","blog/blooper-video-crawl-budget",{"title":34,"path":35,"stem":36},"Blooper: PWA Redirecting SPA Routes","/blog/blooper-vite-pwa-ssr-redirects","blog/blooper-vite-pwa-ssr-redirects",{"title":38,"path":39,"stem":40},"Disk Management in Linux","/blog/disk-management-in-linux","blog/disk-management-in-linux",{"title":42,"path":43,"stem":44},"Docker Devtools Stage | Powerlevel, OhMyZSH, tmux, fuzzy finder, autocomplete etc","/blog/docker-devtools","blog/docker-devtools",{"title":46,"path":47,"stem":48},"Docker container | Resolving Permission Denied Woes: A Decade-Long Struggle Unraveled","/blog/docker-non-root-user-perms","blog/docker-non-root-user-perms",{"title":50,"path":51,"stem":52},"Git commands | underrated","/blog/git-commands-underrated","blog/git-commands-underrated",{"title":54,"path":55,"stem":56},"Journey: Taming Edge Caching and KV Storage","/blog/journey-github-streak-caching","blog/journey-github-streak-caching",{"title":58,"path":59,"stem":60},"Kubernetes Cluster Setup Guide","/blog/k8s-setup","blog/k8s-setup",{"title":62,"path":63,"stem":64},"Linux WiFi Drivers","/blog/linux-wifi-drivers","blog/linux-wifi-drivers",{"title":66,"path":67,"stem":68},"pfSense basic firewall setup","/blog/pfsense-basic-firewall-setup","blog/pfsense-basic-firewall-setup",{"title":70,"path":71,"stem":72},"pfSense Quickstart","/blog/pfsense-quickstart","blog/pfsense-quickstart",{"title":74,"path":75,"stem":76},"Postmortem: Cloudflare Worker Missing Dependency on Deploy","/blog/postmortem-cloudflare-worker-dependency-deploy","blog/postmortem-cloudflare-worker-dependency-deploy",{"title":78,"path":79,"stem":80},"Postmortem: Serverless HTTP Driver Transaction Failures","/blog/postmortem-neon-http-transactions","blog/postmortem-neon-http-transactions",{"title":82,"path":83,"stem":84},"Postmortem: Nuxt Content 404s on Staging Deployments","/blog/postmortem-nuxt-content-404-staging","blog/postmortem-nuxt-content-404-staging",{"title":86,"path":87,"stem":88},"Postmortem: 500 Internal Server Error on ISR Routes","/blog/postmortem-nuxt-content-payload-extraction","blog/postmortem-nuxt-content-payload-extraction",{"title":90,"path":91,"stem":92},"Post-Mortem: Intrusive Database Driver Refactoring","/blog/postmortem-proxy-re-architecting","blog/postmortem-proxy-re-architecting",{"title":94,"path":95,"stem":96},"Post-Mortem: Cloudflare Worker Connection Hang & Resilient DB Fallbacks","/blog/postmortem-worker-db-connection-hang","blog/postmortem-worker-db-connection-hang",{"title":98,"path":99,"stem":100},"Pro Tip: Sandboxing Cloudflare Workers for AI Agents","/blog/pro-tip-wrangler-local-dev-trick","blog/pro-tip-wrangler-local-dev-trick",{"title":102,"path":103,"stem":104},"Proxmox DNS Management","/blog/proxmox-dns","blog/proxmox-dns",{"title":106,"path":107,"stem":108},"Proxmox Recovery","/blog/proxmox-recovery","blog/proxmox-recovery",{"title":110,"path":111,"stem":112},"Proxmox WiFi Connection Story","/blog/proxmox-wifi","blog/proxmox-wifi",{"title":114,"path":115,"stem":116},"roadauth-rails api jwt cors","/blog/rodauth-jwt","blog/rodauth-jwt",{"title":118,"path":119,"stem":120},"SOCKS5 Proxy Quickstart","/blog/sock5-proxy","blog/sock5-proxy",{"title":122,"path":123,"stem":124},"tmux status bar toggle","/blog/tmux-status","blog/tmux-status",{"title":126,"path":127,"stem":128},"UFW - Cheatsheet","/blog/ufw-cheatsheet","blog/ufw-cheatsheet",false,{"id":131,"title":34,"authors":132,"badge":138,"body":140,"date":263,"description":264,"extension":265,"image":266,"imageComponent":267,"meta":268,"navigation":269,"path":35,"pinned":129,"seo":270,"seoImage":271,"stem":36,"__hash__":273},"posts/blog/blooper-vite-pwa-ssr-redirects.md",[133],{"name":134,"to":135,"avatar":136},"Rahul Dhole","/",{"src":137},"/profile.png",{"label":139},"Blooper",{"type":141,"value":142,"toc":257},"minimark",[143,148,164,168,183,197,201,204,250,253],[144,145,147],"h2",{"id":146},"issue","Issue",[149,150,151,152,156,157,160,161,163],"p",{},"Reloading SPA pages (like a ",[153,154,155],"code",{},"/dashboard"," or ",[153,158,159],{},"/profile"," route) in production unexpectedly redirected the user back to the home page ",[153,162,135],{},". Local development worked perfectly fine without any redirects.",[144,165,167],{"id":166},"root-cause","Root Cause",[149,169,170,171,173,174,176,177,182],{},"Vite PWA intercepted the navigation requests in production and fell back to serving the cached ",[153,172,135],{}," HTML. Since the framework hydrated with the root page's state on a different URL, the router detected a state mismatch and forcefully redirected the user back to ",[153,175,135],{}," (",[178,179,181],"a",{"href":180},"#fig-1","Figure 1",").",[149,184,185,188,193],{},[178,186],{"id":187},"fig-1",[189,190],"mermaid",{":config":191,"code":192},"config","flowchart%20TD%0A%20%20%20%20A%5BUser%20visits%20%2Fdashboard%5D%20--%3E%20B(PWA%20Service%20Worker%20intercepts)%0A%20%20%20%20B%20--%3E%20C%7BHas%20%2Fdashboard%20cache%3F%7D%0A%20%20%20%20C%20--%20No%20--%3E%20D%5BPWA%20Fallback%20to%20%2F%20HTML%5D%0A%20%20%20%20D%20--%3E%20E%5BClient%20hydrates%20with%20%2F%20state%5D%0A%20%20%20%20E%20--%3E%20F%5BRouter%20detects%20URL%20mismatch%5D%0A%20%20%20%20F%20--%3E%20G%5BForce%20Redirect%20to%20%2F%5D%0A%20%20%20%20G%20--%3E%20H((User%20confused))",[194,195,196],"em",{},"Figure 1: PWA navigation fallback redirect loop",[144,198,200],{"id":199},"resolution","Resolution",[149,202,203],{},"Disabled the PWA navigation fallback in the configuration:",[205,206,211],"pre",{"className":207,"code":208,"language":209,"meta":210,"style":210},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pwa: { workbox: { navigateFallback: null } }\n","ts","",[153,212,213],{"__ignoreMap":210},[214,215,218,222,226,229,232,234,236,239,241,244,247],"span",{"class":216,"line":217},"line",1,[214,219,221],{"class":220},"sBMFI","pwa",[214,223,225],{"class":224},"sMK4o",":",[214,227,228],{"class":224}," {",[214,230,231],{"class":220}," workbox",[214,233,225],{"class":224},[214,235,228],{"class":224},[214,237,238],{"class":220}," navigateFallback",[214,240,225],{"class":224},[214,242,243],{"class":224}," null",[214,245,246],{"class":224}," }",[214,248,249],{"class":224}," }\n",[149,251,252],{},"This lets the server environment handle navigations naturally and generate SPA shells for client-side only routes.",[254,255,256],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":210,"searchDepth":258,"depth":258,"links":259},2,[260,261,262],{"id":146,"depth":258,"text":147},{"id":166,"depth":258,"text":167},{"id":199,"depth":258,"text":200},"2026-06-23","How Vite PWA intercepted navigation requests in production and caused redirect loops.","md",null,{"type":139},{},true,{"title":34,"description":264},{"src":272},"https://placehold.co/800x400/0f172a/3b82f6?text=PWA+Redirecting+SPA+Routes","wsf7n3VcShZgOAbbmvN5WkyuefWVFl8mYTS51167_bU",[275,280],{"title":30,"path":31,"stem":32,"description":276,"imageComponent":277,"seoImage":278,"children":-1},"How server-rendered YouTube iframes destroyed our SEO crawl budget.",{"type":139},{"src":279},"https://placehold.co/800x400/0f172a/3b82f6?text=Crawl+Budget+Killer",{"title":38,"path":39,"stem":40,"description":281,"imageComponent":282,"seoImage":284,"children":-1},"Disk Management in Linux - Dive into the details of disk management in linux with this quick guide.",{"type":283},"Linux",{"src":285},"https://placehold.co/800x400/0f172a/3b82f6?text=Disk+Management+in+Linux",1784464468316]