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: 2 comments
-
|
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.
I've managed to get TanStack Start working with Serwist. I created a custom Vite plugin: