Skip to content

Commit

Permalink
fix: exclude service worker from tsconfig (#8508)
Browse files Browse the repository at this point in the history
* fix: exclude service worker from tsconfig

Also document how to get types working inside the file
closes #8127

* ws -> sw

Co-authored-by: Rich Harris <hello@rich-harris.dev>
  • Loading branch information
dummdidumm and Rich-Harris authored Jan 13, 2023
1 parent 7e121e0 commit 6c7f9b2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/tidy-tools-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: exclude service worker from tsconfig
27 changes: 27 additions & 0 deletions documentation/docs/30-advanced/40-service-workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ if ('serviceWorker' in navigator) {
}
```

## Inside the service worker

Inside the service worker you have access to the [`$service-worker` module](/docs/modules#$service-worker), 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. 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.
Expand Down Expand Up @@ -87,6 +89,8 @@ self.addEventListener('fetch', (event) => {

> 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](https://web.dev/es-modules-in-sw) 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:

```js
Expand All @@ -99,4 +103,27 @@ navigator.serviceWorker.register('/service-worker.js', {

> `build` and `prerendered` are empty arrays during development
## Type safety

Setting up proper types for service workers requires some manual setup. Inside your `service-worker.js`, add the following to the top of your file:

```original-js
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self));
```
```generated-ts
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />
const sw = self as unknown as ServiceWorkerGlobalScope;
```

This disables access to DOM typings like `HTMLElement` which are not available inside a service worker and instantiates the correct globals. The reassignment of `self` to `sw` allows you to type cast it in the process (there are a couple of ways to do this, but the easiest that requires no additional files). Use `sw` instead of `self` in the rest of the file.

## Other solutions

SvelteKit's service worker implementation is deliberately low-level. If you need a more full-flegded but also more opinionated solution, we recommend looking at solutions like [Vite PWA plugin](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html), which uses [Workbox](https://web.dev/learn/pwa/workbox). For more general information on service workers, we recommend [the MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers).
11 changes: 10 additions & 1 deletion packages/kit/src/core/sync/write_tsconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ export function write_tsconfig(config, cwd = process.cwd()) {
include.push(config_relative(`${test_folder}/**/*.ts`));
include.push(config_relative(`${test_folder}/**/*.svelte`));

const exclude = [config_relative('node_modules/**'), './[!ambient.d.ts]**'];
if (path.extname(config.files.serviceWorker)) {
exclude.push(config_relative(config.files.serviceWorker));
} else {
exclude.push(config_relative(`${config.files.serviceWorker}.js`));
exclude.push(config_relative(`${config.files.serviceWorker}.ts`));
exclude.push(config_relative(`${config.files.serviceWorker}.d.ts`));
}

write_if_changed(
out,
JSON.stringify(
Expand Down Expand Up @@ -88,7 +97,7 @@ export function write_tsconfig(config, cwd = process.cwd()) {
target: 'esnext'
},
include,
exclude: [config_relative('node_modules/**'), './[!ambient.d.ts]**']
exclude
},
null,
'\t'
Expand Down

1 comment on commit 6c7f9b2

@bart
Copy link

@bart bart commented on 6c7f9b2 Feb 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dummdidumm @Rich-Harris Unfortunately this fix causes the following TS error when adding a service-worker.ts file to src folder:

TS2307: Cannot find module '$service-worker' or its corresponding type declarations.

File content:

import { build, files, prerendered, version } from '$service-worker';
import { precacheAndRoute } from 'workbox-precaching';

const precache_list = [...build, ...files, ...prerendered].map((s) => ({
	url: s,
	revision: version
}));
precacheAndRoute(precache_list);

This is caused by adding an exclude of following files to .svelte-kit/tsconfig.json:

"../src/service-worker.js",
"../src/service-worker.ts",
"../src/service-worker.d.ts"

Could you please give an advise how to solve this problem? Thanks in advance and kind regards!

Please sign in to comment.