Repository: sveltejs/kit
Pull request #5262 (2022-06-24 15:05:10)

[docs] suggest npm create rather than npm init
Suggested in https://github.com/sveltejs/sites/pull/352, which would also need to be merged if we want to do this

I think this is a good change somce it uses a command that will also work with pnpm whereas init does not

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

Latest commit: 8355fc362f81db1cc9f5c773240fcda583263ac5

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/create?filename=.changeset/three-rivers-bathe.md&value=---%0A%22kit.svelte.dev%22%3A%20patch%0A---%0A%0A%5Bdocs%5D%20suggest%20npm%20create%20rather%20than%20npm%20init%0A)



Patch:
diff --git a/.changeset/brave-jars-smile.md b/.changeset/brave-jars-smile.md
new file mode 100644
index 000000000..34430f490
--- /dev/null
+++ b/.changeset/brave-jars-smile.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[chore] Prerendering URL is now a subclass instead of a proxy
diff --git a/.changeset/light-rings-trade.md b/.changeset/light-rings-trade.md
new file mode 100644
index 000000000..881fd8fcd
--- /dev/null
+++ b/.changeset/light-rings-trade.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+Enhance docs on importing types in app.d.ts
diff --git a/.changeset/lovely-foxes-visit.md b/.changeset/lovely-foxes-visit.md
new file mode 100644
index 000000000..973061457
--- /dev/null
+++ b/.changeset/lovely-foxes-visit.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+Use ESM eslint config files
diff --git a/.changeset/neat-monkeys-dream.md b/.changeset/neat-monkeys-dream.md
new file mode 100644
index 000000000..4c6ee0d0a
--- /dev/null
+++ b/.changeset/neat-monkeys-dream.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] support vite.config.js on Windows
diff --git a/.changeset/poor-points-live.md b/.changeset/poor-points-live.md
new file mode 100644
index 000000000..b289568c0
--- /dev/null
+++ b/.changeset/poor-points-live.md
@@ -0,0 +1,5 @@
+---
+"@sveltejs/kit": patch
+---
+
+Allow both string and URL as the first argument of `$app/navigation#goto`
diff --git a/.changeset/proud-chicken-unite.md b/.changeset/proud-chicken-unite.md
new file mode 100644
index 000000000..66b6d2b09
--- /dev/null
+++ b/.changeset/proud-chicken-unite.md
@@ -0,0 +1,5 @@
+---
+'create-svelte': patch
+---
+
+fix formatting for initial package.json
diff --git a/.changeset/short-lamps-sing.md b/.changeset/short-lamps-sing.md
new file mode 100644
index 000000000..dc389e2aa
--- /dev/null
+++ b/.changeset/short-lamps-sing.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+rename `goto(href)` to `goto(url)`
diff --git a/.changeset/slow-shirts-retire.md b/.changeset/slow-shirts-retire.md
new file mode 100644
index 000000000..5b2d99ef6
--- /dev/null
+++ b/.changeset/slow-shirts-retire.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Add types for @sveltejs/kit/experimental/vite
diff --git a/.changeset/twenty-ads-turn.md b/.changeset/twenty-ads-turn.md
new file mode 100644
index 000000000..b40f76f66
--- /dev/null
+++ b/.changeset/twenty-ads-turn.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: port flag doesn't work in preview
diff --git a/documentation/docs/00-introduction.md b/documentation/docs/00-introduction.md
index def484bf2..a667c9070 100644
--- a/documentation/docs/00-introduction.md
+++ b/documentation/docs/00-introduction.md
@@ -20,10 +20,10 @@ You don't need to know Svelte to understand the rest of this guide, but it will
 
 ### Getting started
 
