T
TanStack4mo ago
national-gold

vite-pwa plugin does not work in production builds

dev-sw.js works, but the core issue is that sw.js doesn't get built in prod output. is that possible that rollup might be causing the issue? if so, how to ignore that during the build. here's my repo with a workaround: https://github.com/kulterryan/tanstack-start-pwa
GitHub
GitHub - kulterryan/tanstack-start-pwa
Contribute to kulterryan/tanstack-start-pwa development by creating an account on GitHub.
24 Replies
fair-rose
fair-rose4mo ago
from my (and gpt5's) investigation i believe vite-plugin-pwa doesn't work[1] due to the way it detects the server/client vite environment, doesn't seem to be properly fixed for multi-environment and even when I manually edited the package, couldn't figure out a proper way to get the worker to build somewhere other than dist/sw.js[2] [1]: "doesn't work" meaning that the plugin is seemingly not executed when running vite build with VitePWA() and tanstackStart() both present. as soon as you comment out the tanstackStart() plugin, the service worker gets generated to dist/sw.js and the assets generator runs if configured. which convinced me it was some environment detection/compatability issue [2]: this might just be due to my inexperience with configuring vite, and I didn't want to use a copy script. either way the ideal behaviour is that the sw gets built into tanstack start's client-dist, so it can also get picked up by nitro publicAssets[]
fair-rose
fair-rose4mo ago
https://github.com/vite-pwa/vite-plugin-pwa/blob/4385f0a7f03b628ca0d635c07042a1031631ffb4/src/plugins/build.ts#L44 this.environment.config.consumer might be required rather than just checking for PWAPluginContext.viteConfig.build.ssr (not too sure)
GitHub
vite-plugin-pwa/src/plugins/build.ts at 4385f0a7f03b628ca0d635c0704...
Zero-config PWA for Vite. Contribute to vite-pwa/vite-plugin-pwa development by creating an account on GitHub.
fair-rose
fair-rose4mo ago
my temporary solution was a bit different i ended up making a custom script using esbuild and workbox injectManifest, which runs through a vite plugin after client build, but before server (so it gets copied to nitro static assets)
//workbox-generate.ts
import { injectManifest } from 'workbox-build'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { build } from 'esbuild'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

export async function workboxGenerate(buildId: string) {
const clientDist = resolve(__dirname, '.tanstack/start/build/client-dist')
const swDest = resolve(clientDist, 'sw.js')
const swImplDest = resolve(clientDist, 'sw.module.js')

// sw.module includes exports so the browser doesn't refetch workbox when comparing sw.js versions
await build({
entryPoints: [resolve(__dirname, 'src/sw.module.ts')],
bundle: true,
outfile: swImplDest,
format: 'iife',
target: 'es2020',
minify: true,
define: {
'import.meta.env.DEV': 'false'
}
})

// includes importScripts(sw.module.js)
await build({
entryPoints: [resolve(__dirname, 'src/sw.ts')],
bundle: true,
outfile: swDest,
format: 'esm',
target: 'es2020',
minify: true,
define: {
'import.meta.env.DEV': 'false',
'self.__WB_BUILD_ID': `"${buildId}"`
}
})

// could have used generateSW and skipped the esbuild stages, I just needed more customisability
const { count, warnings, size } = await injectManifest({
swSrc: swDest,
swDest: swDest,
globDirectory: clientDist,
globPatterns: [
'**/*.{js,css,html,svg,png,ico,webmanifest,json}',
],
});

if (warnings.length) {
console.warn('[workbox] warnings:', warnings)
}
console.log(`[workbox] generated sw.js with ${count} precached files (${(size/1024).toFixed(1)} KiB)`)
}
//workbox-generate.ts
import { injectManifest } from 'workbox-build'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { build } from 'esbuild'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

export async function workboxGenerate(buildId: string) {
const clientDist = resolve(__dirname, '.tanstack/start/build/client-dist')
const swDest = resolve(clientDist, 'sw.js')
const swImplDest = resolve(clientDist, 'sw.module.js')

// sw.module includes exports so the browser doesn't refetch workbox when comparing sw.js versions
await build({
entryPoints: [resolve(__dirname, 'src/sw.module.ts')],
bundle: true,
outfile: swImplDest,
format: 'iife',
target: 'es2020',
minify: true,
define: {
'import.meta.env.DEV': 'false'
}
})

// includes importScripts(sw.module.js)
await build({
entryPoints: [resolve(__dirname, 'src/sw.ts')],
bundle: true,
outfile: swDest,
format: 'esm',
target: 'es2020',
minify: true,
define: {
'import.meta.env.DEV': 'false',
'self.__WB_BUILD_ID': `"${buildId}"`
}
})

// could have used generateSW and skipped the esbuild stages, I just needed more customisability
const { count, warnings, size } = await injectManifest({
swSrc: swDest,
swDest: swDest,
globDirectory: clientDist,
globPatterns: [
'**/*.{js,css,html,svg,png,ico,webmanifest,json}',
],
});

if (warnings.length) {
console.warn('[workbox] warnings:', warnings)
}
console.log(`[workbox] generated sw.js with ${count} precached files (${(size/1024).toFixed(1)} KiB)`)
}
vite plugin:
{
name: "workbox",
applyToEnvironment(e) {
return e.name === "ssr"; // runs after client is done generating, but before the nitro server copies publicAssets[] so that injectManifest can glob on static assets properly
},
buildStart: () => workboxGenerate(buildId),
},
{
name: "workbox",
applyToEnvironment(e) {
return e.name === "ssr"; // runs after client is done generating, but before the nitro server copies publicAssets[] so that injectManifest can glob on static assets properly
},
buildStart: () => workboxGenerate(buildId),
},
and then just loaded it with workbox-window in __root.tsx but generally PWA support and also the pwa plugin need some work it seems
stormy-gold
stormy-gold4mo ago
is the pwa vite plugin supporting vite's env api?
fair-rose
fair-rose4mo ago
i don't think so
stormy-gold
stormy-gold4mo ago
start is fully based on the env api. so would need that pwa plugin to support that most likely
fair-rose
fair-rose4mo ago
oh looks like there is a PR
fair-rose
fair-rose4mo ago
GitHub
feat!: add Vite 6 Environment API support by userquin · Pull Reque...
Description 2024-11-15: this PR only tested with VanillaJS/TypeScript via test:vite-ecosystem-ci script, rn cannot be tested with lib frameworks, Vite ecosystem-ci is failing for vue and svelte (p...
stormy-gold
stormy-gold4mo ago
nice
fair-rose
fair-rose4mo ago
hm
No description
stormy-gold
stormy-gold4mo ago
can you test the pkr-new preview build?
fair-rose
fair-rose4mo ago
sure, gimme a sec
stormy-gold
stormy-gold4mo ago
this might still need some work but it would be good to know the state of it
fair-rose
fair-rose4mo ago
looks like a similiar situation dev-sw.js works in dev server but no pwa/sw steps are ran in build
fair-rose
fair-rose4mo ago
No description
fair-rose
fair-rose4mo ago
working in dev though
No description
stormy-gold
stormy-gold4mo ago
can you please check whether we have an open issue about this already on github? if yes, please add your findings there, otherwise create a new one.
fair-rose
fair-rose4mo ago
i believe there isn't
stormy-gold
stormy-gold4mo ago
i expect the prod issue to be resolvable with vite 7 as it adds a new buildApp hook for the env api which the plugin should register to build its own env. we should be able to upstream this to the pwa plugin then
fair-rose
fair-rose4mo ago
just to doublecheck, it is the router repo right (possibly silly question)
stormy-gold
stormy-gold4mo ago
yes router repo
fair-rose
fair-rose4mo ago
GitHub
vite-plugin-pwa incompatible with tanstack start production builds ...
Which project does this relate to? Start Describe the bug vite-plugin-pwa's build steps (generate assets, generate serviceworker bundle) are seemingly not executed when running vite build with ...
national-gold
national-goldOP4mo ago
Found this for PWA, might be helpful. https://serwist.pages.dev/docs/vite/getting-started
Getting started - @serwist/vite - Serwist
A Swiss Army knife for service workers.
passive-yellow
passive-yellow4mo ago
I modified the Astro intergration vite-pwa has and it works like a charm, even though it's not clean

Did you find this page helpful?