Repository: sveltejs/kit
Pull request #6233 (2022-08-24 18:21:24)

only output logs if something goes titsup
this should make failures a bit easier to spot in the wall of CI text

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

Latest commit: 56f64bffee3cb79f3296ef72746a549c151b4f6e

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/quiet-adapter-static-tests?filename=.changeset/mean-pears-happen.md&value=---%0A%22%40sveltejs%2Fadapter-static%22%3A%20patch%0A---%0A%0Aonly%20output%20logs%20if%20something%20goes%20titsup%0A)



Patch:
diff --git a/.changeset/afraid-games-jog.md b/.changeset/afraid-games-jog.md
new file mode 100644
index 000000000..18ae59c66
--- /dev/null
+++ b/.changeset/afraid-games-jog.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] prerender routes in a (group)
diff --git a/.changeset/early-bulldogs-smile.md b/.changeset/early-bulldogs-smile.md
new file mode 100644
index 000000000..488e1a694
--- /dev/null
+++ b/.changeset/early-bulldogs-smile.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+Create TypeScript/JSDoc/vanilla versions of shared template .ts files
diff --git a/.changeset/healthy-penguins-fail.md b/.changeset/healthy-penguins-fail.md
new file mode 100644
index 000000000..8b8b0792a
--- /dev/null
+++ b/.changeset/healthy-penguins-fail.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+Create vite.config.ts when creating TypeScript project
diff --git a/.changeset/moody-plums-mate.md b/.changeset/moody-plums-mate.md
new file mode 100644
index 000000000..0441520ac
--- /dev/null
+++ b/.changeset/moody-plums-mate.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+Invalidate data after form submission
diff --git a/.changeset/pre.json b/.changeset/pre.json
index d46bbd95b..273331419 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -36,6 +36,7 @@
   "changesets": [
     "afraid-eels-tease",
     "afraid-flowers-train",
+    "afraid-games-jog",
     "afraid-llamas-matter",
     "afraid-oranges-doubt",
     "angry-crabs-walk",
@@ -975,6 +976,7 @@
     "strong-apples-walk",
     "strong-carrots-work",
     "strong-cats-wonder",
+    "strong-cooks-run",
     "strong-cooks-turn",
     "strong-cups-yell",
     "strong-files-obey",
diff --git a/.changeset/strong-cooks-run.md b/.changeset/strong-cooks-run.md
new file mode 100644
index 000000000..18b6984a3
--- /dev/null
+++ b/.changeset/strong-cooks-run.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] only generate blank non-SSR pages when prerendering is enabled
diff --git a/documentation/docs/01-project-structure.md b/documentation/docs/01-project-structure.md
index 93b637949..737c5b9f8 100644
--- a/documentation/docs/01-project-structure.md
+++ b/documentation/docs/01-project-structure.md
@@ -38,7 +38,7 @@ The `src` directory contains the meat of your project.
 - `routes` contains the [routes](/docs/routing) of your application
 - `app.html` is your page template — an HTML document containing the following placeholders:
   - `%sveltekit.head%` — `<link>` and `<script>` elements needed by the app, plus any `<svelte:head>` content
-  - `%sveltekit.body%` — the markup for a rendered page
+  - `%sveltekit.body%` — the markup for a rendered page. Typically this lives inside a `<div>` or other element, rather than directly inside `<body>`, to prevent bugs caused by browser extensions injecting elements that are then destroyed by the hydration process
   - `%sveltekit.assets%` — either [`paths.assets`](/docs/configuration#paths), if specified, or a relative path to [`paths.base`](/docs/configuration#base)
   - `%sveltekit.nonce%` — a [CSP](/docs/configuration#csp) nonce for manually included links and scripts, if used
 - `hooks.js` (optional) contains your application's [hooks](/docs/hooks)
diff --git a/documentation/docs/05-load.md b/documentation/docs/05-load.md
index f2f9f65fb..b38a211f2 100644
--- a/documentation/docs/05-load.md
+++ b/documentation/docs/05-load.md
@@ -327,6 +327,8 @@ If an _unexpected_ error is thrown, SvelteKit will invoke [`handleError`](/docs/
 
 To redirect users, use the `redirect` helper from `@sveltejs/kit` to specify the location to which they should be redirected alongside a `3xx` status code.
 
+> There is a known bug with `redirect`: it will currently fail during client-side navigation, due to [#5952](https://github.com/sveltejs/kit/issues/5952)
+
 ```diff
 /// file: src/routes/admin/+layout.server.js
 -import { error } from '@sveltejs/kit';
diff --git a/documentation/docs/18-assets.md b/documentation/docs/18-assets.md
index 83217ad24..670a627dc 100644
--- a/documentation/docs/18-assets.md
+++ b/documentation/docs/18-assets.md
@@ -2,7 +2,7 @@
 title: Asset handling
 ---
 
-### Importing
+### Caching and inlining
 
 [Vite will automatically process imported assets](https://vitejs.dev/guide/assets.html) for improved performance. Hashes will be added to the filenames so that they can be cached and assets smaller than `assetsInlineLimit` will be inlined.
 
@@ -14,7 +14,7 @@ title: Asset handling
 <img alt="The project logo" src={logo} />
 ```
 
-If you prefer to reference assets directly in the markup, you can use a preprocessor such as [svelte-preprocess-import-assets](https://github.com/bluwy/svelte-preprocess-import-assets) or [svelte-image](https://github.com/matyunya/svelte-image).
+If you prefer to reference assets directly in the markup, you can use a preprocessor such as [svelte-preprocess-import-assets](https://github.com/bluwy/svelte-preprocess-import-assets).
 
 For assets included via the CSS `url()` function, you may find the [`experimental.useVitePreprocess`](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#usevitepreprocess) option useful:
 
@@ -29,6 +29,6 @@ export default {
 };
 ```
 
-### Optimization
+### Transforming
 
-You may wish to utilize compressed image formats such as `.webp` or `.avif` or responsive images that serve a different size based on your device's screen. For images that are included statically in your project you may use a preprocessor like [svimg](https://github.com/xiphux/svimg) or a Vite plugin such as [vite-imagetools](https://github.com/JonasKruckenberg/imagetools).
+You may wish to transform your images to output compressed image formats such as `.webp` or `.avif`, responsive images with different sizes for different devices, or images with the EXIF data stripped for privacy. For images that are included statically, you may use a Vite plugin such as [vite-imagetools](https://github.com/JonasKruckenberg/imagetools). You may also consider a CDN, which can serve the appropriate transformed image based on the `Accept` HTTP header and query string parameters.
diff --git a/packages/adapter-static/package.json b/packages/adapter-static/package.json
index 9c0a100da..28fa9863b 100644
--- a/packages/adapter-static/package.json
+++ b/packages/adapter-static/package.json
@@ -32,6 +32,6 @@
 		"svelte": "^3.48.0",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	}
 }
diff --git a/packages/create-svelte/scripts/build-templates.js b/packages/create-svelte/scripts/build-templates.js
index c9d21f9a0..d2450f7d2 100644
--- a/packages/create-svelte/scripts/build-templates.js
+++ b/packages/create-svelte/scripts/build-templates.js
@@ -206,22 +206,41 @@ async function generate_shared() {
 		}
 
 		if (name.endsWith('.ts') && !include.includes('typescript')) {
+			// file includes types in TypeScript and JSDoc —
+			// create .js file, with and without JSDoc
+			const js = convert_typescript(contents);
 			const js_name = name.replace(/\.ts$/, '.js');
-			shared.add(js_name);
 
+			// typescript
 			files.push({
-				name: js_name,
-				include: [...include],
-				exclude: [...exclude, 'typescript'],
-				contents: convert_typescript(contents)
+				name,
+				include: [...include, 'typescript'],
+				exclude,
+				contents: strip_jsdoc(contents)
 			});
 
-			include.push('typescript');
-		}
+			// checkjs
+			files.push({
+				name: js_name,
+				include: [...include, 'checkjs'],
+				exclude,
+				contents: js
+			});
 
-		shared.add(name);
+			// no typechecking
+			files.push({
+				name: js_name,
+				include,
+				exclude: [...exclude, 'typescript', 'checkjs'],
+				contents: strip_jsdoc(js)
+			});
 
-		files.push({ name, include, exclude, contents });
+			shared.add(name);
+			shared.add(js_name);
+		} else {
+			shared.add(name);
+			files.push({ name, include, exclude, contents });
+		}
 	});
 
 	files.sort((a, b) => a.include.length + a.exclude.length - (b.include.length + b.exclude.length));
diff --git a/packages/create-svelte/shared/vite.config.ts b/packages/create-svelte/shared/vite.config.ts
new file mode 100644
index 000000000..60ef89c74
--- /dev/null
+++ b/packages/create-svelte/shared/vite.config.ts
@@ -0,0 +1,9 @@
+import { sveltekit } from '@sveltejs/kit/vite';
+import type { UserConfig } from 'vite';
+
+/** @type {import('vite').UserConfig} */
+const config: UserConfig = {
+	plugins: [sveltekit()]
+};
+
+export default config;
diff --git a/packages/create-svelte/templates/default/package.json b/packages/create-svelte/templates/default/package.json
index ce127a154..5766fd226 100644
--- a/packages/create-svelte/templates/default/package.json
+++ b/packages/create-svelte/templates/default/package.json
@@ -13,7 +13,7 @@
 		"svelte": "^3.48.0",
 		"svelte-preprocess": "^4.10.6",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.4"
+		"vite": "^3.0.9"
 	},
 	"type": "module",
 	"dependencies": {
diff --git a/packages/create-svelte/templates/default/src/lib/form.ts b/packages/create-svelte/templates/default/src/lib/form.ts
index f4f1153ff..49894f6d8 100644
--- a/packages/create-svelte/templates/default/src/lib/form.ts
+++ b/packages/create-svelte/templates/default/src/lib/form.ts
@@ -86,7 +86,7 @@ export function enhance(
 
 				const url = new URL(form.action);
 				url.search = url.hash = '';
-				invalidate(url.href);
+				invalidate();
 			} else if (error) {
 				error({ data, form, error: null, response });
 			} else {
diff --git a/packages/create-svelte/templates/default/vite.config.js b/packages/create-svelte/templates/default/vite.config.js
index 874705053..9f6d10066 100644
--- a/packages/create-svelte/templates/default/vite.config.js
+++ b/packages/create-svelte/templates/default/vite.config.js
@@ -1,8 +1,15 @@
+import path from 'path';
 import { sveltekit } from '@sveltejs/kit/vite';
 
 /** @type {import('vite').UserConfig} */
 const config = {
-	plugins: [sveltekit()]
+	plugins: [sveltekit()],
+
+	server: {
+		fs: {
+			allow: [path.resolve('../../../kit')]
+		}
+	}
 };
 
 export default config;
diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md
index ab704e2fb..779dbb06a 100644
--- a/packages/kit/CHANGELOG.md
+++ b/packages/kit/CHANGELOG.md
@@ -1,5 +1,17 @@
 # @sveltejs/kit
 
+## 1.0.0-next.437
+
+### Patch Changes
+
+- [fix] only generate blank non-SSR pages when prerendering is enabled ([#6251](https://github.com/sveltejs/kit/pull/6251))
+
+## 1.0.0-next.436
+
+### Patch Changes
+
+- [fix] prerender routes in a (group) ([#6232](https://github.com/sveltejs/kit/pull/6232))
+
 ## 1.0.0-next.435
 
 ### Patch Changes
diff --git a/packages/kit/package.json b/packages/kit/package.json
index 15169ce54..b10bb7077 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/kit",
-	"version": "1.0.0-next.435",
+	"version": "1.0.0-next.437",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -39,7 +39,7 @@
 		"tiny-glob": "^0.2.9",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"peerDependencies": {
 		"svelte": "^3.44.0",
diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js
index 03b7bb68a..e434d947f 100644
--- a/packages/kit/src/core/adapt/builder.js
+++ b/packages/kit/src/core/adapt/builder.js
@@ -5,6 +5,7 @@ import { pipeline } from 'stream';
 import { promisify } from 'util';
 import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
 import { generate_manifest } from '../generate_manifest/index.js';
+import { get_path } from '../../utils/routing.js';
 
 /**
  * Creates the Builder which is passed to adapters for building the application.
@@ -23,7 +24,7 @@ export function create_builder({ config, build_data, prerendered, log }) {
 	/** @param {import('types').RouteData} route */
 	// TODO routes should come pre-filtered
 	function not_prerendered(route) {
-		const path = route.page && !route.id.includes('[') && `/${route.id}`;
+		const path = route.page && get_path(route.id);
 		if (path) {
 			return !prerendered_paths.has(path) && !prerendered_paths.has(path + '/');
 		}
diff --git a/packages/kit/src/core/prerender/prerender.js b/packages/kit/src/core/prerender/prerender.js
index 410aa0e5b..985cf29f6 100644
--- a/packages/kit/src/core/prerender/prerender.js
+++ b/packages/kit/src/core/prerender/prerender.js
@@ -9,6 +9,8 @@ import { crawl } from './crawl.js';
 import { escape_html_attr } from '../../utils/escape.js';
 import { logger } from '../utils.js';
 import { load_config } from '../config/index.js';
+import { compact } from '../../utils/array.js';
+import { get_path } from '../../utils/routing.js';
 
 /**
  * @typedef {import('types').PrerenderErrorHandler} PrerenderErrorHandler
@@ -341,11 +343,10 @@ export async function prerender() {
 	if (config.prerender.enabled) {
 		for (const entry of config.prerender.entries) {
 			if (entry === '*') {
-				/** @type {import('types').ManifestData} */
-				const { routes } = (await import(pathToFileURL(manifest_path).href)).manifest._;
-				const entries = routes
-					.map((route) => (route.page && !route.id.includes('[') ? `/${route.id}` : ''))
-					.filter(Boolean);
+				/** @type {import('types').SSRManifest} */
+				const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
+				const { routes } = manifest._;
+				const entries = compact(routes.map((route) => route.page && get_path(route.id)));
 
 				for (const entry of entries) {
 					enqueue(null, config.paths.base + entry); // TODO can we pre-normalize these?
diff --git a/packages/kit/src/core/sync/create_manifest_data/index.js b/packages/kit/src/core/sync/create_manifest_data/index.js
index d39282fa4..906e0d9cd 100644
--- a/packages/kit/src/core/sync/create_manifest_data/index.js
+++ b/packages/kit/src/core/sync/create_manifest_data/index.js
@@ -82,6 +82,7 @@ function create_matchers(config, cwd) {
  * @param {string} fallback
  */
 function create_routes_and_nodes(cwd, config, fallback) {
+	/** @type {Map<string, import('types').RouteData>} */
 	const route_map = new Map();
 
 	/** @type {Map<string, import('./types').Part[][]>} */
diff --git a/packages/kit/src/runtime/server/page/index.js b/packages/kit/src/runtime/server/page/index.js
index ebe1f005d..737943603 100644
--- a/packages/kit/src/runtime/server/page/index.js
+++ b/packages/kit/src/runtime/server/page/index.js
@@ -104,6 +104,27 @@ export async function render_page(event, route, page, options, state, resolve_op
 		const should_prerender_data = nodes.some((node) => node?.server);
 		const data_pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`;
 
+		// it's crucial that we do this before returning the non-SSR response, otherwise
+		// SvelteKit will erroneously believe that the path has been prerendered,
+		// causing functions to be omitted from the manifesst generated later
+		const should_prerender =
+			leaf_node.shared?.prerender ?? leaf_node.server?.prerender ?? options.prerender.default;
+		if (should_prerender) {
+			const mod = leaf_node.server;
+			if (mod && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) {
+				throw new Error('Cannot prerender pages that have endpoints with mutative methods');
+			}
+		} else if (state.prerendering) {
+			// if the page isn't marked as prerenderable (or is explicitly
+			// marked NOT prerenderable, if `prerender.default` is `true`),
+			// then bail out at this point
+			if (!should_prerender) {
+				return new Response(undefined, {
+					status: 204
+				});
+			}
+		}
+
 		if (!resolve_opts.ssr) {
 			return await render_response({
 				branch: [],
@@ -123,24 +144,6 @@ export async function render_page(event, route, page, options, state, resolve_op
 			});
 		}
 
-		const should_prerender =
-			leaf_node.shared?.prerender ?? leaf_node.server?.prerender ?? options.prerender.default;
-		if (should_prerender) {
-			const mod = leaf_node.server;
-			if (mod && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) {
-				throw new Error('Cannot prerender pages that have endpoints with mutative methods');
-			}
-		} else if (state.prerendering) {
-			// if the page isn't marked as prerenderable (or is explicitly
-			// marked NOT prerenderable, if `prerender.default` is `true`),
-			// then bail out at this point
-			if (!should_prerender) {
-				return new Response(undefined, {
-					status: 204
-				});
-			}
-		}
-
 		/** @type {Array<Loaded | null>} */
 		let branch = [];
 
diff --git a/packages/kit/src/utils/routing.js b/packages/kit/src/utils/routing.js
index 3ff8c9244..67c6e0c6a 100644
--- a/packages/kit/src/utils/routing.js
+++ b/packages/kit/src/utils/routing.js
@@ -96,6 +96,15 @@ export function affects_path(segment) {
 	return !/^\([^)]+\)$/.test(segment);
 }
 
+/**
+ * Turns a route ID into a path, if possible
+ * @param {string} id
+ */
+export function get_path(id) {
+	if (id.includes('[')) return null;
+	return `/${id.split('/').filter(affects_path).join('/')}`;
+}
+
 /**
  * @param {RegExpMatchArray} match
  * @param {string[]} names
diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js
index c6ecdb9ef..fdf17f074 100644
--- a/packages/kit/src/vite/index.js
+++ b/packages/kit/src/vite/index.js
@@ -58,9 +58,7 @@ const enforced_config = {
 	root: true
 };
 
-/**
- * @return {import('vite').Plugin[]}
- */
+/** @return {import('vite').Plugin[]} */
 export function sveltekit() {
 	return [...svelte(), kit()];
 }
diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts
index 678de3ebe..f0a9efcef 100644
--- a/packages/kit/types/ambient.d.ts
+++ b/packages/kit/types/ambient.d.ts
@@ -151,7 +151,7 @@ declare module '$app/navigation' {
 		opts?: { replaceState?: boolean; noscroll?: boolean; keepfocus?: boolean; state?: any }
 	): Promise<void>;
 	/**
-	 * Causes any `load` functions belonging to the currently active page to re-run if they `fetch` the resource in question, or re-fetches data from a page endpoint if the invalidated resource is the page itself. If no argument is given, all resources will be invalidated. Returns a `Promise` that resolves when the page is subsequently updated.
+	 * Causes any `load` functions belonging to the currently active page to re-run if they `fetch` the resource in question. If no argument is given, all resources will be invalidated. Returns a `Promise` that resolves when the page is subsequently updated.
 	 * @param dependency The invalidated resource
 	 */
 	export function invalidate(dependency?: string | ((href: string) => boolean)): Promise<void>;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a621b9837..0967ad444 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -149,7 +149,7 @@ importers:
       svelte: ^3.48.0
       typescript: ^4.7.4
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
@@ -158,17 +158,17 @@ importers:
       svelte: 3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/adapter-static/test/apps/prerendered:
     specifiers:
       '@sveltejs/kit': workspace:*
       svelte: ^3.48.0
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../../../kit
       svelte: 3.48.0
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/adapter-static/test/apps/spa:
     specifiers:
@@ -176,13 +176,13 @@ importers:
       '@sveltejs/kit': workspace:*
       sirv-cli: ^2.0.2
       svelte: ^3.48.0
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/adapter-node': link:../../../../adapter-node
       '@sveltejs/kit': link:../../../../kit
       sirv-cli: 2.0.2
       svelte: 3.48.0
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/adapter-vercel:
     specifiers:
@@ -247,7 +247,7 @@ importers:
       svelte: ^3.48.0
       svelte-preprocess: ^4.10.6
       typescript: ^4.7.4
-      vite: ^3.0.4
+      vite: ^3.0.9
     dependencies:
       '@fontsource/fira-mono': 4.5.8
       '@lukeed/uuid': 2.0.0
@@ -258,7 +258,7 @@ importers:
       svelte: 3.48.0
       svelte-preprocess: 4.10.7_lvfi2wesz6u4l5rfbnetbucfmm
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/create-svelte/templates/skeleton:
     specifiers:
@@ -294,9 +294,9 @@ importers:
       typescript: ^4.7.4
       undici: ^5.8.1
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     dependencies:
-      '@sveltejs/vite-plugin-svelte': 1.0.1_svelte@3.48.0+vite@3.0.8
+      '@sveltejs/vite-plugin-svelte': 1.0.1_svelte@3.48.0+vite@3.0.9
       cookie: 0.5.0
       devalue: 2.0.1
       kleur: 4.1.5
@@ -323,7 +323,7 @@ importers:
       svelte-preprocess: 4.10.7_lvfi2wesz6u4l5rfbnetbucfmm
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/amp:
     specifiers:
@@ -334,7 +334,7 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/amp': link:../../../../amp
       '@sveltejs/kit': link:../../..
@@ -343,7 +343,7 @@ importers:
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/basics:
     specifiers:
@@ -353,7 +353,7 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       cross-env: 7.0.3
@@ -361,7 +361,7 @@ importers:
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/dev-only:
     specifiers:
@@ -371,7 +371,7 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       cross-env: 7.0.3
@@ -379,7 +379,7 @@ importers:
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/options:
     specifiers:
@@ -388,14 +388,14 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       cross-env: 7.0.3
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/options-2:
     specifiers:
@@ -405,7 +405,7 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/adapter-node': link:../../../../adapter-node
       '@sveltejs/kit': link:../../..
@@ -413,7 +413,7 @@ importers:
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/apps/writes:
     specifiers:
@@ -423,7 +423,7 @@ importers:
       svelte: ^3.48.0
       svelte-check: ^2.7.1
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       cross-env: 7.0.3
@@ -431,7 +431,7 @@ importers:
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/prerendering/basics:
     specifiers:
@@ -440,14 +440,14 @@ importers:
       svelte-check: ^2.7.1
       typescript: ^4.7.4
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/prerendering/fallback:
     specifiers:
@@ -456,14 +456,14 @@ importers:
       svelte-check: ^2.7.1
       typescript: ^4.7.4
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/prerendering/options:
     specifiers:
@@ -472,14 +472,14 @@ importers:
       svelte-check: ^2.7.1
       typescript: ^4.7.4
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/prerendering/paths-base:
     specifiers:
@@ -488,14 +488,14 @@ importers:
       svelte-check: ^2.7.1
       typescript: ^4.7.4
       uvu: ^0.5.3
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/kit/test/prerendering/trailing-slash:
     specifiers:
@@ -504,14 +504,14 @@ importers:
       svelte-check: ^2.7.1
       typescript: ^4.7.4
       uvu: ^0.5.4
-      vite: ^3.0.8
+      vite: ^3.0.9
     devDependencies:
       '@sveltejs/kit': link:../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.7.4
       uvu: 0.5.4
-      vite: 3.0.8
+      vite: 3.0.9
 
   packages/migrate:
     specifiers:
@@ -572,7 +572,7 @@ importers:
       shiki-twoslash: ^3.0.2
       svelte: ^3.48.0
       typescript: ^4.7.4
-      vite: ^3.0.8
+      vite: ^3.0.9
       vite-imagetools: ^4.0.3
     devDependencies:
       '@sveltejs/adapter-auto': link:../../packages/adapter-auto
@@ -588,7 +588,7 @@ importers:
       shiki-twoslash: 3.1.0
       svelte: 3.48.0
       typescript: 4.7.4
-      vite: 3.0.8
+      vite: 3.0.9
       vite-imagetools: 4.0.4
 
 packages:
@@ -1019,7 +1019,7 @@ packages:
       golden-fleece: 1.0.9
     dev: true
 
-  /@sveltejs/vite-plugin-svelte/1.0.1_svelte@3.48.0+vite@3.0.8:
+  /@sveltejs/vite-plugin-svelte/1.0.1_svelte@3.48.0+vite@3.0.9:
     resolution: {integrity: sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==}
     engines: {node: ^14.18.0 || >= 16}
     peerDependencies:
@@ -1037,7 +1037,7 @@ packages:
       magic-string: 0.26.2
       svelte: 3.48.0
       svelte-hmr: 0.14.12_svelte@3.48.0
-      vite: 3.0.8
+      vite: 3.0.9
     transitivePeerDependencies:
       - supports-color
     dev: false
@@ -4495,8 +4495,8 @@ packages:
       magic-string: 0.26.2
     dev: true
 
-  /vite/3.0.8:
-    resolution: {integrity: sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==}
+  /vite/3.0.9:
+    resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==}
     engines: {node: ^14.18.0 || >=16.0.0}
     hasBin: true
     peerDependencies:
diff --git a/sites/kit.svelte.dev/package.json b/sites/kit.svelte.dev/package.json
index eeeb76b29..1a2cd1c4a 100644
--- a/sites/kit.svelte.dev/package.json
+++ b/sites/kit.svelte.dev/package.json
@@ -21,7 +21,7 @@
 		"shiki-twoslash": "^3.0.2",
 		"svelte": "^3.48.0",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8",
+		"vite": "^3.0.9",
 		"vite-imagetools": "^4.0.3"
 	},
 	"type": "module"
diff --git a/sites/kit.svelte.dev/src/lib/docs/client/docs.css b/sites/kit.svelte.dev/src/lib/docs/client/docs.css
index f6e9da40a..8688c0dae 100644
--- a/sites/kit.svelte.dev/src/lib/docs/client/docs.css
+++ b/sites/kit.svelte.dev/src/lib/docs/client/docs.css
@@ -210,7 +210,7 @@
 }
 
 .content ul > li {
-	margin: 0.5em 0;
+	margin: 0.5em 0 !important;
 }
 
 /** hacky overrides to allow filenames inside code blocks —


Test patch:
diff --git a/packages/adapter-static/test/apps/prerendered/package.json b/packages/adapter-static/test/apps/prerendered/package.json
index b38399527..ef581f5c6 100644
--- a/packages/adapter-static/test/apps/prerendered/package.json
+++ b/packages/adapter-static/test/apps/prerendered/package.json
@@ -10,7 +10,7 @@
 	"devDependencies": {
 		"@sveltejs/kit": "workspace:*",
 		"svelte": "^3.48.0",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/adapter-static/test/apps/spa/package.json b/packages/adapter-static/test/apps/spa/package.json
index a3144238b..859b0929f 100644
--- a/packages/adapter-static/test/apps/spa/package.json
+++ b/packages/adapter-static/test/apps/spa/package.json
@@ -12,7 +12,7 @@
 		"@sveltejs/kit": "workspace:*",
 		"sirv-cli": "^2.0.2",
 		"svelte": "^3.48.0",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/adapter-static/test/utils.js b/packages/adapter-static/test/utils.js
index be3c90f03..914f80ec4 100644
--- a/packages/adapter-static/test/utils.js
+++ b/packages/adapter-static/test/utils.js
@@ -1,4 +1,4 @@
-import child_process from 'child_process';
+import { execSync } from 'child_process';
 import fs from 'fs';
 import http from 'http';
 import { fileURLToPath } from 'url';
@@ -30,11 +30,16 @@ export function run(app, callback) {
 
 			rimraf(`${cwd}/build`);
 
-			await spawn('npm run build', {
-				cwd,
-				stdio: 'inherit',
-				shell: true
-			});
+			try {
+				execSync(`npm run build`, { cwd, stdio: 'pipe' });
+				console.log(`✅ build successful`);
+			} catch (e) {
+				console.error(`❌ failed to build ${app}`);
+				console.error(`---\nstdout:\n${e.stdout}`);
+				console.error(`---\nstderr:\n${e.stderr}`);
+				console.groupEnd();
+				assert.unreachable(e.message);
+			}
 
 			context.cwd = cwd;
 			const handler = sirv(`${cwd}/build`, {
@@ -69,26 +74,6 @@ export function run(app, callback) {
 	suite.run();
 }
 
-const parameterRegex = new RegExp('"[^"]+"|[\\S]+', 'g');
-
-/**
- * @param {string} str
- * @param {child_process.SpawnOptions} opts
- */
-function spawn(str, opts) {
-	return new Promise((fulfil, reject) => {
-		const [cmd, ...args] = str.match(parameterRegex);
-
-		const child = child_process.spawn(cmd, args, opts);
-
-		child.on('error', reject);
-
-		child.on('exit', () => {
-			fulfil();
-		});
-	});
-}
-
 /**
  * @param {number} port
  * @param {(req: http.IncomingMessage, res: http.ServerResponse) => void} handler
diff --git a/packages/kit/test/apps/amp/package.json b/packages/kit/test/apps/amp/package.json
index 1576cdbfc..0cc8e95fa 100644
--- a/packages/kit/test/apps/amp/package.json
+++ b/packages/kit/test/apps/amp/package.json
@@ -19,7 +19,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/apps/amp/playwright.config.js b/packages/kit/test/apps/amp/playwright.config.js
index e83b1fd33..e97e615a6 100644
--- a/packages/kit/test/apps/amp/playwright.config.js
+++ b/packages/kit/test/apps/amp/playwright.config.js
@@ -1,6 +1,6 @@
 import { config } from '../../utils.js';
 
-config.webServer && (config.webServer.timeout = 15000); // AMP validator needs a long time to get moving
+config.webServer && (config.webServer.timeout = 45000); // AMP validator needs a long time to get moving
 
 // remove any projects with javaScriptEnabled
 const projects = config.projects || [];
diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json
index a58156c56..e29507332 100644
--- a/packages/kit/test/apps/basics/package.json
+++ b/packages/kit/test/apps/basics/package.json
@@ -18,7 +18,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/apps/dev-only/package.json b/packages/kit/test/apps/dev-only/package.json
index e222d532c..cbba7da8d 100644
--- a/packages/kit/test/apps/dev-only/package.json
+++ b/packages/kit/test/apps/dev-only/package.json
@@ -16,7 +16,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/apps/options-2/package.json b/packages/kit/test/apps/options-2/package.json
index 747b2bef6..dd612d2c4 100644
--- a/packages/kit/test/apps/options-2/package.json
+++ b/packages/kit/test/apps/options-2/package.json
@@ -18,7 +18,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/apps/options/package.json b/packages/kit/test/apps/options/package.json
index 51e96620d..48734ac77 100644
--- a/packages/kit/test/apps/options/package.json
+++ b/packages/kit/test/apps/options/package.json
@@ -17,7 +17,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/apps/writes/package.json b/packages/kit/test/apps/writes/package.json
index 3aeed6b2b..3c6cab88a 100644
--- a/packages/kit/test/apps/writes/package.json
+++ b/packages/kit/test/apps/writes/package.json
@@ -18,7 +18,7 @@
 		"svelte": "^3.48.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/basics/package.json b/packages/kit/test/prerendering/basics/package.json
index 92c4a6bfa..2a60f53f9 100644
--- a/packages/kit/test/prerendering/basics/package.json
+++ b/packages/kit/test/prerendering/basics/package.json
@@ -15,7 +15,7 @@
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/basics/src/routes/(grouped)/grouped/+page.svelte b/packages/kit/test/prerendering/basics/src/routes/(grouped)/grouped/+page.svelte
new file mode 100644
index 000000000..addccd133
--- /dev/null
+++ b/packages/kit/test/prerendering/basics/src/routes/(grouped)/grouped/+page.svelte
@@ -0,0 +1,1 @@
+<h1>grouped</h1>
diff --git a/packages/kit/test/prerendering/basics/test/test.js b/packages/kit/test/prerendering/basics/test/test.js
index b38c6ab65..2a450e965 100644
--- a/packages/kit/test/prerendering/basics/test/test.js
+++ b/packages/kit/test/prerendering/basics/test/test.js
@@ -205,4 +205,9 @@ test('$env - includes environment variables', () => {
 	assert.match(content, /.*PUBLIC_DYNAMIC: accessible anywhere\/evaluated at run time.*/gs);
 });
 
+test('prerenders a page in a (group)', () => {
+	const content = read('grouped.html');
+	assert.ok(content.includes('<h1>grouped</h1>'));
+});
+
 test.run();
diff --git a/packages/kit/test/prerendering/basics/vite.config.js b/packages/kit/test/prerendering/basics/vite.config.js
index 3c59318ad..a2fe148d6 100644
--- a/packages/kit/test/prerendering/basics/vite.config.js
+++ b/packages/kit/test/prerendering/basics/vite.config.js
@@ -6,8 +6,13 @@ const config = {
 	build: {
 		minify: false
 	},
+
 	clearScreen: false,
+
+	logLevel: 'silent',
+
 	plugins: [sveltekit()],
+
 	server: {
 		fs: {
 			allow: [path.resolve('../../../src')]
diff --git a/packages/kit/test/prerendering/fallback/package.json b/packages/kit/test/prerendering/fallback/package.json
index 8b6a09282..9835390fe 100644
--- a/packages/kit/test/prerendering/fallback/package.json
+++ b/packages/kit/test/prerendering/fallback/package.json
@@ -15,7 +15,7 @@
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/fallback/vite.config.js b/packages/kit/test/prerendering/fallback/vite.config.js
index 3c59318ad..a2fe148d6 100644
--- a/packages/kit/test/prerendering/fallback/vite.config.js
+++ b/packages/kit/test/prerendering/fallback/vite.config.js
@@ -6,8 +6,13 @@ const config = {
 	build: {
 		minify: false
 	},
+
 	clearScreen: false,
+
+	logLevel: 'silent',
+
 	plugins: [sveltekit()],
+
 	server: {
 		fs: {
 			allow: [path.resolve('../../../src')]
diff --git a/packages/kit/test/prerendering/options/package.json b/packages/kit/test/prerendering/options/package.json
index 1fba5f302..7c75411c6 100644
--- a/packages/kit/test/prerendering/options/package.json
+++ b/packages/kit/test/prerendering/options/package.json
@@ -15,7 +15,7 @@
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/options/vite.config.js b/packages/kit/test/prerendering/options/vite.config.js
index 3c59318ad..a2fe148d6 100644
--- a/packages/kit/test/prerendering/options/vite.config.js
+++ b/packages/kit/test/prerendering/options/vite.config.js
@@ -6,8 +6,13 @@ const config = {
 	build: {
 		minify: false
 	},
+
 	clearScreen: false,
+
+	logLevel: 'silent',
+
 	plugins: [sveltekit()],
+
 	server: {
 		fs: {
 			allow: [path.resolve('../../../src')]
diff --git a/packages/kit/test/prerendering/paths-base/package.json b/packages/kit/test/prerendering/paths-base/package.json
index 1f743ca22..10eb75923 100644
--- a/packages/kit/test/prerendering/paths-base/package.json
+++ b/packages/kit/test/prerendering/paths-base/package.json
@@ -15,7 +15,7 @@
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.3",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/paths-base/vite.config.js b/packages/kit/test/prerendering/paths-base/vite.config.js
index 3c59318ad..a2fe148d6 100644
--- a/packages/kit/test/prerendering/paths-base/vite.config.js
+++ b/packages/kit/test/prerendering/paths-base/vite.config.js
@@ -6,8 +6,13 @@ const config = {
 	build: {
 		minify: false
 	},
+
 	clearScreen: false,
+
+	logLevel: 'silent',
+
 	plugins: [sveltekit()],
+
 	server: {
 		fs: {
 			allow: [path.resolve('../../../src')]
diff --git a/packages/kit/test/prerendering/trailing-slash/package.json b/packages/kit/test/prerendering/trailing-slash/package.json
index a2c589586..d149c42bf 100644
--- a/packages/kit/test/prerendering/trailing-slash/package.json
+++ b/packages/kit/test/prerendering/trailing-slash/package.json
@@ -15,7 +15,7 @@
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.7.4",
 		"uvu": "^0.5.4",
-		"vite": "^3.0.8"
+		"vite": "^3.0.9"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/prerendering/trailing-slash/vite.config.js b/packages/kit/test/prerendering/trailing-slash/vite.config.js
index 3c59318ad..a2fe148d6 100644
--- a/packages/kit/test/prerendering/trailing-slash/vite.config.js
+++ b/packages/kit/test/prerendering/trailing-slash/vite.config.js
@@ -6,8 +6,13 @@ const config = {
 	build: {
 		minify: false
 	},
+
 	clearScreen: false,
+
+	logLevel: 'silent',
+
 	plugins: [sveltekit()],
+
 	server: {
 		fs: {
 			allow: [path.resolve('../../../src')]