Repository: sveltejs/kit
Pull request #8060 (2022-12-10 15:25:59)

Update dependency svelte-preprocess to v5
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [svelte-preprocess](https://togithub.com/sveltejs/svelte-preprocess) | [`^4.10.7` -> `^5.0.0`](https://renovatebot.com/diffs/npm/svelte-preprocess/4.10.7/5.0.0) | [![age](https://badges.renovateapi.com/packages/npm/svelte-preprocess/5.0.0/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/npm/svelte-preprocess/5.0.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/npm/svelte-preprocess/5.0.0/compatibility-slim/4.10.7)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/npm/svelte-preprocess/5.0.0/confidence-slim/4.10.7)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>sveltejs/svelte-preprocess</summary>

### [`v5.0.0`](https://togithub.com/sveltejs/svelte-preprocess/blob/HEAD/CHANGELOG.md#&#8203;500-httpsgithubcomsveltejssvelte-preprocesscomparev4105v500-2022-12-10)

[Compare Source](https://togithub.com/sveltejs/svelte-preprocess/compare/78a0c5571e9271eb1a0881725b4d2ebbfbdcdaf4...v5.0.0)

##### Bug Fixes

-   🐛 add sugarss v3 and v4 as supported ([3f2687b](https://togithub.com/sveltejs/svelte-preprocess/commit/3f2687bc2c3036c96a95a0d491a9491f18e5c28f))
-   🐛 remove support for 'type' attribute ([07bc8aa](https://togithub.com/sveltejs/svelte-preprocess/commit/07bc8aae571300413c52af05554b08451d338443))
-   🐛 remove support for custom default languages ([3d60856](https://togithub.com/sveltejs/svelte-preprocess/commit/3d6085611120895b5527f4e17868105d6ec81c4d))
-   🐛 map .sss as .css to support sugarss extension ([2c0bd45](https://togithub.com/sveltejs/svelte-preprocess/commit/2c0bd4561fc3dd53ff525509925bcc9c5f7b436b))

##### Performance Improvements

-   ⚡️ remove support for deprecated node-sass ([a617fe1](https://togithub.com/sveltejs/svelte-preprocess/commit/a617fe13b0922188346775475325ab8af83c56f7))

##### BREAKING CHANGES

-   🧨 Languages must be explicitly defined via the lang attribute.
-   🧨 Minimum node version was bumped from 9 to 14
-   🧨 Cannot use "type" attribute to identify the language of a style or
    script tag anymore. Use `lang` instead
-   🧨 node-sass is not supported anymore. Use `sass` instead
-   minimum node version changed to v14

#### [4.10.7](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.5...v4.10.7) (2022-06-04)

##### Bug Fixes

-   add pug const mixin ([#&#8203;518](https://togithub.com/sveltejs/svelte-preprocess/issues/518)) ([0551a9b](https://togithub.com/sveltejs/svelte-preprocess/commit/0551a9b557ee18bb05a3e9021a8c9aa1f7b8c665)), closes [#&#8203;467](https://togithub.com/sveltejs/svelte-preprocess/issues/467)
-   paths in postcss sourcemap sources array ([#&#8203;500](https://togithub.com/sveltejs/svelte-preprocess/issues/500)) ([2027375](https://togithub.com/sveltejs/svelte-preprocess/commit/2027375969255d11708340ee40eb2e3ded7ddb35))
-   preserve `[@font-face](https://togithub.com/font-face)` inside `:global` block ([#&#8203;486](https://togithub.com/sveltejs/svelte-preprocess/issues/486)) ([8064473](https://togithub.com/sveltejs/svelte-preprocess/commit/8064473ae107f6e2d34eb9590e4befa70ce4618c)), closes [#&#8203;236](https://togithub.com/sveltejs/svelte-preprocess/issues/236)
-   stylus - handle relative sourcemap sources([#&#8203;513](https://togithub.com/sveltejs/svelte-preprocess/issues/513)) ([77bd3bf](https://togithub.com/sveltejs/svelte-preprocess/commit/77bd3bf69554afbc45d6f1e34a4eb5abf398a933))

#### [4.10.6](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.5...v4.10.6) (2022-04-13)

##### Bug Fixes

-   paths in postcss sourcemap sources array ([#&#8203;500](https://togithub.com/sveltejs/svelte-preprocess/issues/500)) ([2027375](https://togithub.com/sveltejs/svelte-preprocess/commit/2027375969255d11708340ee40eb2e3ded7ddb35))
-   preserve `[@font-face](https://togithub.com/font-face)` inside `:global` block ([#&#8203;486](https://togithub.com/sveltejs/svelte-preprocess/issues/486)) ([8064473](https://togithub.com/sveltejs/svelte-preprocess/commit/8064473ae107f6e2d34eb9590e4befa70ce4618c)), closes [#&#8203;236](https://togithub.com/sveltejs/svelte-preprocess/issues/236)

#### [4.10.5](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.4...v4.10.5) (2022-04-04)

##### Bug Fixes

-   always use absolute paths for less imports ([#&#8203;495](https://togithub.com/sveltejs/svelte-preprocess/issues/495)) ([#&#8203;496](https://togithub.com/sveltejs/svelte-preprocess/issues/496)) ([be0fda4](https://togithub.com/sveltejs/svelte-preprocess/commit/be0fda4ddbe95040221ff248ccbb492fb5555334))

#### [4.10.4](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.3...v4.10.4) (2022-02-23)

##### Bug Fixes

-   only try to load external files with relative paths ([#&#8203;487](https://togithub.com/sveltejs/svelte-preprocess/issues/487)) ([80d87ed](https://togithub.com/sveltejs/svelte-preprocess/commit/80d87edac4723401db47d06ed03bb6cd388c21d9))

#### [4.10.3](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.2...v4.10.3) (2022-02-09)

##### Bug Fixes

-   add # and numbers to ts store regex ([#&#8203;473](https://togithub.com/sveltejs/svelte-preprocess/issues/473)) ([881f3c9](https://togithub.com/sveltejs/svelte-preprocess/commit/881f3c9ad6118fb66b560494a67042944567e0ec)), closes [#&#8203;466](https://togithub.com/sveltejs/svelte-preprocess/issues/466)
-   adjust typescript peer dep ([#&#8203;479](https://togithub.com/sveltejs/svelte-preprocess/issues/479)) ([68fae2c](https://togithub.com/sveltejs/svelte-preprocess/commit/68fae2c56fb3e22ff21f12c9aab74b42ad4f7bb8))

#### [4.10.2](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.1...v4.10.2) (2022-01-17)

##### Bug Fixes

-   accept less v4 as peer dep ([#&#8203;455](https://togithub.com/sveltejs/svelte-preprocess/issues/455)) ([fbc484a](https://togithub.com/sveltejs/svelte-preprocess/commit/fbc484a6d0394928c1318b70dfe007fed1d9fdac))
-   better pug error message ([#&#8203;448](https://togithub.com/sveltejs/svelte-preprocess/issues/448)) ([a239e82](https://togithub.com/sveltejs/svelte-preprocess/commit/a239e829295bde5f62383697266cefe7767dd0e2)), closes [#&#8203;447](https://togithub.com/sveltejs/svelte-preprocess/issues/447)
-   provide caller information to Babel ([#&#8203;449](https://togithub.com/sveltejs/svelte-preprocess/issues/449)) ([51007ab](https://togithub.com/sveltejs/svelte-preprocess/commit/51007abf946ffdd1d407c6bcf86439d38e113626))
-   ts preprocessor - consider store suffixed with number ([#&#8203;461](https://togithub.com/sveltejs/svelte-preprocess/issues/461)) ([a7a94cf](https://togithub.com/sveltejs/svelte-preprocess/commit/a7a94cfb29f6ea85cfafd1afa2c61363f72cb4b3)), closes [sveltejs/svelte#&#8203;7120](https://togithub.com/sveltejs/svelte/issues/7120)

#### [4.10.1](https://togithub.com/sveltejs/svelte-preprocess/compare/v4.10.0...v4.10.1) (2021-12-17)

##### Bug Fixes

-   adjust store regex ([#&#8203;441](https://togithub.com/sveltejs/svelte-preprocess/issues/441)) ([85a86c8](https://togithub.com/sveltejs/svelte-preprocess/commit/85a86c86513f98c2b02f2d314a18b0e68378c8f6)), closes [#&#8203;433](https://togithub.com/sveltejs/svelte-preprocess/issues/433)
-   generate high resolution source map ([#&#8203;443](https://togithub.com/sveltejs/svelte-preprocess/issues/443)) ([57012ba](https://togithub.com/sveltejs/svelte-preprocess/commit/57012ba9f87abfec99f061196fb955da4ccfa384))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/sveltejs/kit).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC41NC4wIiwidXBkYXRlZEluVmVyIjoiMzQuNTQuMCJ9-->


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 9a4365b121a7b39cb6518daca251a68c80adfebc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/sveltejs/kit/new/renovate/svelte-preprocess-5.x?filename=.changeset/brown-games-refuse.md&value=---%0A%22%40sveltejs%2Fkit%22%3A%20patch%0A%22%40sveltejs%2Fpackage%22%3A%20patch%0A---%0A%0AUpdate%20dependency%20svelte-preprocess%20to%20v5%0A)



Patch:
diff --git a/.changeset/clever-ducks-wave.md b/.changeset/clever-ducks-wave.md
new file mode 100644
index 000000000..e17730950
--- /dev/null
+++ b/.changeset/clever-ducks-wave.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] set Vite base URL
diff --git a/.changeset/violet-donuts-share.md b/.changeset/violet-donuts-share.md
new file mode 100644
index 000000000..51213dcb5
--- /dev/null
+++ b/.changeset/violet-donuts-share.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+add declaration for vitePreprocess reexport
diff --git a/documentation/docs/20-core-concepts/30-form-actions.md b/documentation/docs/20-core-concepts/30-form-actions.md
index f84b24143..71be240cf 100644
--- a/documentation/docs/20-core-concepts/30-form-actions.md
+++ b/documentation/docs/20-core-concepts/30-form-actions.md
@@ -25,8 +25,14 @@ To invoke this action from the `/login` page, just add a `<form>` — no JavaScr
 ```svelte
 /// file: src/routes/login/+page.svelte
 <form method="POST">
-	<input name="email" type="email">
-	<input name="password" type="password">
+	<label>
+		Email
+		<input name="email" type="email">
+	</label>
+	<label>
+		Password
+		<input name="password" type="password">
+	</label>
 	<button>Log in</button>
 </form>
 ```
@@ -81,8 +87,14 @@ As well as the `action` attribute, we can use the `formaction` attribute on a bu
 /// file: src/routes/login/+page.svelte
 -<form method="POST">
 +<form method="POST" action="?/login">
-	<input name="email" type="email">
-	<input name="password" type="password">
+	<label>
+		Email
+		<input name="email" type="email">
+	</label>
+	<label>
+		Password
+		<input name="password" type="password">
+	</label>
 	<button>Log in</button>
 +	<button formaction="?/register">Register</button>
 </form>
@@ -179,12 +191,17 @@ export const actions = {
 ```diff
 /// file: src/routes/login/+page.svelte
 <form method="POST" action="?/login">
--	<input name="email" type="email">
 +	{#if form?.missing}<p class="error">The email field is required</p>{/if}
 +	{#if form?.incorrect}<p class="error">Invalid credentials!</p>{/if}
-+	<input name="email" type="email" value={form?.email ?? ''}>
-
-	<input name="password" type="password">
+	<label>
+		Email
+-		<input name="email" type="email">
++		<input name="email" type="email" value={form?.email ?? ''}>
+	</label>
+	<label>
+		Password
+		<input name="password" type="password">
+	</label>
 	<button>Log in</button>
 	<button formaction="?/register">Register</button>
 </form>
@@ -323,6 +340,7 @@ Without an argument, `use:enhance` will emulate the browser-native behaviour, ju
 - reset the `<form>` element and invalidate all data using `invalidateAll` on a successful response
 - call `goto` on a redirect response
 - render the nearest `+error` boundary if an error occurs
+- [reset focus](/docs/accessibility#focus-management) to the appropriate element
 
 To customise the behaviour, you can provide a `SubmitFunction` that runs immediately before the form is submitted, and (optionally) returns a callback that runs with the `ActionResult`. Note that if you return a callback, the default behavior mentioned above is not triggered. To get it back, call `update`.
 
@@ -381,6 +399,8 @@ The behaviour of `applyAction(result)` depends on `result.type`:
 - `redirect` — calls `goto(result.location)`
 - `error` — renders the nearest `+error` boundary with `result.error`
 
+In all cases, [focus will be reset](/docs/accessibility#focus-management).
+
 ### Custom event listener
 
 We can also implement progressive enhancement ourselves, without `use:enhance`, with a normal event listener on the `<form>`:
@@ -448,7 +468,10 @@ Some forms don't need to `POST` data to the server — search inputs, for exampl
 
 ```html
 <form action="/search">
-	<input name="q">
+	<label>
+		Search
+		<input name="q">
+	</label>
 </form>
 ```
 
diff --git a/documentation/docs/40-best-practices/10-accessibility.md b/documentation/docs/40-best-practices/10-accessibility.md
index 6ab3fa1c4..5a85e00e0 100644
--- a/documentation/docs/40-best-practices/10-accessibility.md
+++ b/documentation/docs/40-best-practices/10-accessibility.md
@@ -29,7 +29,9 @@ This will allow screen readers and other assistive technology to identify the ne
 
 In traditional server-rendered applications, every navigation will reset focus to the top of the page. This ensures that people browsing the web with a keyboard or screen reader will start interacting with the page from the beginning.
 
-To simulate this behavior during client-side routing, SvelteKit focuses the `<body>` element after each navigation. If you want to customize this behavior, you can implement custom focus management logic using the `afterNavigate` hook:
+To simulate this behavior during client-side routing, SvelteKit focuses the `<body>` element after each navigation and [enhanced form submission](https://kit.svelte.dev/docs/form-actions#progressive-enhancement). There is one exception - if an element with the [`autofocus`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) attribute is present, SvelteKit will focus that element instead. Make sure to [consider the implications for assistive technology](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus#accessibility_considerations) when using that attribute.
+
+If you want to customize SvelteKit's focus management, you can use the `afterNavigate` hook:
 
 ```js
 /// <reference types="@sveltejs/kit" />
diff --git a/documentation/docs/60-appendix/05-integrations.md b/documentation/docs/60-appendix/05-integrations.md
index 205df56b3..fa3d3b87f 100644
--- a/documentation/docs/60-appendix/05-integrations.md
+++ b/documentation/docs/60-appendix/05-integrations.md
@@ -21,7 +21,9 @@ export default {
 
 ### `svelte-preprocess`
 
-[`svelte-preprocess`](https://github.com/sveltejs/svelte-preprocess) automatically transforms the code in your Svelte templates to provide support for TypeScript, PostCSS, scss/sass, Less, and many other technologies (except CoffeeScript which is [not supported](https://github.com/sveltejs/kit/issues/2920#issuecomment-996469815) by SvelteKit). `vitePreprocess` may be faster and require less configuration, so it is used by default. However, `svelte-preprocess` has some additional functionality not found in `vitePreprocess`. The first step of setting it up is to add `svelte-preprocess` to your [`svelte.config.js`](/docs/configuration). After that, you will often only need to install the corresponding library such as `npm install -D sass` or `npm install -D less`. See the [`svelte-preprocess`](https://github.com/sveltejs/svelte-preprocess) docs for more details.
+`svelte-preprocess` has some additional functionality not found in `vitePreprocess` such as support for Pug, Babel, and global styles. However, `vitePreprocess` may be faster and require less configuration, so it is used by default. Note that CoffeeScript is [not supported](https://github.com/sveltejs/kit/issues/2920#issuecomment-996469815) by SvelteKit.
+
+You will need to install `svelte-preprocess` with `npm install --save-dev svelte-preprocess` and [add it to your `svelte.config.js`](https://github.com/sveltejs/svelte-preprocess/blob/main/docs/usage.md#with-svelte-config). After that, you will often need to [install the corresponding library](https://github.com/sveltejs/svelte-preprocess/blob/main/docs/getting-started.md) such as `npm install -D sass` or `npm install -D less`.
 
 ## Adders
 
diff --git a/packages/kit/package.json b/packages/kit/package.json
index 4a6318bb0..52d8fa59b 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -35,7 +35,7 @@
 		"marked": "^4.2.3",
 		"rollup": "^3.7.0",
 		"svelte": "^3.54.0",
-		"svelte-preprocess": "^4.10.7",
+		"svelte-preprocess": "^5.0.0",
 		"typescript": "^4.9.3",
 		"uvu": "^0.5.6",
 		"vite": "^4.0.0"
diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js
index 51995ef87..e4fabf787 100644
--- a/packages/kit/src/exports/vite/index.js
+++ b/packages/kit/src/exports/vite/index.js
@@ -253,7 +253,7 @@ function kit({ svelte_config }) {
 			/** @type {import('vite').UserConfig} */
 			const result = {
 				appType: 'custom',
-				base: './',
+				base: svelte_config.kit.paths.base,
 				build: {
 					rollupOptions: {
 						// Vite dependency crawler needs an explicit JS entry point
diff --git a/packages/kit/src/exports/vite/utils.js b/packages/kit/src/exports/vite/utils.js
index 4496c1408..1d040ff31 100644
--- a/packages/kit/src/exports/vite/utils.js
+++ b/packages/kit/src/exports/vite/utils.js
@@ -173,8 +173,12 @@ export function not_found(req, res, base) {
 
 	if (type === 'text/html') {
 		res.setHeader('Content-Type', 'text/html');
-		res.end(`Not found (did you mean <a href="${prefixed}">${prefixed}</a>?)`);
+		res.end(
+			`The server is configured with a public base URL of /path-base - did you mean to visit <a href="${prefixed}">${prefixed}</a> instead?`
+		);
 	} else {
-		res.end(`Not found (did you mean ${prefixed}?)`);
+		res.end(
+			`The server is configured with a public base URL of /path-base - did you mean to visit ${prefixed} instead?`
+		);
 	}
 }
diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts
index 9011f3d34..175de0fea 100644
--- a/packages/kit/types/ambient.d.ts
+++ b/packages/kit/types/ambient.d.ts
@@ -434,4 +434,5 @@ declare module '@sveltejs/kit/vite' {
 	 * Returns the SvelteKit Vite plugins.
 	 */
 	export function sveltekit(): Promise<Plugin[]>;
+	export { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
 }
diff --git a/packages/package/package.json b/packages/package/package.json
index cfe1a4bb1..2080e8130 100644
--- a/packages/package/package.json
+++ b/packages/package/package.json
@@ -18,7 +18,7 @@
 	"devDependencies": {
 		"@types/node": "^16.18.6",
 		"svelte": "^3.54.0",
-		"svelte-preprocess": "^4.10.7",
+		"svelte-preprocess": "^5.0.0",
 		"typescript": "^4.9.3",
 		"uvu": "^0.5.6"
 	},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8ecc65ebe..6e9d1b7fe 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -280,7 +280,7 @@ importers:
       set-cookie-parser: ^2.5.1
       sirv: ^2.0.2
       svelte: ^3.54.0
-      svelte-preprocess: ^4.10.7
+      svelte-preprocess: ^5.0.0
       tiny-glob: ^0.2.9
       typescript: ^4.9.3
       undici: 5.14.0
@@ -311,7 +311,7 @@ importers:
       marked: 4.2.3
       rollup: 3.7.0
       svelte: 3.54.0
-      svelte-preprocess: 4.10.7_gf4dcx76vtk2o62ixxeqx7chra
+      svelte-preprocess: 5.0.0_gf4dcx76vtk2o62ixxeqx7chra
       typescript: 4.9.3
       uvu: 0.5.6
       vite: 4.0.0_@types+node@16.18.6
@@ -652,7 +652,7 @@ importers:
       kleur: ^4.1.5
       sade: ^1.8.1
       svelte: ^3.54.0
-      svelte-preprocess: ^4.10.7
+      svelte-preprocess: ^5.0.0
       svelte2tsx: ~0.5.20
       typescript: ^4.9.3
       uvu: ^0.5.6
@@ -664,7 +664,7 @@ importers:
     devDependencies:
       '@types/node': 16.18.6
       svelte: 3.54.0
-      svelte-preprocess: 4.10.7_gf4dcx76vtk2o62ixxeqx7chra
+      svelte-preprocess: 5.0.0_gf4dcx76vtk2o62ixxeqx7chra
       typescript: 4.9.3
       uvu: 0.5.6
 
@@ -4291,6 +4291,54 @@ packages:
       typescript: 4.9.3
     dev: true
 
+  /svelte-preprocess/5.0.0_gf4dcx76vtk2o62ixxeqx7chra:
+    resolution: {integrity: sha512-q7lpa7i2FBu8Pa+G0MmuQQWETBwCKgsGmuq1Sf6n8q4uaG9ZLcLP0Y+etC6bF4sE6EbLxfiI38zV6RfPe3RSfg==}
+    engines: {node: '>= 14.10.0'}
+    requiresBuild: true
+    peerDependencies:
+      '@babel/core': ^7.10.2
+      coffeescript: ^2.5.1
+      less: ^3.11.3 || ^4.0.0
+      postcss: ^7 || ^8
+      postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0
+      pug: ^3.0.0
+      sass: ^1.26.8
+      stylus: ^0.55.0
+      sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0
+      svelte: ^3.23.0
+      typescript: ^3.9.5 || ^4.0.0
+    peerDependenciesMeta:
+      '@babel/core':
+        optional: true
+      coffeescript:
+        optional: true
+      less:
+        optional: true
+      postcss:
+        optional: true
+      postcss-load-config:
+        optional: true
+      pug:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      typescript:
+        optional: true
+    dependencies:
+      '@types/pug': 2.0.6
+      '@types/sass': 1.43.1
+      detect-indent: 6.1.0
+      magic-string: 0.27.0
+      sorcery: 0.10.0
+      strip-indent: 3.0.0
+      svelte: 3.54.0
+      typescript: 4.9.3
+    dev: true
+
   /svelte/3.54.0:
     resolution: {integrity: sha512-tdrgeJU0hob0ZWAMoKXkhcxXA7dpTg6lZGxUeko5YqvPdJBiyRspGsCwV27kIrbrqPP2WUoSV9ca0gnLlw8YzQ==}
     engines: {node: '>= 8'}
diff --git a/sites/kit.svelte.dev/src/routes/edge.svg/+server.js b/sites/kit.svelte.dev/src/routes/edge.svg/+server.js
index e873ab1ec..5bff2f15e 100644
--- a/sites/kit.svelte.dev/src/routes/edge.svg/+server.js
+++ b/sites/kit.svelte.dev/src/routes/edge.svg/+server.js
@@ -2,6 +2,7 @@ import { geoPath } from 'd3-geo';
 import { geoSatellite } from 'd3-geo-projection';
 import * as topojson from 'topojson-client';
 import topology from './land-110m.json';
+import countries from './countries.json';
 
 const land = topojson.feature(topology, topology.objects.land);
 
@@ -28,18 +29,27 @@ const projection = geoSatellite()
 const path = geoPath(projection);
 
 /**
- * @param {number} lat
- * @param {number} lon
+ * @param {string | null} lat
+ * @param {string | null} lon
  * @param {string} city
  * @param {string} country
  */
 function render(lat, lon, city, country) {
-	projection.rotate([-lon - 10, -lat + 20, 0]);
+	const coords = lat && lon ? [+lon, +lat] : [-74, 40.7];
 
-	const [x, y] = projection([lon, lat]);
+	// spin globe a little west of the user's location so that it isn't
+	// dead centre, and tilt them slightly towards the vertical center
+	projection.rotate([-coords[0] - 30, -coords[1] * (30 / 90), 0]);
 
-	const sphere = path({ type: 'Sphere' });
-	const label = `${city}, ${country}`;
+	const dot = lon && lat ? projection([lon, lat]) : null;
+
+	const MAX_LABEL_LENGTH = 27;
+	const DEFAULT_LABEL = 'Your location';
+
+	let label = [city, country].filter(Boolean).join(', ') || DEFAULT_LABEL;
+	if (label.length > MAX_LABEL_LENGTH) label = city ?? DEFAULT_LABEL;
+	if (label.length > MAX_LABEL_LENGTH) label = country ?? DEFAULT_LABEL;
+	if (label.length > MAX_LABEL_LENGTH) label = DEFAULT_LABEL;
 
 	return `<?xml version="1.0" encoding="UTF-8"?>
 		<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}">
@@ -81,10 +91,13 @@ function render(lat, lon, city, country) {
 				}
 			</style>
 
-			<path d="${sphere}" class="ocean"/>
+			<path d="${path({ type: 'Sphere' })}" class="ocean"/>
 			<path d="${path(land)}" class="land"/>
 
-			<g transform="translate(${x},${y})">
+			${
+				dot
+					? `
+			<g transform="translate(${dot[0]},${dot[1]})">
 				<circle r="20" class="dot"/>
 				<rect x="50" y="-30" width="${font_size * 0.6 * label.length + 40}" height="60" class="highlight"/>
 				<polygon points="35,0 50,-10 50,10" class="highlight" />
@@ -96,27 +109,26 @@ function render(lat, lon, city, country) {
 					dominant-baseline="middle"
 					style="font-family: 'Courier', 'Courier New'; font-size: ${font_size}px; font-weight: bold"
 				>${label.toUpperCase()}</text>
-			</g>
+			</g>`
+					: ''
+			}
 		</svg>
 	`;
 }
 
 /** @type {import('./$types').RequestHandler} */
-export function GET({ request, url }) {
-	const q = url.searchParams;
+export function GET({ request }) {
 	const h = request.headers;
 
-	const latitude = q.get('lat') ?? h.get('x-vercel-ip-latitude') ?? '40.7';
-	const longitude = q.get('lon') ?? h.get('x-vercel-ip-longitude') ?? '-74';
-	const city = q.get('city') ?? h.get('x-vercel-ip-city') ?? 'New York City';
-	const country = q.get('country') ?? h.get('x-vercel-ip-country') ?? 'USA';
-
-	const svg = render(
-		+latitude,
-		+longitude,
-		decodeURIComponent(city),
-		decodeURIComponent(country)
-	).replace(/\d\.\d+/g, (match) => match.slice(0, 4));
+	const latitude = h.get('x-vercel-ip-latitude') ?? '';
+	const longitude = h.get('x-vercel-ip-longitude') ?? '';
+	const city = h.get('x-vercel-ip-city') ?? '';
+	const country = countries[h.get('x-vercel-ip-country')];
+
+	const svg = render(latitude, longitude, decodeURIComponent(city), country).replace(
+		/\d\.\d+/g,
+		(match) => match.slice(0, 4)
+	);
 
 	return new Response(svg, {
 		headers: {
diff --git a/sites/kit.svelte.dev/src/routes/edge.svg/countries.json b/sites/kit.svelte.dev/src/routes/edge.svg/countries.json
new file mode 100644
index 000000000..bb92e51a9
--- /dev/null
+++ b/sites/kit.svelte.dev/src/routes/edge.svg/countries.json
@@ -0,0 +1,251 @@
+{
+	"AF": "Afghanistan",
+	"AL": "Albania",
+	"DZ": "Algeria",
+	"AS": "American Samoa",
+	"AD": "Andorra",
+	"AO": "Angola",
+	"AI": "Anguilla",
+	"AQ": "Antarctica",
+	"AG": "Antigua and Barbuda",
+	"AR": "Argentina",
+	"AM": "Armenia",
+	"AW": "Aruba",
+	"AU": "Australia",
+	"AT": "Austria",
+	"AZ": "Azerbaijan",
+	"BS": "Bahamas (the)",
+	"BH": "Bahrain",
+	"BD": "Bangladesh",
+	"BB": "Barbados",
+	"BY": "Belarus",
+	"BE": "Belgium",
+	"BZ": "Belize",
+	"BJ": "Benin",
+	"BM": "Bermuda",
+	"BT": "Bhutan",
+	"BO": "Bolivia",
+	"BQ": "Bonaire, Sint Eustatius and Saba",
+	"BA": "Bosnia and Herzegovina",
+	"BW": "Botswana",
+	"BV": "Bouvet Island",
+	"BR": "Brazil",
+	"IO": "British Indian Ocean Territory",
+	"BN": "Brunei Darussalam",
+	"BG": "Bulgaria",
+	"BF": "Burkina Faso",
+	"BI": "Burundi",
+	"CV": "Cabo Verde",
+	"KH": "Cambodia",
+	"CM": "Cameroon",
+	"CA": "Canada",
+	"KY": "Cayman Islands",
+	"CF": "Central African Republic",
+	"TD": "Chad",
+	"CL": "Chile",
+	"CN": "China",
+	"CX": "Christmas Island",
+	"CC": "Cocos (Keeling) Islands",
+	"CO": "Colombia",
+	"KM": "Comoros",
+	"CD": "Congo (Kinshasa)",
+	"CG": "Congo (Brazzaville)",
+	"CK": "Cook Islands",
+	"CR": "Costa Rica",
+	"HR": "Croatia",
+	"CU": "Cuba",
+	"CW": "Curaçao",
+	"CY": "Cyprus",
+	"CZ": "Czechia",
+	"CI": "Côte d'Ivoire",
+	"DK": "Denmark",
+	"DJ": "Djibouti",
+	"DM": "Dominica",
+	"DO": "Dominican Republic",
+	"EC": "Ecuador",
+	"EG": "Egypt",
+	"SV": "El Salvador",
+	"GQ": "Equatorial Guinea",
+	"ER": "Eritrea",
+	"EE": "Estonia",
+	"SZ": "Eswatini",
+	"ET": "Ethiopia",
+	"FK": "Falkland Islands",
+	"FO": "Faroe Islands",
+	"FJ": "Fiji",
+	"FI": "Finland",
+	"FR": "France",
+	"GF": "French Guiana",
+	"PF": "French Polynesia",
+	"TF": "French Southern Territories",
+	"GA": "Gabon",
+	"GM": "Gambia",
+	"GE": "Georgia",
+	"DE": "Germany",
+	"GH": "Ghana",
+	"GI": "Gibraltar",
+	"GR": "Greece",
+	"GL": "Greenland",
+	"GD": "Grenada",
+	"GP": "Guadeloupe",
+	"GU": "Guam",
+	"GT": "Guatemala",
+	"GG": "Guernsey",
+	"GN": "Guinea",
+	"GW": "Guinea-Bissau",
+	"GY": "Guyana",
+	"HT": "Haiti",
+	"HM": "Heard Island and McDonald Islands",
+	"VA": "Holy See",
+	"HN": "Honduras",
+	"HK": "Hong Kong",
+	"HU": "Hungary",
+	"IS": "Iceland",
+	"IN": "India",
+	"ID": "Indonesia",
+	"IR": "Iran",
+	"IQ": "Iraq",
+	"IE": "Ireland",
+	"IM": "Isle of Man",
+	"IL": "Israel",
+	"IT": "Italy",
+	"JM": "Jamaica",
+	"JP": "Japan",
+	"JE": "Jersey",
+	"JO": "Jordan",
+	"KZ": "Kazakhstan",
+	"KE": "Kenya",
+	"KI": "Kiribati",
+	"KP": "DPRK",
+	"KR": "Republic of Korea",
+	"KW": "Kuwait",
+	"KG": "Kyrgyzstan",
+	"LA": "Laos",
+	"LV": "Latvia",
+	"LB": "Lebanon",
+	"LS": "Lesotho",
+	"LR": "Liberia",
+	"LY": "Libya",
+	"LI": "Liechtenstein",
+	"LT": "Lithuania",
+	"LU": "Luxembourg",
+	"MO": "Macao",
+	"MG": "Madagascar",
+	"MW": "Malawi",
+	"MY": "Malaysia",
+	"MV": "Maldives",
+	"ML": "Mali",
+	"MT": "Malta",
+	"MH": "Marshall Islands",
+	"MQ": "Martinique",
+	"MR": "Mauritania",
+	"MU": "Mauritius",
+	"YT": "Mayotte",
+	"MX": "Mexico",
+	"FM": "Micronesia",
+	"MD": "Moldova",
+	"MC": "Monaco",
+	"MN": "Mongolia",
+	"ME": "Montenegro",
+	"MS": "Montserrat",
+	"MA": "Morocco",
+	"MZ": "Mozambique",
+	"MM": "Myanmar",
+	"NA": "Namibia",
+	"NR": "Nauru",
+	"NP": "Nepal",
+	"NL": "Netherlands",
+	"NC": "New Caledonia",
+	"NZ": "New Zealand",
+	"NI": "Nicaragua",
+	"NE": "Niger",
+	"NG": "Nigeria",
+	"NU": "Niue",
+	"NF": "Norfolk Island",
+	"MP": "Northern Mariana Islands",
+	"NO": "Norway",
+	"OM": "Oman",
+	"PK": "Pakistan",
+	"PW": "Palau",
+	"PS": "Palestine",
+	"PA": "Panama",
+	"PG": "Papua New Guinea",
+	"PY": "Paraguay",
+	"PE": "Peru",
+	"PH": "Philippines",
+	"PN": "Pitcairn",
+	"PL": "Poland",
+	"PT": "Portugal",
+	"PR": "Puerto Rico",
+	"QA": "Qatar",
+	"MK": "North Macedonia",
+	"RO": "Romania",
+	"RU": "Russian Federation",
+	"RW": "Rwanda",
+	"RE": "Réunion",
+	"BL": "Saint Barthélemy",
+	"SH": "Saint Helena, Ascension and Tristan da Cunha",
+	"KN": "Saint Kitts and Nevis",
+	"LC": "Saint Lucia",
+	"MF": "Saint Martin (French part)",
+	"PM": "Saint Pierre and Miquelon",
+	"VC": "Saint Vincent and the Grenadines",
+	"WS": "Samoa",
+	"SM": "San Marino",
+	"ST": "Sao Tome and Principe",
+	"SA": "Saudi Arabia",
+	"SN": "Senegal",
+	"RS": "Serbia",
+	"SC": "Seychelles",
+	"SL": "Sierra Leone",
+	"SG": "Singapore",
+	"SX": "Sint Maarten (Dutch part)",
+	"SK": "Slovakia",
+	"SI": "Slovenia",
+	"SB": "Solomon Islands",
+	"SO": "Somalia",
+	"ZA": "South Africa",
+	"GS": "South Georgia and the South Sandwich Islands",
+	"SS": "South Sudan",
+	"ES": "Spain",
+	"LK": "Sri Lanka",
+	"SD": "Sudan (the)",
+	"SR": "Suriname",
+	"SJ": "Svalbard and Jan Mayen",
+	"SE": "Sweden",
+	"CH": "Switzerland",
+	"SY": "Syrian Arab Republic",
+	"TW": "Taiwan",
+	"TJ": "Tajikistan",
+	"TZ": "Tanzania",
+	"TH": "Thailand",
+	"TL": "Timor-Leste",
+	"TG": "Togo",
+	"TK": "Tokelau",
+	"TO": "Tonga",
+	"TT": "Trinidad and Tobago",
+	"TN": "Tunisia",
+	"TR": "Turkey",
+	"TM": "Turkmenistan",
+	"TC": "Turks and Caicos Islands (the)",
+	"TV": "Tuvalu",
+	"UG": "Uganda",
+	"UA": "Ukraine",
+	"AE": "UAE",
+	"GB": "UK",
+	"UM": "United States Minor Outlying Islands",
+	"US": "USA",
+	"UY": "Uruguay",
+	"UZ": "Uzbekistan",
+	"VU": "Vanuatu",
+	"VE": "Venezuela",
+	"VN": "Vietnam",
+	"VG": "British Virgin Islands",
+	"VI": "US Virgin Islands",
+	"WF": "Wallis and Futuna",
+	"EH": "Western Sahara",
+	"YE": "Yemen",
+	"ZM": "Zambia",
+	"ZW": "Zimbabwe",
+	"AX": "Åland Islands"
+}
diff --git a/sites/site-kit/src/lib/styles/text.css b/sites/site-kit/src/lib/styles/text.css
index 0c4de285d..1e62d3cba 100644
--- a/sites/site-kit/src/lib/styles/text.css
+++ b/sites/site-kit/src/lib/styles/text.css
@@ -56,6 +56,14 @@
 	background: transparent;
 }
 
+.text p code {
+	max-width: 100%;
+	display: inline-flex;
+	overflow-x: auto;
+	padding-top: 0;
+	padding-bottom: 0;
+}
+
 .text .code-block .filename {
 	content: attr(data-file);
 	display: block;


Test patch:
diff --git a/packages/kit/test/apps/options/source/template.html b/packages/kit/test/apps/options/source/template.html
index 5b4fa5d89..3a1269063 100644
--- a/packages/kit/test/apps/options/source/template.html
+++ b/packages/kit/test/apps/options/source/template.html
@@ -9,6 +9,6 @@
 	<body>
 		<h1>I am in the template</h1>
 		<div>%sveltekit.body%</div>
-		<a href="/path-base/routing/link-outside-app-target/target">outside app target</a>
+		<a href="/path-base/routing/link-outside-app-target/target/">outside app target</a>
 	</body>
 </html>
diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js
index 516536c6c..588a7cbe5 100644
--- a/packages/kit/test/apps/options/test/test.js
+++ b/packages/kit/test/apps/options/test/test.js
@@ -10,12 +10,14 @@ test.describe('base path', () => {
 		const html = await request.get('/slash/', { headers: { Accept: 'text/html' } });
 		expect(html.status()).toBe(404);
 		expect(await html.text()).toBe(
-			'Not found (did you mean <a href="/path-base/slash/">/path-base/slash/</a>?)'
+			'The server is configured with a public base URL of /path-base - did you mean to visit <a href="/path-base/slash/">/path-base/slash/</a> instead?'
 		);
 
 		const plain = await request.get('/slash/');
 		expect(plain.status()).toBe(404);
-		expect(await plain.text()).toBe('Not found (did you mean /path-base/slash/?)');
+		expect(await plain.text()).toBe(
+			'The server is configured with a public base URL of /path-base - did you mean to visit /path-base/slash/ instead?'
+		);
 	});
 
 	test('serves /', async ({ page, javaScriptEnabled }) => {
@@ -248,9 +250,9 @@ test.describe('Vite options', () => {
 
 test.describe('Routing', () => {
 	test('ignores clicks outside the app target', async ({ page }) => {
-		await page.goto('/path-base/routing/link-outside-app-target/source');
+		await page.goto('/path-base/routing/link-outside-app-target/source/');
 
-		await page.click('[href="/path-base/routing/link-outside-app-target/target"]');
+		await page.click('[href="/path-base/routing/link-outside-app-target/target/"]');
 		await expect(page.locator('h2')).toHaveText('target: 0');
 	});
 });