Service workers
Service workers act as proxy servers that handle network requests inside your app. This makes it possible to make your app work offline, but even if you don't need offline support (or can't realistically implement it because of the type of app you're building), it's often worth using service workers to speed up navigation by precaching your built JS and CSS.
In SvelteKit, if you have a src/service-worker.js file (or src/service-worker/index.js) it will be bundled and automatically registered.
You can disable automatic registration if you need to register the service worker with your own logic or use another solution. The default registration looks something like this:
if ('serviceWorker' in var navigator: NavigatorThe Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
navigator) {
function addEventListener<"load">(type: "load", listener: (this: Window, ev: Event) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)addEventListener('load', function () {
var navigator: NavigatorThe Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
navigator.Navigator.serviceWorker: ServiceWorkerContainerThe serviceWorker read-only property of the Navigator interface returns the ServiceWorkerContainer object for the associated document, which provides access to registration, removal, upgrade, and communication with the ServiceWorker.
Available only in secure contexts.
serviceWorker.ServiceWorkerContainer.register(scriptURL: string | URL, options?: RegistrationOptions): Promise<ServiceWorkerRegistration>The register() method of the ServiceWorkerContainer interface creates or updates a ServiceWorkerRegistration for the given scope.
register('./path/to/service-worker.js');
});
}Inside the service worker
Inside the service worker you have access to the $service-worker module, which provides you with the paths to all static assets, build files and prerendered pages. You're also provided with an app version string, which you can use for creating a unique cache name, and the deployment's base path. If your Vite config specifies define (used for global variable replacements), this will be applied to service workers as well as your server/client builds.
The following example caches the built app and any files in static eagerly, and caches all other requests as they happen. This would make each page work offline once visited.
// Disables access to DOM typings like `HTMLElement` which are not available
// inside a service worker and instantiates the correct globals
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
// Ensures that the `$service-worker` import has proper type definitions
/// <reference types="@sveltejs/kit" />
// Only necessary if you have an import from `$env/static/public`
/// <reference types="../.svelte-kit/ambient.d.ts" />
import { const build: string[]An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build).
During development, this is an empty array.
build, const files: string[]An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files
files, const version: stringSee config.kit.version. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.
version } from '$service-worker';
// This gives `self` the correct types
const const self: ServiceWorkerGlobalScopeself = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (module globalThisglobalThis.var self: Window & typeof globalThisThe Window.self read-only property returns the window itself, as a WindowProxy. It can be used with dot notation on a window object (that is, window.self) or standalone (self). The advantage of the standalone notation is that a similar notation exists for non-window contexts, such as in Web Workers. By using self, you can refer to the global scope in a way that will work not only in a window context (self will resolve to window.self) but also in a worker context (self will then resolve to WorkerGlobalScope.self).
The self read-only property of the WorkerGlobalScope interface returns a reference to the WorkerGlobalScope itself. Most of the time it is a specific scope like DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, or ServiceWorkerGlobalScope.
self));
// Create a unique cache name for this deployment
const const CACHE: stringCACHE = `cache-${const version: stringSee config.kit.version. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.
version}`;
const const ASSETS: string[]ASSETS = [
...const build: string[]An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build).
During development, this is an empty array.
build, // the app itself
...const files: string[]An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files
files // everything in `static`
];
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"install">(type: "install", listener: (this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('install', (event: ExtendableEventevent) => {
// Create a new cache and add all files to it
async function function (local function) addFilesToCache(): Promise<void>addFilesToCache() {
const const cache: Cachecache = await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.open(cacheName: string): Promise<Cache> (+1 overload)The open() method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
open(const CACHE: stringCACHE);
await const cache: Cachecache.Cache.addAll(requests: Iterable<RequestInfo>): Promise<void> (+3 overloads)The addAll() method of the Cache interface takes an array of URLs, retrieves them, and adds the resulting response objects to the given cache. The request objects created during retrieval become keys to the stored response operations.
addAll(const ASSETS: string[]ASSETS);
}
event: ExtendableEventevent.ExtendableEvent.waitUntil(f: Promise<any>): voidThe ExtendableEvent.waitUntil() method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
waitUntil(function (local function) addFilesToCache(): Promise<void>addFilesToCache());
});
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"activate">(type: "activate", listener: (this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('activate', (event: ExtendableEventevent) => {
// Remove previous cached data from disk
async function function (local function) deleteOldCaches(): Promise<void>deleteOldCaches() {
for (const const key: stringkey of await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.keys(): Promise<string[]> (+1 overload)The keys() method of the CacheStorage interface returns a Promise that will resolve with an array containing strings corresponding to all of the named Cache objects tracked by the CacheStorage object in the order they were created. Use this method to iterate over a list of all Cache objects.
keys()) {
if (const key: stringkey !== const CACHE: stringCACHE) await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.delete(cacheName: string): Promise<boolean> (+1 overload)The delete() method of the CacheStorage interface finds the Cache object matching the cacheName, and if found, deletes the Cache object and returns a Promise that resolves to true. If no Cache object is found, it resolves to false.
delete(const key: stringkey);
}
}
event: ExtendableEventevent.ExtendableEvent.waitUntil(f: Promise<any>): voidThe ExtendableEvent.waitUntil() method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
waitUntil(function (local function) deleteOldCaches(): Promise<void>deleteOldCaches());
});
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"fetch">(type: "fetch", listener: (this: ServiceWorkerGlobalScope, ev: FetchEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('fetch', (event: FetchEventevent) => {
// ignore POST requests etc
if (event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request.Request.method: stringThe method read-only property of the Request interface contains the request's method (GET, POST, etc.)
method !== 'GET') return;
async function function (local function) respond(): Promise<Response>respond() {
const const url: URLurl = new var URL: new (url: string | URL, base?: string | URL) => URLThe URL interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL.
URL class is a global reference for import { URL } from 'url'
https://nodejs.org/api/url.html#the-whatwg-url-api
URL(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request.Request.url: stringThe url read-only property of the Request interface contains the URL of the request.
url);
const const cache: Cachecache = await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.open(cacheName: string): Promise<Cache> (+1 overload)The open() method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
open(const CACHE: stringCACHE);
// `build`/`files` can always be served from the cache
if (const ASSETS: string[]ASSETS.Array<string>.includes(searchElement: string, fromIndex?: number): booleanDetermines whether an array includes a certain element, returning true or false as appropriate.
includes(const url: URLurl.URL.pathname: stringThe pathname property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
pathname)) {
const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined> (+1 overload)The match() method of the Cache interface returns a Promise that resolves to the Response associated with the first matching request in the Cache object. If no match is found, the Promise resolves to undefined.
match(const url: URLurl.URL.pathname: stringThe pathname property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
pathname);
if (const response: Response | undefinedresponse) {
return const response: Responseresponse;
}
}
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
const const response: Responseresponse = await function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+2 overloads)fetch(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request);
// if we're offline, fetch can return a value that is not a Response
// instead of throwing - and we can't pass this non-Response to respondWith
if (!(const response: Responseresponse instanceof var Response: {
new (body?: BodyInit | null, init?: ResponseInit): Response;
prototype: Response;
error(): Response;
json(data: any, init?: ResponseInit): Response;
redirect(url: string | URL, status?: number): Response;
}
The Response interface of the Fetch API represents the response to a request.
Response)) {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error('invalid response from fetch');
}
if (const response: Responseresponse.Response.status: numberThe status read-only property of the Response interface contains the HTTP status codes of the response.
status === 200 && !const response: Responseresponse.Response.headers: HeadersThe headers read-only property of the Response interface contains the Headers object associated with the response.
headers.Headers.get(name: string): string | null (+1 overload)The get() method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
get('cache-control')?.String.includes(searchString: string, position?: number): booleanReturns true if searchString appears as a substring of the result of converting this
object to a String, at one or more positions that are
greater than or equal to position; otherwise, returns false.
includes('no-store')) {
const cache: Cachecache.Cache.put(request: RequestInfo | URL, response: Response): Promise<void> (+1 overload)The put() method of the Cache interface allows key/value pairs to be added to the current Cache object.
put(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request, const response: Responseresponse.Response.clone(): Response (+1 overload)The clone() method of the Response interface creates a clone of a response object, identical in every way, but stored in a different variable.
clone());
}
return const response: Responseresponse;
} catch (function (local var) err: unknownerr) {
const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined> (+1 overload)The match() method of the Cache interface returns a Promise that resolves to the Response associated with the first matching request in the Cache object. If no match is found, the Promise resolves to undefined.
match(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request);
if (const response: Response | undefinedresponse) {
return const response: Responseresponse;
}
// if there's no cache, then just error out
// as there is nothing we can do to respond to this request
throw function (local var) err: unknownerr;
}
}
event: FetchEventevent.FetchEvent.respondWith(r: Response | PromiseLike<Response>): voidThe respondWith() method of FetchEvent prevents the browser's default fetch handling, and allows you to provide a promise for a Response yourself.
respondWith(function (local function) respond(): Promise<Response>respond());
});// Disables access to DOM typings like `HTMLElement` which are not available
// inside a service worker and instantiates the correct globals
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
// Ensures that the `$service-worker` import has proper type definitions
/// <reference types="@sveltejs/kit" />
// Only necessary if you have an import from `$env/static/public`
/// <reference types="../.svelte-kit/ambient.d.ts" />
import { const build: string[]An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build).
During development, this is an empty array.
build, const files: string[]An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files
files, const version: stringSee config.kit.version. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.
version } from '$service-worker';
// This gives `self` the correct types
const const self: ServiceWorkerGlobalScopeself = module globalThisglobalThis.var self: Window & typeof globalThisThe Window.self read-only property returns the window itself, as a WindowProxy. It can be used with dot notation on a window object (that is, window.self) or standalone (self). The advantage of the standalone notation is that a similar notation exists for non-window contexts, such as in Web Workers. By using self, you can refer to the global scope in a way that will work not only in a window context (self will resolve to window.self) but also in a worker context (self will then resolve to WorkerGlobalScope.self).
The self read-only property of the WorkerGlobalScope interface returns a reference to the WorkerGlobalScope itself. Most of the time it is a specific scope like DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, or ServiceWorkerGlobalScope.
self as unknown as ServiceWorkerGlobalScope;
// Create a unique cache name for this deployment
const const CACHE: stringCACHE = `cache-${const version: stringSee config.kit.version. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches.
version}`;
const const ASSETS: string[]ASSETS = [
...const build: string[]An array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build).
During development, this is an empty array.
build, // the app itself
...const files: string[]An array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can customize which files are included from static directory using config.kit.serviceWorker.files
files // everything in `static`
];
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"install">(type: "install", listener: (this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('install', (event: ExtendableEventevent) => {
// Create a new cache and add all files to it
async function function (local function) addFilesToCache(): Promise<void>addFilesToCache() {
const const cache: Cachecache = await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.open(cacheName: string): Promise<Cache> (+1 overload)The open() method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
open(const CACHE: stringCACHE);
await const cache: Cachecache.Cache.addAll(requests: Iterable<RequestInfo>): Promise<void> (+3 overloads)The addAll() method of the Cache interface takes an array of URLs, retrieves them, and adds the resulting response objects to the given cache. The request objects created during retrieval become keys to the stored response operations.
addAll(const ASSETS: string[]ASSETS);
}
event: ExtendableEventevent.ExtendableEvent.waitUntil(f: Promise<any>): voidThe ExtendableEvent.waitUntil() method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
waitUntil(function (local function) addFilesToCache(): Promise<void>addFilesToCache());
});
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"activate">(type: "activate", listener: (this: ServiceWorkerGlobalScope, ev: ExtendableEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('activate', (event: ExtendableEventevent) => {
// Remove previous cached data from disk
async function function (local function) deleteOldCaches(): Promise<void>deleteOldCaches() {
for (const const key: stringkey of await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.keys(): Promise<string[]> (+1 overload)The keys() method of the CacheStorage interface returns a Promise that will resolve with an array containing strings corresponding to all of the named Cache objects tracked by the CacheStorage object in the order they were created. Use this method to iterate over a list of all Cache objects.
keys()) {
if (const key: stringkey !== const CACHE: stringCACHE) await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.delete(cacheName: string): Promise<boolean> (+1 overload)The delete() method of the CacheStorage interface finds the Cache object matching the cacheName, and if found, deletes the Cache object and returns a Promise that resolves to true. If no Cache object is found, it resolves to false.
delete(const key: stringkey);
}
}
event: ExtendableEventevent.ExtendableEvent.waitUntil(f: Promise<any>): voidThe ExtendableEvent.waitUntil() method tells the event dispatcher that work is ongoing. It can also be used to detect whether that work was successful. In service workers, waitUntil() tells the browser that work is ongoing until the promise settles, and it shouldn't terminate the service worker if it wants that work to complete.
waitUntil(function (local function) deleteOldCaches(): Promise<void>deleteOldCaches());
});
const self: ServiceWorkerGlobalScopeself.ServiceWorkerGlobalScope.addEventListener<"fetch">(type: "fetch", listener: (this: ServiceWorkerGlobalScope, ev: FetchEvent) => any, options?: boolean | AddEventListenerOptions): void (+1 overload)The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
addEventListener('fetch', (event: FetchEventevent) => {
// ignore POST requests etc
if (event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request.Request.method: stringThe method read-only property of the Request interface contains the request's method (GET, POST, etc.)
method !== 'GET') return;
async function function (local function) respond(): Promise<Response>respond() {
const const url: URLurl = new var URL: new (url: string | URL, base?: string | URL) => URLThe URL interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL.
URL class is a global reference for import { URL } from 'url'
https://nodejs.org/api/url.html#the-whatwg-url-api
URL(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request.Request.url: stringThe url read-only property of the Request interface contains the URL of the request.
url);
const const cache: Cachecache = await var caches: CacheStorageAvailable only in secure contexts.
caches.CacheStorage.open(cacheName: string): Promise<Cache> (+1 overload)The open() method of the CacheStorage interface returns a Promise that resolves to the Cache object matching the cacheName.
open(const CACHE: stringCACHE);
// `build`/`files` can always be served from the cache
if (const ASSETS: string[]ASSETS.Array<string>.includes(searchElement: string, fromIndex?: number): booleanDetermines whether an array includes a certain element, returning true or false as appropriate.
includes(const url: URLurl.URL.pathname: stringThe pathname property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
pathname)) {
const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined> (+1 overload)The match() method of the Cache interface returns a Promise that resolves to the Response associated with the first matching request in the Cache object. If no match is found, the Promise resolves to undefined.
match(const url: URLurl.URL.pathname: stringThe pathname property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character.
pathname);
if (const response: Response | undefinedresponse) {
return const response: Responseresponse;
}
}
// for everything else, try the network first, but
// fall back to the cache if we're offline
try {
const const response: Responseresponse = await function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+2 overloads)fetch(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request);
// if we're offline, fetch can return a value that is not a Response
// instead of throwing - and we can't pass this non-Response to respondWith
if (!(const response: Responseresponse instanceof var Response: {
new (body?: BodyInit | null, init?: ResponseInit): Response;
prototype: Response;
error(): Response;
json(data: any, init?: ResponseInit): Response;
redirect(url: string | URL, status?: number): Response;
}
The Response interface of the Fetch API represents the response to a request.
Response)) {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error('invalid response from fetch');
}
if (const response: Responseresponse.Response.status: numberThe status read-only property of the Response interface contains the HTTP status codes of the response.
status === 200 && !const response: Responseresponse.Response.headers: HeadersThe headers read-only property of the Response interface contains the Headers object associated with the response.
headers.Headers.get(name: string): string | null (+1 overload)The get() method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
get('cache-control')?.String.includes(searchString: string, position?: number): booleanReturns true if searchString appears as a substring of the result of converting this
object to a String, at one or more positions that are
greater than or equal to position; otherwise, returns false.
includes('no-store')) {
const cache: Cachecache.Cache.put(request: RequestInfo | URL, response: Response): Promise<void> (+1 overload)The put() method of the Cache interface allows key/value pairs to be added to the current Cache object.
put(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request, const response: Responseresponse.Response.clone(): Response (+1 overload)The clone() method of the Response interface creates a clone of a response object, identical in every way, but stored in a different variable.
clone());
}
return const response: Responseresponse;
} catch (function (local var) err: unknownerr) {
const const response: Response | undefinedresponse = await const cache: Cachecache.Cache.match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined> (+1 overload)The match() method of the Cache interface returns a Promise that resolves to the Response associated with the first matching request in the Cache object. If no match is found, the Promise resolves to undefined.
match(event: FetchEventevent.FetchEvent.request: RequestThe request read-only property of the FetchEvent interface returns the Request that triggered the event handler.
request);
if (const response: Response | undefinedresponse) {
return const response: Responseresponse;
}
// if there's no cache, then just error out
// as there is nothing we can do to respond to this request
throw function (local var) err: unknownerr;
}
}
event: FetchEventevent.FetchEvent.respondWith(r: Response | PromiseLike<Response>): voidThe respondWith() method of FetchEvent prevents the browser's default fetch handling, and allows you to provide a promise for a Response yourself.
respondWith(function (local function) respond(): Promise<Response>respond());
});Be careful when caching! In some cases, stale data might be worse than data that's unavailable while offline. Since browsers will empty caches if they get too full, you should also be careful about caching large assets like video files.
During development
The service worker is bundled for production, but not during development. For that reason, only browsers that support modules in service workers will be able to use them at dev time. If you are manually registering your service worker, you will need to pass the { type: 'module' } option in development:
import { import devdev } from '$app/environment';
var navigator: NavigatorThe Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
navigator.Navigator.serviceWorker: ServiceWorkerContainerThe serviceWorker read-only property of the Navigator interface returns the ServiceWorkerContainer object for the associated document, which provides access to registration, removal, upgrade, and communication with the ServiceWorker.
Available only in secure contexts.
serviceWorker.ServiceWorkerContainer.register(scriptURL: string | URL, options?: RegistrationOptions): Promise<ServiceWorkerRegistration>The register() method of the ServiceWorkerContainer interface creates or updates a ServiceWorkerRegistration for the given scope.
register('/service-worker.js', {
RegistrationOptions.type?: WorkerType | undefinedtype: import devdev ? 'module' : 'classic'
});
buildandprerenderedare empty arrays during development
Other solutions
SvelteKit's service worker implementation is designed to be easy to work with and is probably a good solution for most users. However, outside of SvelteKit, many PWA applications leverage the Workbox library. If you're used to using Workbox you may prefer Vite PWA plugin.
References
For more general information on service workers, we recommend the MDN web docs.
Edit this page on GitHub llms.txt