Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose base via $service-worker, make paths relative #9250

Merged
merged 5 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/great-toes-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: expose `base` via `$service-worker`, make paths relative
2 changes: 1 addition & 1 deletion documentation/docs/30-advanced/40-service-workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if ('serviceWorker' in navigator) {

## Inside the service worker

Inside the service worker you have access to the [`$service-worker` module](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.
Inside the service worker you have access to the [`$service-worker` module](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, 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.

Expand Down
12 changes: 9 additions & 3 deletions packages/kit/src/exports/vite/build/build_service_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,30 @@ export async function build_service_worker(

const service_worker = `${kit.outDir}/generated/service-worker.js`;

// in a service worker, `location` is the location of the service worker itself,
// which is guaranteed to be `<base>/service-worker.js`
const base = `location.pathname.split('/').slice(0, -1).join('/')`;

fs.writeFileSync(
service_worker,
dedent`
export const base = /*@__PURE__*/ ${base};

export const build = [
${Array.from(build)
.map((file) => `${s(`${kit.paths.base}/${file}`)}`)
.map((file) => `base + ${s(`/${file}`)}`)
.join(',\n')}
];

export const files = [
${manifest_data.assets
.filter((asset) => kit.serviceWorker.files(asset.file))
.map((asset) => `${s(`${kit.paths.base}/${asset.file}`)}`)
.map((asset) => `base + ${s(`/${asset.file}`)}`)
.join(',\n')}
];

export const prerendered = [
${prerendered.paths.map((path) => s(path)).join(',\n')}
${prerendered.paths.map((path) => `base + ${s(path.replace(kit.paths.base, ''))}`).join(',\n')}
];

export const version = ${s(kit.version.name)};
Expand Down
1 change: 1 addition & 0 deletions packages/kit/test/apps/options-2/src/routes/hello/+page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const prerender = true;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Prerendered</h1>
5 changes: 4 additions & 1 deletion packages/kit/test/apps/options-2/src/service-worker.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { build, version } from '$service-worker';
import { base, build, files, prerendered, version } from '$service-worker';

self.base = base;
self.build = build;

const name = `cache-${version}`;

Expand Down
15 changes: 14 additions & 1 deletion packages/kit/test/apps/options-2/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,20 @@ test.describe('Service worker', () => {
const response = await request.get('/basepath/service-worker.js');
const content = await response.text();

expect(content).toMatch(/\/_app\/immutable\/entry\/start\.[a-z0-9]+\.js/);
const fn = new Function('self', 'location', content);

const self = {
addEventListener: () => {},
base: null,
build: null
};

fn(self, {
pathname: '/basepath/service-worker.js'
});

expect(self.base).toBe('/basepath');
expect(self.build[0]).toMatch(/\/basepath\/_app\/immutable\/entry\/start\.[a-z0-9]+\.js/);
});

test('does not register /basepath/service-worker.js', async ({ page }) => {
Expand Down
5 changes: 5 additions & 0 deletions packages/kit/types/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@ declare module '$app/stores' {
* This module is only available to [service workers](https://kit.svelte.dev/docs/service-workers).
*/
declare module '$service-worker' {
/**
* The `base` path of the deployment. Typically this is equivalent to `config.kit.paths.base`, but it is calculated from `location.pathname` meaning that it will continue to work correctly if the site is deployed to a subdirectory.
* Note that there is a `base` but no `assets`, since service workers cannot be used if `config.kit.paths.assets` is specified.
*/
export const base: 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.
Expand Down