-The easiest way to start building a SvelteKit app is to run `npm init`:
+The easiest way to start building a SvelteKit app is to run `npm create`:
 
 ```bash
-npm init svelte my-app
+npm create svelte my-app
 cd my-app
 npm install
 npm run dev
diff --git a/packages/create-svelte/index.js b/packages/create-svelte/index.js
index 849b9ba07..0cbcf5999 100755
--- a/packages/create-svelte/index.js
+++ b/packages/create-svelte/index.js
@@ -74,7 +74,7 @@ function write_common_files(cwd, options, name) {
 	pkg.devDependencies = sort_keys(pkg.devDependencies);
 	pkg.name = to_valid_package_name(name);
 
-	fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, '\t'));
+	fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, '\t') + '\n');
 }
 
 /**
diff --git a/packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.cjs b/packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.js
similarity index 96%
rename from packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.cjs
rename to packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.js
index 3ccf435f0..1d79a06d0 100644
--- a/packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.cjs
+++ b/packages/create-svelte/shared/+eslint+prettier+typescript/.eslintrc.js
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
 	root: true,
 	parser: '@typescript-eslint/parser',
 	extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
diff --git a/packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.cjs b/packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.js
similarity index 93%
rename from packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.cjs
rename to packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.js
index fab32bfc9..0ca10dff4 100644
--- a/packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.cjs
+++ b/packages/create-svelte/shared/+eslint+prettier-typescript/.eslintrc.js
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
 	root: true,
 	extends: ['eslint:recommended', 'prettier'],
 	plugins: ['svelte3'],
diff --git a/packages/create-svelte/shared/+eslint+typescript/.eslintrc.cjs b/packages/create-svelte/shared/+eslint+typescript/.eslintrc.js
similarity index 96%
rename from packages/create-svelte/shared/+eslint+typescript/.eslintrc.cjs
rename to packages/create-svelte/shared/+eslint+typescript/.eslintrc.js
index 13b641403..cb6b93728 100644
--- a/packages/create-svelte/shared/+eslint+typescript/.eslintrc.cjs
+++ b/packages/create-svelte/shared/+eslint+typescript/.eslintrc.js
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
 	root: true,
 	parser: '@typescript-eslint/parser',
 	extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
diff --git a/packages/create-svelte/shared/+eslint-typescript/.eslintrc.cjs b/packages/create-svelte/shared/+eslint-typescript/.eslintrc.js
similarity index 93%
rename from packages/create-svelte/shared/+eslint-typescript/.eslintrc.cjs
rename to packages/create-svelte/shared/+eslint-typescript/.eslintrc.js
index 845ea51cd..da76bf23e 100644
--- a/packages/create-svelte/shared/+eslint-typescript/.eslintrc.cjs
+++ b/packages/create-svelte/shared/+eslint-typescript/.eslintrc.js
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
 	root: true,
 	extends: ['eslint:recommended'],
 	plugins: ['svelte3'],
diff --git a/packages/create-svelte/templates/default/src/app.d.ts b/packages/create-svelte/templates/default/src/app.d.ts
index 57a579197..9ca010a6d 100644
--- a/packages/create-svelte/templates/default/src/app.d.ts
+++ b/packages/create-svelte/templates/default/src/app.d.ts
@@ -2,6 +2,7 @@
 
 // See https://kit.svelte.dev/docs/types#app
 // for information about these interfaces
+// and what to do when importing types
 declare namespace App {
 	interface Locals {
 		userid: string;
diff --git a/packages/create-svelte/templates/skeleton/src/app.d.ts b/packages/create-svelte/templates/skeleton/src/app.d.ts
index 121720c58..b28d84056 100644
--- a/packages/create-svelte/templates/skeleton/src/app.d.ts
+++ b/packages/create-svelte/templates/skeleton/src/app.d.ts
@@ -2,6 +2,7 @@
 
 // See https://kit.svelte.dev/docs/types#app
 // for information about these interfaces
+// and what to do when importing types
 declare namespace App {
 	// interface Locals {}
 	// interface Platform {}
diff --git a/packages/kit/.gitignore b/packages/kit/.gitignore
index a1519ebbd..88f731c73 100644
--- a/packages/kit/.gitignore
+++ b/packages/kit/.gitignore
@@ -3,9 +3,12 @@
 /assets/*
 /dist
 /docs
-/test/**/.svelte-kit
 /test/**/build
 !/src/vite/build/adapt/fixtures/*/.svelte-kit
 !/test/node_modules
 /test/apps/basics/test/errors.json
-.custom-out-dir
\ No newline at end of file
+.custom-out-dir
+
+# these are already ignored by the top level .gitignore
+# repeating them here as a faux prettier ignore
+.svelte-kit
diff --git a/packages/kit/src/cli.js b/packages/kit/src/cli.js
index 1dcff209a..d08ac2f3e 100755
--- a/packages/kit/src/cli.js
+++ b/packages/kit/src/cli.js
@@ -4,8 +4,9 @@ import path from 'path';
 import colors from 'kleur';
 import sade from 'sade';
 import * as vite from 'vite';
-import { load_config } from './core/config/index.js';
 import { networkInterfaces, release } from 'os';
+import { pathToFileURL } from 'url';
+import { load_config } from './core/config/index.js';
 import { coalesce_to_error } from './utils/error.js';
 
 /** @param {unknown} e */
@@ -289,7 +290,7 @@ export async function get_vite_config(svelte_config) {
 	for (const file of ['vite.config.js', 'vite.config.mjs', 'vite.config.cjs']) {
 		if (fs.existsSync(file)) {
 			// TODO warn here if config.kit.vite was specified
-			const module = await import(path.resolve(file));
+			const module = await import(pathToFileURL(file).toString());
 			return {
 				...module.default,
 				configFile: false
diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js
index e098ab428..b844f637f 100644
--- a/packages/kit/src/runtime/client/client.js
+++ b/packages/kit/src/runtime/client/client.js
@@ -156,16 +156,18 @@ export function create_client({ target, session, base, trailing_slash }) {
 	let token;
 
 	/**
-	 * @param {string} href
+	 * @param {string | URL} url
 	 * @param {{ noscroll?: boolean; replaceState?: boolean; keepfocus?: boolean; state?: any }} opts
 	 * @param {string[]} redirect_chain
 	 */
 	async function goto(
-		href,
+		url,
 		{ noscroll = false, replaceState = false, keepfocus = false, state = {} },
 		redirect_chain
 	) {
-		const url = new URL(href, get_base_uri(document));
+		if (typeof url === 'string') {
+			url = new URL(url, get_base_uri(document));
+		}
 
 		if (router_enabled) {
 			return navigate({
diff --git a/packages/kit/src/runtime/server/page/load_node.js b/packages/kit/src/runtime/server/page/load_node.js
index b925a2776..f14bc75a6 100644
--- a/packages/kit/src/runtime/server/page/load_node.js
+++ b/packages/kit/src/runtime/server/page/load_node.js
@@ -2,8 +2,7 @@ import * as cookie from 'cookie';
 import * as set_cookie_parser from 'set-cookie-parser';
 import { normalize } from '../../load.js';
 import { respond } from '../index.js';
-import { LoadURL, is_root_relative, resolve } from '../../../utils/url.js';
-import { create_prerendering_url_proxy } from './utils.js';
+import { LoadURL, PrerenderingURL, is_root_relative, resolve } from '../../../utils/url.js';
 import { is_pojo, lowercase_keys, normalize_request_method } from '../utils.js';
 import { coalesce_to_error } from '../../../utils/error.js';
 import { domain_matches, path_matches } from './cookie.js';
@@ -84,7 +83,7 @@ export async function load_node({
 	} else if (module.load) {
 		/** @type {import('types').LoadEvent} */
 		const load_input = {
-			url: state.prerendering ? create_prerendering_url_proxy(event.url) : new LoadURL(event.url),
+			url: state.prerendering ? new PrerenderingURL(event.url) : new LoadURL(event.url),
 			params: event.params,
 			props: shadow.body || {},
 			routeId: event.routeId,
diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js
index e3fd38e38..d6de690a0 100644
--- a/packages/kit/src/runtime/server/page/render.js
+++ b/packages/kit/src/runtime/server/page/render.js
@@ -4,8 +4,8 @@ import { coalesce_to_error } from '../../../utils/error.js';
 import { hash } from '../../hash.js';
 import { render_json_payload_script } from '../../../utils/escape.js';
 import { s } from '../../../utils/misc.js';
-import { create_prerendering_url_proxy } from './utils.js';
 import { Csp, csp_ready } from './csp.js';
+import { PrerenderingURL } from '../../../utils/url.js';
 
 // TODO rename this function/module
 
@@ -109,7 +109,7 @@ export async function render_response({
 				routeId: event.routeId,
 				status,
 				stuff,
-				url: state.prerendering ? create_prerendering_url_proxy(event.url) : event.url
+				url: state.prerendering ? new PrerenderingURL(event.url) : event.url
 			},
 			components: branch.map(({ node }) => node.module.default)
 		};
diff --git a/packages/kit/src/runtime/server/page/utils.js b/packages/kit/src/runtime/server/page/utils.js
deleted file mode 100644
index 25a6684bc..000000000
--- a/packages/kit/src/runtime/server/page/utils.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @param {URL} url */
-export function create_prerendering_url_proxy(url) {
-	return new Proxy(url, {
-		get: (target, prop, receiver) => {
-			if (prop === 'search' || prop === 'searchParams') {
-				throw new Error(`Cannot access url.${prop} on a page with prerendering enabled`);
-			}
-			return Reflect.get(target, prop, receiver);
-		}
-	});
-}
diff --git a/packages/kit/src/utils/url.js b/packages/kit/src/utils/url.js
index 61a7d79ee..1b4169efb 100644
--- a/packages/kit/src/utils/url.js
+++ b/packages/kit/src/utils/url.js
@@ -61,3 +61,15 @@ export class LoadURL extends URL {
 		);
 	}
 }
+
+export class PrerenderingURL extends URL {
+	/** @returns {string} */
+	get search() {
+		throw new Error('Cannot access url.search on a page with prerendering enabled');
+	}
+
+	/** @returns {URLSearchParams} */
+	get searchParams() {
+		throw new Error('Cannot access url.searchParams on a page with prerendering enabled');
+	}
+}
diff --git a/packages/kit/src/utils/url.spec.js b/packages/kit/src/utils/url.spec.js
index 167f3f454..2eb362af9 100644
--- a/packages/kit/src/utils/url.spec.js
+++ b/packages/kit/src/utils/url.spec.js
@@ -1,82 +1,129 @@
-import { test } from 'uvu';
+import { suite } from 'uvu';
 import * as assert from 'uvu/assert';
-import { resolve, normalize_path } from './url.js';
-
-test('resolves a root-relative path', () => {
-	assert.equal(resolve('/a/b/c', '/x/y/z'), '/x/y/z');
-});
-
-test('resolves a relative path without a leading .', () => {
-	assert.equal(resolve('/a/b/c', 'd'), '/a/b/d');
-});
-
-test('resolves a relative path with trailing /', () => {
-	assert.equal(resolve('/a/b/c', 'd/'), '/a/b/d/');
-});
-
-test('resolves a relative path with leading .', () => {
-	assert.equal(resolve('/a/b/c', './d'), '/a/b/d');
-});
-
-test('resolves a relative path with . in the middle', () => {
-	assert.equal(resolve('/a/b/c', 'd/./e/./f'), '/a/b/d/e/f');
-});
-
-test('resolves a relative path with leading ..', () => {
-	assert.equal(resolve('/a/b/c', '../d'), '/a/d');
-});
-
-test('resolves a relative path with .. in the middle', () => {
-	assert.equal(resolve('/a/b/c', 'd/./e/../f'), '/a/b/d/f');
-});
-
-test('resolves a relative path with extraneous leading ..', () => {
-	assert.equal(resolve('/a/b/c', '../../../../../d'), '/d');
-});
-
-test('resolves a root-relative path with .', () => {
-	assert.equal(resolve('/a/b/c', '/x/./y/../z'), '/x/z');
-});
-
-test('resolves a protocol-relative path', () => {
-	assert.equal(resolve('/a/b/c', '//example.com/foo'), '//example.com/foo');
+import { resolve, normalize_path, LoadURL, PrerenderingURL } from './url.js';
+
+/**
+ *
+ * @param {string} name
+ * @param {(suite: import('uvu').Test<import('uvu').Context>) => void} fn
+ */
+function describe(name, fn) {
+	const s = suite(name);
+	fn(s);
+	s.run();
+}
+
+describe('resolve', (test) => {
+	test('resolves a root-relative path', () => {
+		assert.equal(resolve('/a/b/c', '/x/y/z'), '/x/y/z');
+	});
+
+	test('resolves a relative path without a leading .', () => {
+		assert.equal(resolve('/a/b/c', 'd'), '/a/b/d');
+	});
+
+	test('resolves a relative path with trailing /', () => {
+		assert.equal(resolve('/a/b/c', 'd/'), '/a/b/d/');
+	});
+
+	test('resolves a relative path with leading .', () => {
+		assert.equal(resolve('/a/b/c', './d'), '/a/b/d');
+	});
+
+	test('resolves a relative path with . in the middle', () => {
+		assert.equal(resolve('/a/b/c', 'd/./e/./f'), '/a/b/d/e/f');
+	});
+
+	test('resolves a relative path with leading ..', () => {
+		assert.equal(resolve('/a/b/c', '../d'), '/a/d');
+	});
+
+	test('resolves a relative path with .. in the middle', () => {
+		assert.equal(resolve('/a/b/c', 'd/./e/../f'), '/a/b/d/f');
+	});
+
+	test('resolves a relative path with extraneous leading ..', () => {
+		assert.equal(resolve('/a/b/c', '../../../../../d'), '/d');
+	});
+
+	test('resolves a root-relative path with .', () => {
+		assert.equal(resolve('/a/b/c', '/x/./y/../z'), '/x/z');
+	});
+
+	test('resolves a protocol-relative path', () => {
+		assert.equal(resolve('/a/b/c', '//example.com/foo'), '//example.com/foo');
+	});
+
+	test('resolves an absolute path', () => {
+		assert.equal(resolve('/a/b/c', 'https://example.com/foo'), 'https://example.com/foo');
+	});
+
+	test('handles schemes like tel: and mailto:', () => {
+		assert.equal(resolve('/a/b/c', 'mailto:hello@svelte.dev'), 'mailto:hello@svelte.dev');
+	});
 });
 
-test('resolves an absolute path', () => {
-	assert.equal(resolve('/a/b/c', 'https://example.com/foo'), 'https://example.com/foo');
+describe('normalize_path', (test) => {
+	test('normalizes paths', () => {
+		/** @type {Record<string, { ignore: string, always: string, never: string }>} */
+		const paths = {
+			'/': {
+				ignore: '/',
+				always: '/',
+				never: '/'
+			},
+			'/foo': {
+				ignore: '/foo',
+				always: '/foo/',
+				never: '/foo'
+			},
+			'/foo/': {
+				ignore: '/foo/',
+				always: '/foo/',
+				never: '/foo'
+			}
+		};
+
+		for (const path in paths) {
+			const { ignore, always, never } = paths[path];
+
+			assert.equal(normalize_path(path, 'ignore'), ignore);
+			assert.equal(normalize_path(path, 'always'), always);
+			assert.equal(normalize_path(path, 'never'), never);
+		}
+	});
 });
 
-test('handles schemes like tel: and mailto:', () => {
-	assert.equal(resolve('/a/b/c', 'mailto:hello@svelte.dev'), 'mailto:hello@svelte.dev');
+describe('LoadURL', (test) => {
+	test('throws an error when its hash property is accessed', () => {
+		/**
+		 * @type {URL}
+		 */
+		const url = new LoadURL('https://kit.svelte.dev/docs');
+
+		assert.throws(
+			() => url.hash,
+			'url.hash is inaccessible from load. Consider accessing hash from the page store within the script tag of your component.'
+		);
+	});
 });
 
-test('normalizes paths', () => {
-	/** @type {Record<string, { ignore: string, always: string, never: string }>} */
-	const paths = {
-		'/': {
-			ignore: '/',
-			always: '/',
-			never: '/'
-		},
-		'/foo': {
-			ignore: '/foo',
-			always: '/foo/',
-			never: '/foo'
-		},
-		'/foo/': {
-			ignore: '/foo/',
-			always: '/foo/',
-			never: '/foo'
-		}
-	};
-
-	for (const path in paths) {
-		const { ignore, always, never } = paths[path];
-
-		assert.equal(normalize_path(path, 'ignore'), ignore);
-		assert.equal(normalize_path(path, 'always'), always);
-		assert.equal(normalize_path(path, 'never'), never);
-	}
+describe('PrerenderingURL', (test) => {
+	test('throws an error when its search property is accessed', () => {
+		/**
+		 * @type {URL}
+		 */
+		const url = new PrerenderingURL('https://kit.svelte.dev/docs');
+
+		/**
+		 * @type {Array<'search' | 'searchParams'>}
+		 */
+		const props = ['search', 'searchParams'];
+		props.forEach((prop) => {
+			assert.throws(
+				() => url[prop],
+				'Cannot access url.search on a page with prerendering enabled'
+			);
+		});
+	});
 });
-
-test.run();
diff --git a/packages/kit/src/vite/index.js b/packages/kit/src/vite/index.js
index 8c96da350..dd645d8cf 100644
--- a/packages/kit/src/vite/index.js
+++ b/packages/kit/src/vite/index.js
@@ -73,11 +73,13 @@ function kit() {
 	/** @type {import('types').ManifestData} */
 	let manifest_data;
 
-	/** @type {{
+	/**
+	 * @type {{
 	 *   build_dir: string;
 	 *   output_dir: string;
 	 *   client_out_dir: string;
-	 * }} */
+	 * }}
+	 */
 	let paths;
 
 	return {
@@ -146,7 +148,7 @@ function kit() {
 					}
 				},
 				preview: {
-					port: 3000,
+					port: config.preview?.port ?? 3000,
 					strictPort: true
 				},
 				resolve: {
diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts
index 6cdceffd3..25d22b297 100644
--- a/packages/kit/types/ambient.d.ts
+++ b/packages/kit/types/ambient.d.ts
@@ -17,13 +17,29 @@
  *
  * By populating these interfaces, you will gain type safety when using `event.locals`, `event.platform`, `session` and `stuff`.
  *
- * Note that since it's an ambient declaration file, you can't use `import` statements — instead, use the `import(...)` function:
+ * Note that since it's an ambient declaration file, you have to be careful when using `import` statements. Once you add an `import`
+ * at the top level, the declaration file is no longer considered ambient and you lose access to these typings in other files.
+ * To avoid this, either use the `import(...)` function:
  *
  * ```ts
  * interface Locals {
  * 	user: import('$lib/types').User;
  * }
  * ```
+ * Or wrap the namespace with `declare global`:
+ * ```ts
+ * import { User } from '$lib/types';
+ *
+ * declare global {
+ * 	namespace App {
+ * 		interface Locals {
+ * 			user: User;
+ * 		}
+ * 		// ...
+ * 	}
+ * }
+ * ```
+ *
  */
 declare namespace App {
 	/**
@@ -106,16 +122,16 @@ declare module '$app/navigation' {
 	 */
 	export function disableScrollHandling(): void;
 	/**
-	 * Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `href`.
+	 * Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `url`.
 	 *
-	 * @param href Where to navigate to
+	 * @param url Where to navigate to
 	 * @param opts.replaceState If `true`, will replace the current `history` entry rather than creating a new one with `pushState`
 	 * @param opts.noscroll If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
 	 * @param opts.keepfocus If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
 	 * @param opts.state The state of the new/updated history entry
 	 */
 	export function goto(
-		href: string,
+		url: string | URL,
 		opts?: { replaceState?: boolean; noscroll?: boolean; keepfocus?: boolean; state?: any }
 	): Promise<void>;
 	/**
@@ -318,3 +334,12 @@ declare module '@sveltejs/kit/node' {
 	): Promise<Request>;
 	export function setResponse(res: import('http').ServerResponse, response: Response): void;
 }
+
+declare module '@sveltejs/kit/experimental/vite' {
+	import { Plugin } from 'vite';
+
+	/**
+	 * Returns the SvelteKit Vite plugins.
+	 */
+	export function sveltekit(): Plugin[];
+}
diff --git a/sites/kit.svelte.dev/src/routes/index.svelte b/sites/kit.svelte.dev/src/routes/index.svelte
index f4e31b376..26dffff48 100644
--- a/sites/kit.svelte.dev/src/routes/index.svelte
+++ b/sites/kit.svelte.dev/src/routes/index.svelte
@@ -82,7 +82,7 @@
 		</div>
 
 		<div slot="how">
-			<pre><code>npm init <span class="orange-highlight">svelte</span> my-app
+			<pre><code>npm create <span class="orange-highlight">svelte</span> my-app
 cd my-app
 npm install
 npm run dev -- --open</code></pre>


Test patch:
diff --git a/packages/kit/test/apps/options-2/svelte.config.js b/packages/kit/test/apps/options-2/svelte.config.js
index 5d46d5f64..29ef3a0e1 100644
--- a/packages/kit/test/apps/options-2/svelte.config.js
+++ b/packages/kit/test/apps/options-2/svelte.config.js
@@ -1,5 +1,3 @@
-import * as path from 'path';
-
 /** @type {import('@sveltejs/kit').Config} */
 const config = {
 	kit: {
@@ -8,16 +6,6 @@ const config = {
 		},
 		serviceWorker: {
 			register: false
-		},
-		vite: {
-			server: {
-				// TODO: required to support ipv6, remove on vite 3
-				// https://github.com/vitejs/vite/issues/7075
-				host: 'localhost',
-				fs: {
-					allow: [path.resolve('../../../src')]
-				}
-			}
 		}
 	}
 };
diff --git a/packages/kit/test/apps/options-2/vite.config.js b/packages/kit/test/apps/options-2/vite.config.js
new file mode 100644
index 000000000..f9b84890d
--- /dev/null
+++ b/packages/kit/test/apps/options-2/vite.config.js
@@ -0,0 +1,17 @@
+import * as path from 'path';
+import { sveltekit } from '@sveltejs/kit/experimental/vite';
+
+/** @type {import('vite').UserConfig} */
+const config = {
+	plugins: [sveltekit()],
+	server: {
+		// TODO: required to support ipv6, remove on vite 3
+		// https://github.com/vitejs/vite/issues/7075
+		host: 'localhost',
+		fs: {
+			allow: [path.resolve('../../../src')]
+		}
+	}
+};
+
+export default config;
diff --git a/packages/kit/test/utils.d.ts b/packages/kit/test/utils.d.ts
index aea4c9148..e6a7ace33 100644
--- a/packages/kit/test/utils.d.ts
+++ b/packages/kit/test/utils.d.ts
@@ -32,7 +32,7 @@ export const config: PlaywrightTestConfig;
 export const start_server: (
 	handler: (req: IncomingMessage, res: ServerResponse) => void,
 	start?: number
-) => {
+) => Promise<{
 	server: Server;
 	port: number;
-};
+}>;
diff --git a/packages/kit/test/utils.js b/packages/kit/test/utils.js
index 003e0a859..dab0c55d3 100644
--- a/packages/kit/test/utils.js
+++ b/packages/kit/test/utils.js
@@ -171,10 +171,8 @@ export const config = {
 };
 
 /**
- *
  * @param {(req: http.IncomingMessage, res: http.ServerResponse) => void} handler
  * @param {number} [start]
- * @returns
  */
 export async function start_server(handler, start = 4000) {
 	const port = await ports.find(start);