Precache service worker

Is there any way to implement service worker for content precaching? For context I'm creating a website with a midi player. It would be great to precache large (1 to 21 MB ish) SoundFont files. I've tried using VitePWA plugin in Vinxi. It doesn't appear to register any service workers though. app.config.ts:
import { defineConfig } from '@solidjs/start/config'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
vite: {
...
plugins: [
VitePWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{ico,png,svg,jpg,webp,sf3,wasm}'],
},
}),
],
},
...
})
import { defineConfig } from '@solidjs/start/config'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
vite: {
...
plugins: [
VitePWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{ico,png,svg,jpg,webp,sf3,wasm}'],
},
}),
],
},
...
})
9 Replies
bigmistqke
bigmistqke4mo ago
i was looking for that the other day but couldn't find anything either, so i wrote my own rollup plugin to get the job done: https://github.com/bigmistqke/repl/tree/main/src/plugins/rollup-service-worker mb u can adapt this to ur needs
GitHub
repl/src/plugins/rollup-service-worker at main · bigmistqke/repl
🗒️ Unstyled building blocks to compose typescript playgrounds ⚡ Powered by solid-js with integrations for monaco-editor. - bigmistqke/repl
bigmistqke
bigmistqke4mo ago
haven't checked out if it works with solid-start tho, just regular vite project.
Mango Juicy
Mango JuicyOP4mo ago
Fascinating. I guess worst case scenario, I'll have to write it directly into html or separate ts file
bigmistqke
bigmistqke4mo ago
yes exactly that's basically what the plugin does 1 other aspect that is critical is that the location of the service-worker is in the root of the build.
Mango Juicy
Mango JuicyOP4mo ago
Yeah, otherwise the precaching doesn't work properly?
bigmistqke
bigmistqke4mo ago
yes exactly i didn't know personally 🙂 was really surprised by that fact
Mango Juicy
Mango JuicyOP4mo ago
I ran into that problem once with an astro and solid js app Honestly I think it makes more sense to only use one framework
bigmistqke
bigmistqke4mo ago
ye, it's like something you have to figure out by doing it wrong first. very unintuitive. i suppose it is a security measure or something true, astro s cool tho.
Mango Juicy
Mango JuicyOP4mo ago
As a basic solution this is what I have in the sw.js file in public
const monthMillis = 1000 * 60 * 60 * 24 * 30

// Precache large files - 1 Month
const PRECACHE_VERSION = `precache-v${Math.floor(Date.now() / monthMillis)}`
const PRECACHE_URLS = [
'/fluidsynth/fluidsynth.js',
'/fluidsynth/synth.min.js',
'/fluidsynth/synth.worklet.min.js',
'/piano.sf3',
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches
.open(PRECACHE_VERSION)
.then((cache) => cache.addAll(PRECACHE_URLS))
.then(self.skipWaiting()),
)
})
const monthMillis = 1000 * 60 * 60 * 24 * 30

// Precache large files - 1 Month
const PRECACHE_VERSION = `precache-v${Math.floor(Date.now() / monthMillis)}`
const PRECACHE_URLS = [
'/fluidsynth/fluidsynth.js',
'/fluidsynth/synth.min.js',
'/fluidsynth/synth.worklet.min.js',
'/piano.sf3',
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches
.open(PRECACHE_VERSION)
.then((cache) => cache.addAll(PRECACHE_URLS))
.then(self.skipWaiting()),
)
})
The service worker can be loaded in entry-client.tsx
import { StartClient, mount } from '@solidjs/start/client'

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', { scope: '/' }).then(
(registration) => {
console.log('Service worker registration succeeded:', registration)
},
(error) => {
console.error(`Service worker registration failed: ${error}`)
},
)
} else {
console.error('Service workers are not supported.')
}

mount(() => <StartClient />, document.getElementById('app')!)
import { StartClient, mount } from '@solidjs/start/client'

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', { scope: '/' }).then(
(registration) => {
console.log('Service worker registration succeeded:', registration)
},
(error) => {
console.error(`Service worker registration failed: ${error}`)
},
)
} else {
console.error('Service workers are not supported.')
}

mount(() => <StartClient />, document.getElementById('app')!)
As for busting previous cache versions in sw.js
// Update and bust old caches
self.addEventListener('activate', (event) => {
const currentCaches = [PRECACHE_VERSION, RUNCACHE_VERSION]
event.waitUntil(
caches
.keys()
.then((cacheNames) => {
return cacheNames.filter((cacheName) => !currentCaches.includes(cacheName))
})
.then((cachesToDelete) => {
return Promise.all(
cachesToDelete.map((cacheToDelete) => {
return caches.delete(cacheToDelete)
}),
)
})
.then(() => self.clients.claim()),
)
})
// Update and bust old caches
self.addEventListener('activate', (event) => {
const currentCaches = [PRECACHE_VERSION, RUNCACHE_VERSION]
event.waitUntil(
caches
.keys()
.then((cacheNames) => {
return cacheNames.filter((cacheName) => !currentCaches.includes(cacheName))
})
.then((cachesToDelete) => {
return Promise.all(
cachesToDelete.map((cacheToDelete) => {
return caches.delete(cacheToDelete)
}),
)
})
.then(() => self.clients.claim()),
)
})
Unfortunately this is quite verbose. The ideal solution would probably be some sort of Vinxi plugin with Workbox solution
Want results from more Discord servers?
Add your server