TanstackStart + PWA #4770
-
|
Any success story on getting vite-plugin-pwa or Serwist working with TanstackStart? Before de-vinxi-fication at version 1.121 I managed to get Serwist working by adjusting here is the repo with vite-plugin-pwa: |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
|
I don't know enough about how vite handles plugins, but Tanstack Start plugin seems to replace vite-plugin-pwa's build step. I've been attempting it too, and it's looking like it's simply not supported at the moment. |
Beta Was this translation helpful? Give feedback.
-
|
I've managed to get TanStack Start working with Serwist. I created a custom Vite plugin: import path from 'node:path'
import { injectManifest } from '@serwist/build'
import type { Plugin } from 'vite'
import { build } from 'vite'
/**
* Custom Serwist plugin for TanStack Start
* Builds service worker in both dev and production modes
*/
export function tanstackSerwistPlugin(): Plugin {
let rootDir: string
let isProduction: boolean
return {
name: 'tanstack-serwist',
configResolved(config) {
rootDir = config.root
isProduction = config.isProduction
},
async buildStart() {
// Build service worker in dev mode
if (!isProduction) {
await buildServiceWorker(rootDir, false)
}
},
async closeBundle() {
// Build service worker in production mode
if (isProduction) {
await buildServiceWorker(rootDir, true)
}
},
}
}
async function buildServiceWorker(rootDir: string, production: boolean) {
const outName = 'sw.js'
const outDir = production
? path.resolve(rootDir, 'dist', 'client')
: path.resolve(rootDir, 'public')
const swSrc = path.resolve(rootDir, 'src', 'sw.ts')
const swDest = path.resolve(outDir, outName)
const env = production ? 'production' : 'dev'
console.log(`\n🔧 [SERWIST] Building service worker (${env})...`)
try {
// Step 1: Bundle the service worker with Vite
await build({
root: rootDir,
configFile: false,
define: {
'process.env.NODE_ENV': JSON.stringify(
production ? 'production' : 'development',
),
},
build: {
lib: {
entry: swSrc,
formats: ['es'],
fileName: () => outName,
},
outDir,
emptyOutDir: false,
minify: production,
rollupOptions: {
output: {
entryFileNames: outName,
},
},
},
logLevel: 'error',
})
// Step 2: Inject the precache manifest (only in production)
if (production) {
const result = await injectManifest({
swSrc: swDest,
swDest,
globDirectory: outDir,
globPatterns: ['**/*.{js,css,html,png,svg,ico,webmanifest,woff,woff2}'],
injectionPoint: 'self.__SW_MANIFEST',
})
const cacheSize = (result.size / 1024 / 1024).toFixed(2)
console.log(
`✅ [SERWIST] Precached ${result.count} files (${cacheSize} MB)`,
)
} else {
console.log('✅ [SERWIST] Dev service worker built')
}
} catch (error) {
console.error('❌ [SERWIST] Failed to build service worker:', error)
throw error
}
}Load the plugin in your Vite config. Then register the Service Worker in your app: import { Serwist } from '@serwist/window'
function RootComponent() {
useEffect(() => {
const registerServiceWorker = async () => {
if ('serviceWorker' in navigator) {
const serwist = new Serwist('/sw.js', { scope: '/', type: 'module' })
await serwist.register()
}
}
registerServiceWorker().catch(console.error)
}, [])
return (
<RootDocument>
<Outlet />
</RootDocument>
)
}Create your Service Worker file import type { PrecacheEntry, SerwistGlobalConfig } from 'serwist'
import { Serwist } from 'serwist'
declare global {
interface WorkerGlobalScope extends SerwistGlobalConfig {
__SW_MANIFEST: (PrecacheEntry | string)[] | undefined
}
}
declare const self: ServiceWorkerGlobalScope
const serwist = new Serwist({
precacheEntries: self.__SW_MANIFEST,
skipWaiting: true,
clientsClaim: true,
navigationPreload: true,
})
serwist.addEventListeners() |
Beta Was this translation helpful? Give feedback.
-
|
Additionally, if you are using Nitro 3, you need to change outDir in buildServiceWorker. If you don't do this, after the build Nitro will ignore the file and it won't make it into the final build. async function buildServiceWorker(rootDir: string, production: boolean) {
const outName = 'sw.js'
const outDir = production
? path.resolve(rootDir, ".output", "public")
: path.resolve(rootDir, "public");
// ...
} |
Beta Was this translation helpful? Give feedback.
I've managed to get TanStack Start working with Serwist. I created a custom Vite plugin: