SvelteKit
WARNING
From version v0.2.0
, SvelteKitPWA
plugin requires SvelteKit 1.3.1 or above.
If you're using a SvelteKit
version prior to v1.3.1
, you should use SvelteKitPWA
plugin version 0.1.*
.
TIP
From version ^0.1.0
, SvelteKitPWA
has SvelteKit ^1.0.0
as peer dependency.
INFO
For Type declarations
, Prompt for update
and Periodic SW Updates
go to Svelte entry.
TIP
If you're using 0.1.*
version of SvelteKitPWA
, you should remove all references to SvelteKit service worker module to disable it on your application.
Generate Custom Service Worker
From version 0.2.0
, SvelteKitPWA
plugin will delegate your custom service worker build to SvelteKit
, and so by default you will be expected to put your service worker in src/service-worker.js
. If you would like, you can use a custom file location by changing the corresponding SvelteKit option:
// svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
files: {
serviceWorker: 'src/my-sw.js', // or `src/my-sw.ts`
}
}
};
export default config;
// svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
files: {
serviceWorker: 'src/my-sw.js', // or `src/my-sw.ts`
}
}
};
export default config;
Then in your Vite config file:
// vite.config.js or vite.config.ts
/** @type {import('vite').UserConfig} */
const config = {
plugins: [
sveltekit(),
SvelteKitPWA({
strategies: 'injectManifest',
srcDir: 'src',
filename: 'my-sw.js', // or `my-sw.ts`
/* other pwa options */
})
],
};
export default config;
// vite.config.js or vite.config.ts
/** @type {import('vite').UserConfig} */
const config = {
plugins: [
sveltekit(),
SvelteKitPWA({
strategies: 'injectManifest',
srcDir: 'src',
filename: 'my-sw.js', // or `my-sw.ts`
/* other pwa options */
})
],
};
export default config;
You can check SvelteKit docs for more information about service workers.
You will need to exclude the service worker registration from the SvelteKit
configuration if you're using any pwa virtual module (virtual:pwa-register
or virtual:pwa-register/svelte
):
// svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
plugins: {
serviceWorker: {
register: false
}
}
};
export default config;
// svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
plugins: {
serviceWorker: {
register: false
}
}
};
export default config;
WARNING
If your custom service working is importing any workbox-*
module (workbox-routing
, workbox-strategies
, etc), you will need to hack Vite build process in order to remove non ESM
special replacements from the build process (if you don't include p
, the service worker will not be registered). You only need to add this entry in your Vite config file:
// vite.config.js or vite.config.ts
/** @type {import('vite').UserConfig} */
const config = {
define: {
'process.env.NODE_ENV ': process.env.NODE_ENV === 'production'
? '"production"'
: '"development"'
}
};
export default config;
// vite.config.js or vite.config.ts
/** @type {import('vite').UserConfig} */
const config = {
define: {
'process.env.NODE_ENV ': process.env.NODE_ENV === 'production'
? '"production"'
: '"development"'
}
};
export default config;
SvelteKit PWA Plugin
vite-plugin-pwa
provides the new SvelteKitPWA
plugin that will allow you to use vite-plugin-pwa
in your SvelteKit applications.
You will need to install SvelteKitPWA
using:
pnpm add -D @vite-pwa/sveltekit
pnpm add -D @vite-pwa/sveltekit
To update your project to use the new vite-plugin-pwa
for SvelteKit, you only need to change the Vite config file (you don't need oldest pwa
and pwa-configuration
modules):
// vite.config.js / vite.config.ts
import { SvelteKitPWA } from '@vite-pwa/sveltekit'
/** @type {import('vite').UserConfig} */
const config = {
plugins: [
sveltekit(),
SvelteKitPWA({/* pwa options */})
],
}
export default config
// vite.config.js / vite.config.ts
import { SvelteKitPWA } from '@vite-pwa/sveltekit'
/** @type {import('vite').UserConfig} */
const config = {
plugins: [
sveltekit(),
SvelteKitPWA({/* pwa options */})
],
}
export default config
SvelteKit PWA Plugin Options
SvelteKit PWA Plugin options
import type { VitePWAOptions } from 'vite-plugin-pwa'
export interface KitOptions {
/**
* The base path for your application: by default will use the Vite base.
*
* @deprecated since ^0.1.0 version, the plugin has SvelteKit ^1.0.0 as peer dependency, Vite's base is now properly configured.
* @default '/'
* @see https://kit.svelte.dev/docs/configuration#paths
*/
base?: string
/**
* @default '.svelte-kit'
* @see https://kit.svelte.dev/docs/configuration#outdir
*/
outDir?: string
/**
* @see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#fallback
*/
adapterFallback?: string
/**
* @default 'never'
* @see https://kit.svelte.dev/docs/configuration#trailingslash
*/
trailingSlash?: 'never' | 'always' | 'ignore'
}
export interface SvelteKitPWAOptions extends Partial<VitePWAOptions> {
kit?: KitOptions
}
import type { VitePWAOptions } from 'vite-plugin-pwa'
export interface KitOptions {
/**
* The base path for your application: by default will use the Vite base.
*
* @deprecated since ^0.1.0 version, the plugin has SvelteKit ^1.0.0 as peer dependency, Vite's base is now properly configured.
* @default '/'
* @see https://kit.svelte.dev/docs/configuration#paths
*/
base?: string
/**
* @default '.svelte-kit'
* @see https://kit.svelte.dev/docs/configuration#outdir
*/
outDir?: string
/**
* @see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#fallback
*/
adapterFallback?: string
/**
* @default 'never'
* @see https://kit.svelte.dev/docs/configuration#trailingslash
*/
trailingSlash?: 'never' | 'always' | 'ignore'
}
export interface SvelteKitPWAOptions extends Partial<VitePWAOptions> {
kit?: KitOptions
}
SvelteKit Pages
If you want your application to work offline, you should ensure you have not set csr: false
on any of your pages since it will prevent injecting JavaScript into the layout for offline support.
Auto Update
Since SvelteKit uses SSR/SSG, we need to call the vite-plugin-pwa
virtual module using a dynamic import
.
The best place to include the virtual call will be in main layout of the application (you should register it in any layout):
src/routes/+layout.svelte
<script>
import { onMount } from 'svelte'
import { pwaInfo } from 'virtual:pwa-info'
onMount(async () => {
if (pwaInfo) {
const { registerSW } = await import('virtual:pwa-register')
registerSW({
immediate: true,
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`)
},
onRegisterError(error) {
console.log('SW registration error', error)
}
})
}
})
$: webManifest = pwaInfo ? pwaInfo.webManifest.linkTag : ''
</script>
<svelte:head>
{@html webManifest}
</svelte:head>
<main>
<slot />
</main>
<script>
import { onMount } from 'svelte'
import { pwaInfo } from 'virtual:pwa-info'
onMount(async () => {
if (pwaInfo) {
const { registerSW } = await import('virtual:pwa-register')
registerSW({
immediate: true,
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`)
},
onRegisterError(error) {
console.log('SW registration error', error)
}
})
}
})
$: webManifest = pwaInfo ? pwaInfo.webManifest.linkTag : ''
</script>
<svelte:head>
{@html webManifest}
</svelte:head>
<main>
<slot />
</main>
Prompt for update
Since SvelteKit uses SSR/SSG, we need to add the ReloadPrompt
component using a dynamic import
.
The best place to include the ReloadPrompt
component will be in main layout of the application (you should register it in any layout):
src/routes/+layout.svelte
<script>
import { onMount } from 'svelte'
import { pwaInfo } from 'virtual:pwa-info'
let ReloadPrompt
onMount(async () => {
pwaInfo && (ReloadPrompt = (await import('$lib/ReloadPrompt.svelte')).default)
})
$: webManifest = pwaInfo ? pwaInfo.webManifest.linkTag : ''
</script>
<svelte:head>
{@html webManifest}
</svelte:head>
<main>
<slot />
</main>
{#if ReloadPrompt}
<svelte:component this={ReloadPrompt} />
{/if}
<script>
import { onMount } from 'svelte'
import { pwaInfo } from 'virtual:pwa-info'
let ReloadPrompt
onMount(async () => {
pwaInfo && (ReloadPrompt = (await import('$lib/ReloadPrompt.svelte')).default)
})
$: webManifest = pwaInfo ? pwaInfo.webManifest.linkTag : ''
</script>
<svelte:head>
{@html webManifest}
</svelte:head>
<main>
<slot />
</main>
{#if ReloadPrompt}
<svelte:component this={ReloadPrompt} />
{/if}
$lib/ReloadPrompt.svelte
<script lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/svelte'
const {
needRefresh,
updateServiceWorker,
offlineReady
} = useRegisterSW({
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`)
},
onRegisterError(error) {
console.log('SW registration error', error)
},
})
const close = () => {
offlineReady.set(false)
needRefresh.set(false)
}
$: toast = $offlineReady || $needRefresh
</script>
{#if toast}
<div class="pwa-toast" role="alert">
<div class="message">
{#if $offlineReady}
<span>
App ready to work offline
</span>
{:else}
<span>
New content available, click on reload button to update.
</span>
{/if}
</div>
{#if $needRefresh}
<button on:click={() => updateServiceWorker(true)}>
Reload
</button>
{/if}
<button on:click={close}>
Close
</button>
</div>
{/if}
<style>
.pwa-toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 2;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
background-color: white;
}
.pwa-toast .message {
margin-bottom: 8px;
}
.pwa-toast button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
</style>
<script lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/svelte'
const {
needRefresh,
updateServiceWorker,
offlineReady
} = useRegisterSW({
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`)
},
onRegisterError(error) {
console.log('SW registration error', error)
},
})
const close = () => {
offlineReady.set(false)
needRefresh.set(false)
}
$: toast = $offlineReady || $needRefresh
</script>
{#if toast}
<div class="pwa-toast" role="alert">
<div class="message">
{#if $offlineReady}
<span>
App ready to work offline
</span>
{:else}
<span>
New content available, click on reload button to update.
</span>
{/if}
</div>
{#if $needRefresh}
<button on:click={() => updateServiceWorker(true)}>
Reload
</button>
{/if}
<button on:click={close}>
Close
</button>
</div>
{/if}
<style>
.pwa-toast {
position: fixed;
right: 0;
bottom: 0;
margin: 16px;
padding: 12px;
border: 1px solid #8885;
border-radius: 4px;
z-index: 2;
text-align: left;
box-shadow: 3px 4px 5px 0 #8885;
background-color: white;
}
.pwa-toast .message {
margin-bottom: 8px;
}
.pwa-toast button {
border: 1px solid #8885;
outline: none;
margin-right: 5px;
border-radius: 2px;
padding: 3px 10px;
}
</style>
SvelteKit and Adapters
If you set certain SvelteKit options, you should also configure the PWA plugin properly using the kit
option: