Repository: sveltejs/kit
Pull request #6727 (2022-09-10 23:44:23)

refactor: Graph analysis - unit testing
The first of what I hope will be a long line of PRs leading up to 1.0 that focus on refactoring code to add unit tests and remove integration tests. Our test suites are starting to drag on to infinity, making merging PRs quickly a bit of a chore. Unfortunately, in this case, we haven't been able to remove any integration tests, but I think the unit tests do a much better job of covering all cases in a clean and readable way (that doesn't abuse TypeScript like we used to!). 

We can't remove the integration tests because there's not really a great way to unit test our dependency on Vite and Rollup's module graph implementations. Sure, we could do some dumb and labor-intensive mock of their implementations, but that wouldn't really give us any benefits. We should continue to rely on the integration tests to see how this feature interacts with the real Rollup/Vite environment during dev and build.

Just a note: The graph analysis stuff is pretty self-contained and doesn't really feel at home in a `utils.js` file, so I moved it to its own folder to separate it and its types from the rest of the project.

### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [x] Ideally, include a test that fails without this PR but passes with it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. All changesets should be `patch` until SvelteKit 1.0


changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: 4875d905c666090ff8f39cbac73923d60e65e4f3

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name          | Type  |
| ------------- | ----- |
| @sveltejs/kit | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/sveltejs/kit/new/sejohnson-refactor-and-test-graphs?filename=.changeset/forty-maps-fold.md&value=---%0A%22%40sveltejs%2Fkit%22%3A%20patch%0A---%0A%0Arefactor%3A%20Graph%20analysis%20-%20unit%20testing%0A)



Patch:
diff --git a/.changeset/blue-glasses-compete.md b/.changeset/blue-glasses-compete.md
new file mode 100644
index 000000000..48fdd5011
--- /dev/null
+++ b/.changeset/blue-glasses-compete.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] ActionData type
diff --git a/.changeset/friendly-starfishes-yell.md b/.changeset/friendly-starfishes-yell.md
new file mode 100644
index 000000000..f68ed9672
--- /dev/null
+++ b/.changeset/friendly-starfishes-yell.md
@@ -0,0 +1,9 @@
+---
+'@sveltejs/adapter-cloudflare': patch
+'@sveltejs/adapter-cloudflare-workers': patch
+'@sveltejs/adapter-netlify': patch
+'@sveltejs/adapter-node': patch
+'@sveltejs/adapter-vercel': patch
+---
+
+Update to esbuild 0.15
diff --git a/.changeset/lovely-sloths-flow.md b/.changeset/lovely-sloths-flow.md
new file mode 100644
index 000000000..c2cfa9d81
--- /dev/null
+++ b/.changeset/lovely-sloths-flow.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[chore] Refactor graph analysis for better unit tests
diff --git a/.changeset/nasty-hornets-sneeze.md b/.changeset/nasty-hornets-sneeze.md
new file mode 100644
index 000000000..61eaa37c0
--- /dev/null
+++ b/.changeset/nasty-hornets-sneeze.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-netlify': patch
+---
+
+[feat] only generate ESM functions
diff --git a/.changeset/pre.json b/.changeset/pre.json
index 34b9774f0..970fe858b 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -349,6 +349,7 @@
     "friendly-dodos-exercise",
     "friendly-eggs-cry",
     "friendly-rivers-argue",
+    "friendly-starfishes-yell",
     "funny-ads-move",
     "funny-keys-appear",
     "funny-needles-talk",
@@ -644,6 +645,7 @@
     "nasty-boats-bathe",
     "nasty-buttons-invent",
     "nasty-falcons-ring",
+    "nasty-hornets-sneeze",
     "nasty-lemons-provide",
     "nasty-llamas-lay",
     "nasty-seahorses-know",
@@ -1079,6 +1081,7 @@
     "stupid-bottles-approve",
     "stupid-countries-sneeze",
     "stupid-dolls-fly",
+    "stupid-eyes-attend",
     "stupid-laws-jog",
     "stupid-maps-hide",
     "stupid-owls-provide",
@@ -1113,6 +1116,7 @@
     "tame-rings-cry",
     "tasty-cars-love",
     "tasty-donkeys-wait",
+    "tasty-geese-burn",
     "tasty-geese-hug",
     "tasty-islands-drive",
     "tasty-squids-share",
@@ -1212,6 +1216,7 @@
     "twelve-snakes-tan",
     "twelve-stingrays-cry",
     "twenty-ads-turn",
+    "twenty-apricots-grin",
     "twenty-carpets-enjoy",
     "twenty-dogs-shout",
     "twenty-dryers-hope",
diff --git a/.changeset/tasty-geese-burn.md b/.changeset/tasty-geese-burn.md
new file mode 100644
index 000000000..e7834786d
--- /dev/null
+++ b/.changeset/tasty-geese-burn.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] docs links in generated and published types
diff --git a/.changeset/twenty-apricots-grin.md b/.changeset/twenty-apricots-grin.md
new file mode 100644
index 000000000..b80319f65
--- /dev/null
+++ b/.changeset/twenty-apricots-grin.md
@@ -0,0 +1,6 @@
+---
+"@sveltejs/adapter-node": patch
+"@sveltejs/adapter-static": patch
+---
+
+Improve performance by compressing in parallel
diff --git a/documentation/docs/00-introduction.md b/documentation/docs/00-introduction.md
index afe9aec69..3278c0469 100644
--- a/documentation/docs/00-introduction.md
+++ b/documentation/docs/00-introduction.md
@@ -12,7 +12,7 @@ title: Introduction
 
 SvelteKit is a framework for building extremely high-performance web apps.
 
-Building an app with all the modern best practices is fiendishly complicated. Those practices include [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations), so that you load only the minimal required code; [offline support](/docs/service-workers); [prefetching](/docs/link-options#data-sveltekit-prefetch) pages before the user initiates navigation; and [configurable rendering](/docs/page-options) that allows you to render your app [on the server](/docs/appendix#ssr) or [in the browser](/docs/appendix#csr) at runtime or [at build-time](/docs/page-options#prerender). SvelteKit does all the boring stuff for you so that you can get on with the creative part.
+Building an app with all the modern best practices is fiendishly complicated. Those practices include [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations), so that you load only the minimal required code; [offline support](/docs/service-workers); [prefetching](/docs/link-options#data-sveltekit-prefetch) pages before the user initiates navigation; and [configurable rendering](/docs/page-options) that allows you to render your app [on the server](/docs/appendix#ssr) or [in the browser](/docs/appendix#csr-and-spa) at runtime or [at build-time](/docs/appendix#prerendering). SvelteKit does all the boring stuff for you so that you can get on with the creative part.
 
 It uses [Vite](https://vitejs.dev/) with a [Svelte plugin](https://github.com/sveltejs/vite-plugin-svelte) to provide a lightning-fast and feature-rich development experience with [Hot Module Replacement (HMR)](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#hot), where changes to your code are reflected in the browser instantly.
 
@@ -29,7 +29,7 @@ npm install
 npm run dev
 ```
 
-The first command will scaffold a new project in the `my-app` directory asking you if you'd like to set up some basic tooling such as TypeScript. See the FAQ for [pointers on setting up additional tooling](https://kit.svelte.dev/faq#integrations). The subsequent commands will then install its dependencies and start a server on [localhost:5173](http://localhost:5173).
+The first command will scaffold a new project in the `my-app` directory asking you if you'd like to set up some basic tooling such as TypeScript. See the FAQ for [pointers on setting up additional tooling](/faq#integrations). The subsequent commands will then install its dependencies and start a server on [localhost:5173](http://localhost:5173).
 
 There are two basic concepts:
 
diff --git a/documentation/docs/01-project-structure.md b/documentation/docs/01-project-structure.md
index 5d89563a1..5bd093833 100644
--- a/documentation/docs/01-project-structure.md
+++ b/documentation/docs/01-project-structure.md
@@ -40,7 +40,7 @@ The `src` directory contains the meat of your project.
 - `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. 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.assets%` — either [`paths.assets`](/docs/configuration#paths), if specified, or a relative path to [`paths.base`](/docs/configuration#paths)
   - `%sveltekit.nonce%` — a [CSP](/docs/configuration#csp) nonce for manually included links and scripts, if used
 - `error.html` (optional) is the page that is rendered when everything else fails. It can contain the following placeholders:
   - `%sveltekit.status%` — the HTTP status
diff --git a/documentation/docs/02-web-standards.md b/documentation/docs/02-web-standards.md
index 8c5c09a18..1d68b36fc 100644
--- a/documentation/docs/02-web-standards.md
+++ b/documentation/docs/02-web-standards.md
@@ -51,7 +51,7 @@ Most of the time, your endpoints will return complete data, as in the `userAgent
 
 ### URL APIs
 
-URLs are represented by the [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) interface, which includes useful properties like `origin` and `pathname` (and, in the browser, `hash`). This interface shows up in various places — `event.url` in [hooks](/docs/hooks) and [server routes](/docs/routing#server), [`$page.url`](/docs/modules#$app-stores) in [pages](/docs/routing#pages), `from` and `to` in [`beforeNavigate` and `afterNavigate`](/docs/modules#$app-navigation) and so on.
+URLs are represented by the [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) interface, which includes useful properties like `origin` and `pathname` (and, in the browser, `hash`). This interface shows up in various places — `event.url` in [hooks](/docs/hooks) and [server routes](/docs/routing#server), [`$page.url`](/docs/modules#$app-stores) in [pages](/docs/routing#page), `from` and `to` in [`beforeNavigate` and `afterNavigate`](/docs/modules#$app-navigation) and so on.
 
 #### URLSearchParams
 
diff --git a/documentation/docs/04-advanced-routing.md b/documentation/docs/04-advanced-routing.md
index fc665576d..05c1c813f 100644
--- a/documentation/docs/04-advanced-routing.md
+++ b/documentation/docs/04-advanced-routing.md
@@ -47,7 +47,7 @@ src/routes/
 └ +error.svelte
 ```
 
-> `src/routes/a/[...rest]/z/+page.svelte` will match `/a/z` (i.e. there's no parameter at all) as well as `/a/b/z` and `/a/b/c/z` and so on. Make sure you check that the value of the rest parameter is valid, for example using a [matcher](#advanced-routing-matching).
+> `src/routes/a/[...rest]/z/+page.svelte` will match `/a/z` (i.e. there's no parameter at all) as well as `/a/b/z` and `/a/b/c/z` and so on. Make sure you check that the value of the rest parameter is valid, for example using a [matcher](#matching).
 
 ### Matching
 
@@ -88,7 +88,7 @@ SvelteKit needs to know which route is being requested. To do so, it sorts them
 
 - More specific routes are higher priority (e.g. a route with no parameters is more specific than a route with one dynamic parameter, and so on)
 - `+server` files have higher priority than `+page` files
-- Parameters with [matchers](#advanced-routing-matching) (`[name=type]`) are higher priority than those without (`[name]`)
+- Parameters with [matchers](#matching) (`[name=type]`) are higher priority than those without (`[name]`)
 - Rest parameters have lowest priority
 - Ties are resolved alphabetically
 
diff --git a/documentation/docs/05-load.md b/documentation/docs/05-load.md
index 7bcf13c70..d048a2f7a 100644
--- a/documentation/docs/05-load.md
+++ b/documentation/docs/05-load.md
@@ -143,7 +143,7 @@ export async function load({ depends }) {
 - it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request
 - it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context)
 - internal requests (e.g. for `+server.js` routes) go direct to the handler function when running on the server, without the overhead of an HTTP call
-- during server-side rendering, the response will be captured and inlined into the rendered HTML. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](/docs/hooks#hooks-server-js-handle)
+- during server-side rendering, the response will be captured and inlined into the rendered HTML. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](/docs/hooks#server-hooks-handle)
 - during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request
 
 > Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.
@@ -308,7 +308,7 @@ export function load({ locals }) {
 }
 ```
 
-If an _unexpected_ error is thrown, SvelteKit will invoke [`handleError`](/docs/hooks#hooks-server-js-handleerror) and treat it as a 500 Internal Error.
+If an _unexpected_ error is thrown, SvelteKit will invoke [`handleError`](/docs/hooks#shared-hooks-handleerror) and treat it as a 500 Internal Error.
 
 > In development, stack traces for unexpected errors are visible as `$page.error.stack`. In production, stack traces are hidden.
 
@@ -343,7 +343,7 @@ A `load` function will re-run in the following situations:
 - It references a property of `params` whose value has changed
 - It references a property of `url` (such as `url.pathname` or `url.search`) whose value has changed
 - It calls `await parent()` and a parent `load` function re-ran
-- It declared a dependency on a specific URL via [`fetch`](#fetch) or [`depends`](#depends), and that URL was marked invalid with [`invalidate(url)`](/docs/modules#$app-navigation-invalidate)
+- It declared a dependency on a specific URL via [`fetch`](#input-methods-fetch) or [`depends`](#input-methods-depends), and that URL was marked invalid with [`invalidate(url)`](/docs/modules#$app-navigation-invalidate)
 - All active `load` functions were forcibly re-run with [`invalidate()`](/docs/modules#$app-navigation-invalidate)
 
 If a `load` function is triggered to re-run, the page will not remount — instead, it will update with the new `data`. This means that components' internal state is preserved. If this isn't want you want, you can reset whatever you need to reset inside an [`afterNavigate`](/docs/modules#$app-navigation-afternavigate) callback, and/or wrap your component in a [`{#key ...}`](https://svelte.dev/docs#template-syntax-key) block.
diff --git a/documentation/docs/07-hooks.md b/documentation/docs/07-hooks.md
index 86a507e54..810ac0ebe 100644
--- a/documentation/docs/07-hooks.md
+++ b/documentation/docs/07-hooks.md
@@ -9,6 +9,8 @@ There are two hooks files, both optional:
 - `src/hooks.server.js` — your app's server hooks
 - `src/hooks.client.js` — your app's client hooks
 
+Code in these modules will run when the application starts up, making them useful for initializing database clients and so on.
+
 > You can configure the location of these files with [`config.kit.files.hooks`](/docs/configuration#files).
 
 ### Server hooks
@@ -90,7 +92,7 @@ export async function handle({ event, resolve }) {
 
 #### handleFetch
 
-This function allows you to modify (or replace) a `fetch` request for an external resource that happens inside a `load` function that runs on the server (or during pre-rendering).
+This function allows you to modify (or replace) a `fetch` request that happens inside a `load` function that runs on the server (or during pre-rendering).
 
 Or your `load` function might make a request to a public URL like `https://api.yourapp.com` when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).
 
diff --git a/documentation/docs/11-adapters.md b/documentation/docs/11-adapters.md
index 2195b3354..80bee1dd6 100644
--- a/documentation/docs/11-adapters.md
+++ b/documentation/docs/11-adapters.md
@@ -54,7 +54,7 @@ Most adapters will generate static HTML for any [prerenderable](/docs/page-optio
 
 You can also use `adapter-static` to generate single-page apps (SPAs) by specifying a [fallback page](https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode).
 
-> You must ensure [`trailingSlash`](configuration#trailingslash) is set appropriately for your environment. If your host does not render `/a.html` upon receiving a request for `/a` then you will need to set `trailingSlash: 'always'` to create `/a/index.html` instead.
+> You must ensure [`trailingSlash`](/docs/configuration#trailingslash) is set appropriately for your environment. If your host does not render `/a.html` upon receiving a request for `/a` then you will need to set `trailingSlash: 'always'` to create `/a/index.html` instead.
 
 #### Platform-specific context
 
diff --git a/documentation/docs/12-page-options.md b/documentation/docs/12-page-options.md
index 9569e1671..e6a9b0c80 100644
--- a/documentation/docs/12-page-options.md
+++ b/documentation/docs/12-page-options.md
@@ -58,7 +58,7 @@ The basic rule is this: for a page to be prerenderable, any two users hitting it
 
 Note that you can still prerender pages that load data based on the page's parameters, such as a `src/routes/blog/[slug]/+page.svelte` route.
 
-Accessing [`url.searchParams`](/docs/load#input-url) during prerendering is forbidden. If you need to use it, ensure you are only doing so in the browser (for example in `onMount`).
+Accessing [`url.searchParams`](/docs/load#input-properties-url) during prerendering is forbidden. If you need to use it, ensure you are only doing so in the browser (for example in `onMount`).
 
 #### Route conflicts
 
diff --git a/documentation/docs/15-configuration.md b/documentation/docs/15-configuration.md
index ad5dd2bd6..eb62e504b 100644
--- a/documentation/docs/15-configuration.md
+++ b/documentation/docs/15-configuration.md
@@ -184,7 +184,7 @@ An object containing zero or more of the following `string` values:
 - `assets` — a place to put static files that should have stable URLs and undergo no processing, such as `favicon.ico` or `manifest.json`
 - `hooks` — the location of your client and server hooks (see [Hooks](/docs/hooks))
 - `lib` — your app's internal library, accessible throughout the codebase as `$lib`
-- `params` — a directory containing [parameter matchers](/docs/routing#advanced-routing-matching)
+- `params` — a directory containing [parameter matchers](/docs/advanced-routing#matching)
 - `routes` — the files that define the structure of your app (see [Routing](/docs/routing))
 - `serviceWorker` — the location of your service worker's entry point (see [Service workers](/docs/service-workers))
 - `template` — the location of the template for HTML responses
@@ -299,7 +299,7 @@ Whether to remove, append, or ignore trailing slashes when resolving URLs (note
 
 This option also affects [prerendering](/docs/page-options#prerender). If `trailingSlash` is `always`, a route like `/about` will result in an `about/index.html` file, otherwise it will create `about.html`, mirroring static webserver conventions.
 
-> Ignoring trailing slashes is not recommended — the semantics of relative paths differ between the two cases (`./y` from `/x` is `/y`, but from `/x/` is `/x/y`), and `/x` and `/x/` are treated as separate URLs which is harmful to SEO. If you use this option, ensure that you implement logic for conditionally adding or removing trailing slashes from `request.path` inside your [`handle`](/docs/hooks#hooks-server-js-handle) function.
+> Ignoring trailing slashes is not recommended — the semantics of relative paths differ between the two cases (`./y` from `/x` is `/y`, but from `/x/` is `/x/y`), and `/x` and `/x/` are treated as separate URLs which is harmful to SEO. If you use this option, ensure that you implement logic for conditionally adding or removing trailing slashes from `request.path` inside your [`handle`](/docs/hooks#server-hooks-handle) function.
 
 ### version
 
diff --git a/documentation/docs/17-seo.md b/documentation/docs/17-seo.md
index 0a6bb5cf1..5ae9b4333 100644
--- a/documentation/docs/17-seo.md
+++ b/documentation/docs/17-seo.md
@@ -8,7 +8,7 @@ The most important aspect of SEO is to create high-quality content that is widel
 
 #### SSR
 
-While search engines have got better in recent years at indexing content that was rendered with client-side JavaScript, server-side rendered content is indexed more frequently and reliably. SvelteKit employs SSR by default, and while you can disable it in [`handle`](/docs/hooks#hooks-server-js-handle), you should leave it on unless you have a good reason not to.
+While search engines have got better in recent years at indexing content that was rendered with client-side JavaScript, server-side rendered content is indexed more frequently and reliably. SvelteKit employs SSR by default, and while you can disable it in [`handle`](/docs/hooks#server-hooks-handle), you should leave it on unless you have a good reason not to.
 
 > SvelteKit's rendering is highly configurable and you can implement [dynamic rendering](https://developers.google.com/search/docs/advanced/javascript/dynamic-rendering) if necessary. It's not generally recommended, since SSR has other benefits beyond SEO.
 
@@ -18,7 +18,7 @@ Signals such as [Core Web Vitals](https://web.dev/vitals/#core-web-vitals) impac
 
 #### Normalized URLs
 
-SvelteKit redirects pathnames with trailing slashes to ones without (or vice versa depending on your [configuration](configuration#trailingslash)), as duplicate URLs are bad for SEO.
+SvelteKit redirects pathnames with trailing slashes to ones without (or vice versa depending on your [configuration](/docs/configuration#trailingslash)), as duplicate URLs are bad for SEO.
 
 ### Manual setup
 
diff --git a/documentation/docs/19-accessibility.md b/documentation/docs/19-accessibility.md
index aa2247fb9..b725f320f 100644
--- a/documentation/docs/19-accessibility.md
+++ b/documentation/docs/19-accessibility.md
@@ -54,7 +54,7 @@ By default, SvelteKit's page template sets the default language of the document
 <html lang="de">
 ```
 
-If your content is available in multiple languages, you should set the `lang` attribute based on the language of the current page. You can do this with SvelteKit's [handle hook](/docs/hooks#hooks-server-js-handle):
+If your content is available in multiple languages, you should set the `lang` attribute based on the language of the current page. You can do this with SvelteKit's [handle hook](/docs/hooks#server-hooks-handle):
 
 ```html
 /// file: src/app.html
diff --git a/documentation/docs/80-migrating.md b/documentation/docs/80-migrating.md
index f3b17d1e3..7d8750494 100644
--- a/documentation/docs/80-migrating.md
+++ b/documentation/docs/80-migrating.md
@@ -5,7 +5,7 @@ rank: 1
 
 SvelteKit is the successor to Sapper and shares many elements of its design.
 
-If you have an existing Sapper app that you plan to migrate to SvelteKit, there are a number of changes you will need to make. You may find it helpful to view [some examples](https://kit.svelte.dev/docs/additional-resources#examples) while migrating.
+If you have an existing Sapper app that you plan to migrate to SvelteKit, there are a number of changes you will need to make. You may find it helpful to view [some examples](/docs/additional-resources#examples) while migrating.
 
 ### package.json
 
@@ -41,7 +41,7 @@ Your `webpack.config.js` or `rollup.config.js` should be replaced with a `svelte
 
 You will need to add an [adapter](/docs/adapters). `sapper build` is roughly equivalent to [adapter-node](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) while `sapper export` is roughly equivalent to [adapter-static](https://github.com/sveltejs/kit/tree/master/packages/adapter-static), though you might prefer to use an adapter designed for the platform you're deploying to.
 
-If you were using plugins for filetypes that are not automatically handled by [Vite](https://vitejs.dev), you will need to find Vite equivalents and add them to the [Vite config](/docs/configuration#vite).
+If you were using plugins for filetypes that are not automatically handled by [Vite](https://vitejs.dev), you will need to find Vite equivalents and add them to the [Vite config](/docs/project-structure#project-files-vite-config-js).
 
 #### src/client.js
 
@@ -81,7 +81,7 @@ Routes now are made up of the folder name exclusively to remove ambiguity, the f
 | routes/about/index.svelte | routes/about/+page.svelte |
 | routes/about.svelte       | routes/about/+page.svelte |
 
-Your custom error page component should be renamed from `_error.svelte` to `+error.svelte`. Any `_layout.svelte` files should likewise be renamed `+layout.svelte`. [Any other files are ignored](https://kit.svelte.dev/docs/routing#other-files).
+Your custom error page component should be renamed from `_error.svelte` to `+error.svelte`. Any `_layout.svelte` files should likewise be renamed `+layout.svelte`. [Any other files are ignored](/docs/routing#other-files).
 
 #### Imports
 
@@ -97,7 +97,7 @@ As before, pages and layouts can export a function that allows data to be loaded
 
 This function has been renamed from `preload` to [`load`](/docs/load), it now lives in a `+page.js` (or `+layout.js`) next to its `+page.svelte` (or `+layout.svelte`), and its API has changed. Instead of two arguments — `page` and `session` — there is a single `event` argument.
 
-There is no more `this` object, and consequently no `this.fetch`, `this.error` or `this.redirect`. Instead, you can get [`fetch`](https://kit.svelte.dev/docs/load#input-methods-fetch) from the input methods, and both [`error`](https://kit.svelte.dev/docs/load#errors) and [`redirect`](https://kit.svelte.dev/docs/load#redirects) are now thrown.
+There is no more `this` object, and consequently no `this.fetch`, `this.error` or `this.redirect`. Instead, you can get [`fetch`](/docs/load#input-methods-fetch) from the input methods, and both [`error`](/docs/load#errors) and [`redirect`](/docs/load#redirects) are now thrown.
 
 #### Stores
 
@@ -119,7 +119,7 @@ You access them differently in SvelteKit. `stores` is now `getStores`, but in mo
 
 #### Routing
 
-Regex routes are no longer supported. Instead, use [advanced route matching](/docs/routing#advanced-routing-matching).
+Regex routes are no longer supported. Instead, use [advanced route matching](/docs/advanced-routing#matching).
 
 #### Segments
 
@@ -150,7 +150,7 @@ See [the FAQ](/faq#integrations) for detailed information about integrations.
 
 #### HTML minifier
 
-Sapper includes `html-minifier` by default. SvelteKit does not include this, but it can be added as a [hook](/docs/hooks#hooks-server-js-handle):
+Sapper includes `html-minifier` by default. SvelteKit does not include this, but it can be added as a [hook](/docs/hooks#server-hooks-handle):
 
 ```js
 // @filename: ambient.d.ts
diff --git a/packages/adapter-auto/CHANGELOG.md b/packages/adapter-auto/CHANGELOG.md
index b6bf21ca3..d74f6736a 100644
--- a/packages/adapter-auto/CHANGELOG.md
+++ b/packages/adapter-auto/CHANGELOG.md
@@ -1,5 +1,14 @@
 # @sveltejs/adapter-auto
 
+## 1.0.0-next.73
+
+### Patch Changes
+
+- Updated dependencies [[`b32b3ac9`](https://github.com/sveltejs/kit/commit/b32b3ac9c05efebfab5651de9bf5cdd0d4d54c12), [`ee5777e3`](https://github.com/sveltejs/kit/commit/ee5777e33695d2ddf1742a5e1d0144674d48d2d3)]:
+  - @sveltejs/adapter-cloudflare@1.0.0-next.33
+  - @sveltejs/adapter-netlify@1.0.0-next.77
+  - @sveltejs/adapter-vercel@1.0.0-next.74
+
 ## 1.0.0-next.72
 
 ### Patch Changes
diff --git a/packages/adapter-auto/package.json b/packages/adapter-auto/package.json
index a8b922547..d200d512c 100644
--- a/packages/adapter-auto/package.json
+++ b/packages/adapter-auto/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-auto",
-	"version": "1.0.0-next.72",
+	"version": "1.0.0-next.73",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/adapter-cloudflare-workers/CHANGELOG.md b/packages/adapter-cloudflare-workers/CHANGELOG.md
index 334709210..2a0d9c898 100644
--- a/packages/adapter-cloudflare-workers/CHANGELOG.md
+++ b/packages/adapter-cloudflare-workers/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-cloudflare-workers
 
+## 1.0.0-next.55
+
+### Patch Changes
+
+- Update to esbuild 0.15 ([#6740](https://github.com/sveltejs/kit/pull/6740))
+
 ## 1.0.0-next.54
 
 ### Patch Changes
diff --git a/packages/adapter-cloudflare-workers/package.json b/packages/adapter-cloudflare-workers/package.json
index 47bb3a070..769ed805c 100644
--- a/packages/adapter-cloudflare-workers/package.json
+++ b/packages/adapter-cloudflare-workers/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-cloudflare-workers",
-	"version": "1.0.0-next.54",
+	"version": "1.0.0-next.55",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -30,7 +30,7 @@
 	"dependencies": {
 		"@cloudflare/workers-types": "^3.14.0",
 		"@iarna/toml": "^2.2.5",
-		"esbuild": "^0.14.48"
+		"esbuild": "^0.15.6"
 	},
 	"devDependencies": {
 		"@cloudflare/kv-asset-handler": "^0.2.0",
diff --git a/packages/adapter-cloudflare/CHANGELOG.md b/packages/adapter-cloudflare/CHANGELOG.md
index ad4e408b8..b3691a46d 100644
--- a/packages/adapter-cloudflare/CHANGELOG.md
+++ b/packages/adapter-cloudflare/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-cloudflare
 
+## 1.0.0-next.33
+
+### Patch Changes
+
+- Update to esbuild 0.15 ([#6740](https://github.com/sveltejs/kit/pull/6740))
+
 ## 1.0.0-next.32
 
 ### Patch Changes
diff --git a/packages/adapter-cloudflare/README.md b/packages/adapter-cloudflare/README.md
index ac335d69b..d1ed0857a 100644
--- a/packages/adapter-cloudflare/README.md
+++ b/packages/adapter-cloudflare/README.md
@@ -81,11 +81,11 @@ declare namespace App {
 
 ## Notes
 
-Functions contained in the `/functions` directory at the project's root will _not_ be included in the deployment, which is compiled to a [single `_worker.js` file](https://developers.cloudflare.com/pages/platform/functions/#advanced-mode). Functions should be implemented as [endpoints](https://kit.svelte.dev/docs/routing#endpoints) in your SvelteKit app.
+Functions contained in the `/functions` directory at the project's root will _not_ be included in the deployment, which is compiled to a [single `_worker.js` file](https://developers.cloudflare.com/pages/platform/functions/#advanced-mode). Functions should be implemented as [server endpoints](https://kit.svelte.dev/docs/routing#server) in your SvelteKit app.
 
 The [`_headers` and `_redirects`](config files) files specific to Cloudflare Pages can be used for static asset responses (like images) by putting them into the `/static` folder.
 
-However, they will have no effect on responses dynamically rendered by SvelteKit, which should return custom headers or redirect responses from [endpoints](https://kit.svelte.dev/docs/routing#endpoints) or with the [`handle`](https://kit.svelte.dev/docs/hooks#hooks-server-js-handle) hook.
+However, they will have no effect on responses dynamically rendered by SvelteKit, which should return custom headers or redirect responses from [server endpoints](https://kit.svelte.dev/docs/routing#server) or with the [`handle`](https://kit.svelte.dev/docs/hooks#server-hooks-handle) hook.
 
 ## Changelog
 
diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json
index 5054a4f17..89b35dd58 100644
--- a/packages/adapter-cloudflare/package.json
+++ b/packages/adapter-cloudflare/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-cloudflare",
-	"version": "1.0.0-next.32",
+	"version": "1.0.0-next.33",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -32,7 +32,7 @@
 	},
 	"dependencies": {
 		"@cloudflare/workers-types": "^3.14.0",
-		"esbuild": "^0.14.48",
+		"esbuild": "^0.15.6",
 		"worktop": "0.8.0-next.14"
 	},
 	"devDependencies": {
diff --git a/packages/adapter-netlify/CHANGELOG.md b/packages/adapter-netlify/CHANGELOG.md
index 52eadbe17..09d6eb432 100644
--- a/packages/adapter-netlify/CHANGELOG.md
+++ b/packages/adapter-netlify/CHANGELOG.md
@@ -1,5 +1,13 @@
 # @sveltejs/adapter-netlify
 
+## 1.0.0-next.77
+
+### Patch Changes
+
+- Update to esbuild 0.15 ([#6740](https://github.com/sveltejs/kit/pull/6740))
+
+* [feat] only generate ESM functions ([#6760](https://github.com/sveltejs/kit/pull/6760))
+
 ## 1.0.0-next.76
 
 ### Patch Changes
diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js
index cb99dfab4..6d77b17a7 100644
--- a/packages/adapter-netlify/index.js
+++ b/packages/adapter-netlify/index.js
@@ -1,7 +1,6 @@
 import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs';
 import { dirname, join, resolve, posix } from 'path';
 import { fileURLToPath } from 'url';
-import glob from 'tiny-glob/sync.js';
 import esbuild from 'esbuild';
 import toml from '@iarna/toml';
 
@@ -66,10 +65,6 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
 				`\n\n/${builder.config.kit.appDir}/immutable/*\n  cache-control: public\n  cache-control: immutable\n  cache-control: max-age=31536000\n`
 			);
 
-			// for esbuild, use ESM
-			// for zip-it-and-ship-it, use CJS until https://github.com/netlify/zip-it-and-ship-it/issues/750
-			const esm = netlify_config?.functions?.node_bundler === 'esbuild';
-
 			if (edge) {
 				if (split) {
 					throw new Error('Cannot use `split: true` alongside `edge: true`');
@@ -77,7 +72,7 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
 
 				await generate_edge_functions({ builder });
 			} else {
-				await generate_lambda_functions({ builder, esm, split, publish });
+				await generate_lambda_functions({ builder, split, publish });
 			}
 		}
 	};
@@ -148,9 +143,8 @@ async function generate_edge_functions({ builder }) {
  * @param {import('@sveltejs/kit').Builder} params.builder
  * @param { string } params.publish
  * @param { boolean } params.split
- * @param { boolean } params.esm
  */
-async function generate_lambda_functions({ builder, publish, split, esm }) {
+async function generate_lambda_functions({ builder, publish, split }) {
 	builder.mkdirp('.netlify/functions-internal');
 
 	/** @type {string[]} */
@@ -160,19 +154,11 @@ async function generate_lambda_functions({ builder, publish, split, esm }) {
 	const replace = {
 		'0SERVER': './server/index.js' // digit prefix prevents CJS build from using this as a variable name, which would also get replaced
 	};
-	if (esm) {
-		builder.copy(`${files}/esm`, '.netlify', { replace });
-	} else {
-		glob('**/*.js', { cwd: '.netlify/server', filesOnly: true }).forEach((file) => {
-			const filepath = `.netlify/server/${file}`;
-			const input = readFileSync(filepath, 'utf8');
-			const output = esbuild.transformSync(input, { format: 'cjs', target: 'node12' }).code;
-			writeFileSync(filepath, output);
-		});
 
-		builder.copy(`${files}/cjs`, '.netlify', { replace });
-		writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' }));
-	}
+	builder.copy(`${files}/esm`, '.netlify', { replace });
+
+	// Configuring the function to use ESM as the output format.
+	const fn_config = JSON.stringify({ config: { nodeModuleFormat: 'esm' }, version: 1 });
 
 	if (split) {
 		builder.log.minor('Generating serverless functions...');
@@ -201,14 +187,13 @@ async function generate_lambda_functions({ builder, publish, split, esm }) {
 				complete: (entry) => {
 					const manifest = entry.generateManifest({
 						relativePath: '../server',
-						format: esm ? 'esm' : 'cjs'
+						format: 'esm'
 					});
 
-					const fn = esm
-						? `import { init } from '../serverless.js';\n\nexport const handler = init(${manifest});\n`
-						: `const { init } = require('../serverless.js');\n\nexports.handler = init(${manifest});\n`;
+					const fn = `import { init } from '../serverless.js';\n\nexport const handler = init(${manifest});\n`;
 
-					writeFileSync(`.netlify/functions-internal/${name}.js`, fn);
+					writeFileSync(`.netlify/functions-internal/${name}.mjs`, fn);
+					writeFileSync(`.netlify/functions-internal/${name}.json`, fn_config);
 
 					redirects.push(`${pattern} /.netlify/functions/${name} 200`);
 					redirects.push(`${pattern}/__data.js /.netlify/functions/${name} 200`);
@@ -220,14 +205,13 @@ async function generate_lambda_functions({ builder, publish, split, esm }) {
 
 		const manifest = builder.generateManifest({
 			relativePath: '../server',
-			format: esm ? 'esm' : 'cjs'
+			format: 'esm'
 		});
 
-		const fn = esm
-			? `import { init } from '../serverless.js';\n\nexport const handler = init(${manifest});\n`
-			: `const { init } = require('../serverless.js');\n\nexports.handler = init(${manifest});\n`;
+		const fn = `import { init } from '../serverless.js';\n\nexport const handler = init(${manifest});\n`;
 
-		writeFileSync('.netlify/functions-internal/render.js', fn);
+		writeFileSync(`.netlify/functions-internal/render.json`, fn_config);
+		writeFileSync('.netlify/functions-internal/render.mjs', fn);
 		redirects.push('* /.netlify/functions/render 200');
 	}
 
diff --git a/packages/adapter-netlify/package.json b/packages/adapter-netlify/package.json
index b459484f6..8f8c25119 100644
--- a/packages/adapter-netlify/package.json
+++ b/packages/adapter-netlify/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-netlify",
-	"version": "1.0.0-next.76",
+	"version": "1.0.0-next.77",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -33,9 +33,8 @@
 	},
 	"dependencies": {
 		"@iarna/toml": "^2.2.5",
-		"esbuild": "^0.14.48",
-		"set-cookie-parser": "^2.4.8",
-		"tiny-glob": "^0.2.9"
+		"esbuild": "^0.15.6",
+		"set-cookie-parser": "^2.4.8"
 	},
 	"devDependencies": {
 		"@netlify/functions": "^1.0.0",
diff --git a/packages/adapter-node/CHANGELOG.md b/packages/adapter-node/CHANGELOG.md
index 90e59e25c..929eeadae 100644
--- a/packages/adapter-node/CHANGELOG.md
+++ b/packages/adapter-node/CHANGELOG.md
@@ -1,5 +1,13 @@
 # @sveltejs/adapter-node
 
+## 1.0.0-next.90
+
+### Patch Changes
+
+- Update to esbuild 0.15 ([#6740](https://github.com/sveltejs/kit/pull/6740))
+
+* Improve performance by compressing in parallel ([#6710](https://github.com/sveltejs/kit/pull/6710))
+
 ## 1.0.0-next.89
 
 ### Patch Changes
diff --git a/packages/adapter-node/README.md b/packages/adapter-node/README.md
index 2d5a93f21..664b99c55 100644
--- a/packages/adapter-node/README.md
+++ b/packages/adapter-node/README.md
@@ -45,7 +45,7 @@ PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
 
 ### `ADDRESS_HEADER` and `XFF_DEPTH`
 
-The [RequestEvent](https://kit.svelte.dev/docs/types#additional-types-requestevent) object passed to hooks and endpoints includes an `event.clientAddress` property representing the client's IP address. By default this is the connecting `remoteAddress`. If your server is behind one or more proxies (such as a load balancer), this value will contain the innermost proxy's IP address rather than the client's, so we need to specify an `ADDRESS_HEADER` to read the address from:
+The [RequestEvent](https://kit.svelte.dev/docs/types#sveltejs-kit-requestevent) object passed to hooks and endpoints includes an `event.clientAddress` property representing the client's IP address. By default this is the connecting `remoteAddress`. If your server is behind one or more proxies (such as a load balancer), this value will contain the innermost proxy's IP address rather than the client's, so we need to specify an `ADDRESS_HEADER` to read the address from:
 
 ```
 ADDRESS_HEADER=True-Client-IP node build
diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js
index 48a0ac5c3..cc3d0da78 100644
--- a/packages/adapter-node/index.js
+++ b/packages/adapter-node/index.js
@@ -32,8 +32,10 @@ export default function (opts = {}) {
 
 			if (precompress) {
 				builder.log.minor('Compressing assets');
-				await builder.compress(`${out}/client`);
-				await builder.compress(`${out}/prerendered`);
+				await Promise.all([
+					builder.compress(`${out}/client`),
+					builder.compress(`${out}/prerendered`)
+				]);
 			}
 
 			builder.log.minor('Building server');
diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json
index b589fdd6a..656bbba56 100644
--- a/packages/adapter-node/package.json
+++ b/packages/adapter-node/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-node",
-	"version": "1.0.0-next.89",
+	"version": "1.0.0-next.90",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -45,6 +45,6 @@
 		"uvu": "^0.5.3"
 	},
 	"dependencies": {
-		"esbuild": "^0.14.48"
+		"esbuild": "^0.15.6"
 	}
 }
diff --git a/packages/adapter-static/CHANGELOG.md b/packages/adapter-static/CHANGELOG.md
index 1c27b28e9..120da9650 100644
--- a/packages/adapter-static/CHANGELOG.md
+++ b/packages/adapter-static/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-static
 
+## 1.0.0-next.43
+
+### Patch Changes
+
+- Improve performance by compressing in parallel ([#6710](https://github.com/sveltejs/kit/pull/6710))
+
 ## 1.0.0-next.42
 
 ### Patch Changes
diff --git a/packages/adapter-static/README.md b/packages/adapter-static/README.md
index a692e1bdf..bd90b5a2d 100644
--- a/packages/adapter-static/README.md
+++ b/packages/adapter-static/README.md
@@ -92,6 +92,8 @@ export default {
 };
 ```
 
+> How to configure this behaviour does however depend on your hosting solution and is not part of SvelteKit. It is recommended to search the host's documentation on how to redirect requests.
+
 When operating in SPA mode, you can omit the [`prerender`](https://kit.svelte.dev/docs/page-options#prerender) option from your root layout (or set it to `false`, its default value), and only pages that have the `prerender` option set will be prerendered at build time.
 
 SvelteKit will still crawl your app's entry points looking for prerenderable pages. If `svelte-kit build` fails because of pages that can't be loaded outside the browser, you can set `config.kit.prerender.entries` to `[]` to prevent this from happening. (Setting `config.kit.prerender.enabled` to `false` also has this effect, but would prevent the fallback page from being generated.)
diff --git a/packages/adapter-static/index.js b/packages/adapter-static/index.js
index 8f2577e7a..03bdb8ab5 100644
--- a/packages/adapter-static/index.js
+++ b/packages/adapter-static/index.js
@@ -64,15 +64,11 @@ export default function (options) {
 			builder.writePrerendered(pages, { fallback });
 
 			if (precompress) {
+				builder.log.minor('Compressing assets and pages');
 				if (pages === assets) {
-					builder.log.minor('Compressing assets and pages');
 					await builder.compress(assets);
 				} else {
-					builder.log.minor('Compressing assets');
-					await builder.compress(assets);
-
-					builder.log.minor('Compressing pages');
-					await builder.compress(pages);
+					await Promise.all([builder.compress(assets), builder.compress(pages)]);
 				}
 			}
 
diff --git a/packages/adapter-static/package.json b/packages/adapter-static/package.json
index 8dd2269a6..b446f742d 100644
--- a/packages/adapter-static/package.json
+++ b/packages/adapter-static/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-static",
-	"version": "1.0.0-next.42",
+	"version": "1.0.0-next.43",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/adapter-vercel/CHANGELOG.md b/packages/adapter-vercel/CHANGELOG.md
index daf8a1a63..db6440c7b 100644
--- a/packages/adapter-vercel/CHANGELOG.md
+++ b/packages/adapter-vercel/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/adapter-vercel
 
+## 1.0.0-next.74
+
+### Patch Changes
+
+- Update to esbuild 0.15 ([#6740](https://github.com/sveltejs/kit/pull/6740))
+
 ## 1.0.0-next.73
 
 ### Patch Changes
diff --git a/packages/adapter-vercel/README.md b/packages/adapter-vercel/README.md
index 03a2db919..c12ea6f82 100644
--- a/packages/adapter-vercel/README.md
+++ b/packages/adapter-vercel/README.md
@@ -38,7 +38,7 @@ export default {
 
 ### Vercel functions
 
-Vercel functions contained in the `/api` directory at the project's root will _not_ be included in the deployment — these should be implemented as [endpoints](https://kit.svelte.dev/docs/routing#endpoints) in your SvelteKit app.
+Vercel functions contained in the `/api` directory at the project's root will _not_ be included in the deployment — these should be implemented as [server endpoints](https://kit.svelte.dev/docs/routing#server) in your SvelteKit app.
 
 ### Node version
 
diff --git a/packages/adapter-vercel/package.json b/packages/adapter-vercel/package.json
index ad49aaf03..d36d75c92 100644
--- a/packages/adapter-vercel/package.json
+++ b/packages/adapter-vercel/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/adapter-vercel",
-	"version": "1.0.0-next.73",
+	"version": "1.0.0-next.74",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -29,7 +29,7 @@
 	},
 	"dependencies": {
 		"@vercel/nft": "^0.22.0",
-		"esbuild": "^0.14.48"
+		"esbuild": "^0.15.6"
 	},
 	"devDependencies": {
 		"@sveltejs/kit": "workspace:*",
diff --git a/packages/create-svelte/CHANGELOG.md b/packages/create-svelte/CHANGELOG.md
index 6fdb49944..3010c334c 100644
--- a/packages/create-svelte/CHANGELOG.md
+++ b/packages/create-svelte/CHANGELOG.md
@@ -1,5 +1,11 @@
 # create-svelte
 
+## 2.0.0-next.176
+
+### Patch Changes
+
+- SvelteKit 1.0 RC ([#6707](https://github.com/sveltejs/kit/pull/6707))
+
 ## 2.0.0-next.175
 
 ### Patch Changes
diff --git a/packages/create-svelte/README.md b/packages/create-svelte/README.md
index caeef9e55..99cf8e729 100644
--- a/packages/create-svelte/README.md
+++ b/packages/create-svelte/README.md
@@ -17,7 +17,7 @@ import { create } from 'create-svelte';
 
 await create('my-new-app', {
   name: 'my-new-app',
-  template: 'default', // or 'skeleton'
+  template: 'default', // or 'skeleton' or 'skeletonlib'
   types: 'checkjs', // or 'typescript' or null;
   prettier: false,
   eslint: false,
diff --git a/packages/create-svelte/package.json b/packages/create-svelte/package.json
index 3b6e5b329..66c5cbd2f 100644
--- a/packages/create-svelte/package.json
+++ b/packages/create-svelte/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "create-svelte",
-	"version": "2.0.0-next.175",
+	"version": "2.0.0-next.176",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/create-svelte/templates/default/package.json b/packages/create-svelte/templates/default/package.json
index 360ec1230..4371c9c6e 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.8.2",
-		"vite": "3.1.0-beta.2"
+		"vite": "^3.1.0"
 	},
 	"type": "module",
 	"dependencies": {
diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md
index 6e6a36510..e4e472130 100644
--- a/packages/kit/CHANGELOG.md
+++ b/packages/kit/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/kit
 
+## 1.0.0-next.481
+
+### Patch Changes
+
+- [fix] docs links in generated and published types ([#6741](https://github.com/sveltejs/kit/pull/6741))
+
 ## 1.0.0-next.480
 
 ### Patch Changes
diff --git a/packages/kit/package.json b/packages/kit/package.json
index d4c0fcedc..5cc728230 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/kit",
-	"version": "1.0.0-next.480",
+	"version": "1.0.0-next.481",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/kit/scripts/special-types/$env+dynamic+private.md b/packages/kit/scripts/special-types/$env+dynamic+private.md
index 675b1a96e..689e8e879 100644
--- a/packages/kit/scripts/special-types/$env+dynamic+private.md
+++ b/packages/kit/scripts/special-types/$env+dynamic+private.md
@@ -1,4 +1,4 @@
-This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix).
+This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
 
 This module cannot be imported into client-side code.
 
diff --git a/packages/kit/scripts/special-types/$env+dynamic+public.md b/packages/kit/scripts/special-types/$env+dynamic+public.md
index 2c2ccdce9..b70626ba6 100644
--- a/packages/kit/scripts/special-types/$env+dynamic+public.md
+++ b/packages/kit/scripts/special-types/$env+dynamic+public.md
@@ -1,4 +1,4 @@
-Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
+Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
 
 Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
 
diff --git a/packages/kit/scripts/special-types/$env+static+private.md b/packages/kit/scripts/special-types/$env+static+private.md
index cb490f888..536ce64de 100644
--- a/packages/kit/scripts/special-types/$env+static+private.md
+++ b/packages/kit/scripts/special-types/$env+static+private.md
@@ -1,4 +1,4 @@
-Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix).
+Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
 
 _Unlike_ [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
 
diff --git a/packages/kit/scripts/special-types/$env+static+public.md b/packages/kit/scripts/special-types/$env+static+public.md
index 60fc224fa..2b55250f0 100644
--- a/packages/kit/scripts/special-types/$env+static+public.md
+++ b/packages/kit/scripts/special-types/$env+static+public.md
@@ -1,4 +1,4 @@
-Similar to [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
+Similar to [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
 
 Values are replaced statically at build time.
 
diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js
index 8bfd4eaf3..3c28acb48 100644
--- a/packages/kit/src/exports/vite/dev/index.js
+++ b/packages/kit/src/exports/vite/dev/index.js
@@ -11,7 +11,7 @@ import { load_error_page, load_template } from '../../../core/config/index.js';
 import { SVELTE_KIT_ASSETS } from '../../../constants.js';
 import * as sync from '../../../core/sync/sync.js';
 import { get_mime_lookup, runtime_base, runtime_prefix } from '../../../core/utils.js';
-import { prevent_illegal_vite_imports } from '../utils.js';
+import { prevent_illegal_vite_imports } from '../graph_analysis/index.js';
 import { compact } from '../../../utils/array.js';
 import { normalizePath } from 'vite';
 
diff --git a/packages/kit/src/exports/vite/graph_analysis/index.js b/packages/kit/src/exports/vite/graph_analysis/index.js
new file mode 100644
index 000000000..7a380125e
--- /dev/null
+++ b/packages/kit/src/exports/vite/graph_analysis/index.js
@@ -0,0 +1,277 @@
+import path from 'path';
+import { normalizePath } from 'vite';
+import { remove_query_from_id, get_module_types } from './utils.js';
+
+/** @typedef {import('./types').ImportGraph} ImportGraph */
+
+const CWD_ID = normalizePath(process.cwd());
+const NODE_MODULES_ID = normalizePath(path.resolve(process.cwd(), 'node_modules'));
+const ILLEGAL_IMPORTS = new Set([
+	'/@id/__x00__$env/dynamic/private', //dev
+	'\0$env/dynamic/private', // prod
+	'/@id/__x00__$env/static/private', // dev
+	'\0$env/static/private' // prod
+]);
+const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/;
+
+export class IllegalModuleGuard {
+	/** @type {string} */
+	#lib_dir;
+
+	/** @type {string} */
+	#server_dir;
+
+	/** @type {Array<ImportGraph>} */
+	#chain = [];
+
+	/**
+	 * @param {string} lib_dir
+	 */
+	constructor(lib_dir) {
+		this.#lib_dir = normalizePath(lib_dir);
+		this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
+	}
+
+	/**
+	 * Assert that a node imports no illegal modules.
+	 * @param {ImportGraph} node
+	 * @returns {void}
+	 */
+	assert_legal(node) {
+		this.#chain.push(node);
+		for (const child of node.children) {
+			if (this.#is_illegal(child.id)) {
+				this.#chain.push(child);
+				const error = this.#format_illegal_import_chain(this.#chain);
+				this.#chain = []; // Reset the chain in case we want to reuse this guard
+				throw new Error(error);
+			}
+			this.assert_legal(child);
+		}
+		this.#chain.pop();
+	}
+
+	/**
+	 * `true` if the provided ID represents a server-only module, else `false`.
+	 * @param {string} module_id
+	 * @returns {boolean}
+	 */
+	#is_illegal(module_id) {
+		if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
+		return false;
+	}
+
+	/**
+	 * `true` if the provided ID represents a Kit-defined server-only module, else `false`.
+	 * @param {string} module_id
+	 * @returns {boolean}
+	 */
+	#is_kit_illegal(module_id) {
+		return ILLEGAL_IMPORTS.has(module_id);
+	}
+
+	/**
+	 * `true` if the provided ID represents a user-defined server-only module, else `false`.
+	 * @param {string} module_id
+	 * @returns {boolean}
+	 */
+	#is_user_illegal(module_id) {
+		if (module_id.startsWith(this.#server_dir)) return true;
+
+		// files outside the project root are ignored
+		if (!module_id.startsWith(CWD_ID)) return false;
+
+		// so are files inside node_modules
+		if (module_id.startsWith(NODE_MODULES_ID)) return false;
+
+		return ILLEGAL_MODULE_NAME_PATTERN.test(path.basename(module_id));
+	}
+
+	/**
+	 * @param {string} str
+	 * @param {number} times
+	 */
+	#repeat(str, times) {
+		return new Array(times + 1).join(str);
+	}
+
+	/**
+	 * Create a formatted error for an illegal import.
+	 * @param {Array<ImportGraph>} stack
+	 */
+	#format_illegal_import_chain(stack) {
+		const dev_virtual_prefix = '/@id/__x00__';
+		const prod_virtual_prefix = '\0';
+
+		stack = stack.map((graph) => {
+			if (graph.id.startsWith(dev_virtual_prefix)) {
+				return { ...graph, id: graph.id.replace(dev_virtual_prefix, '') };
+			}
+			if (graph.id.startsWith(prod_virtual_prefix)) {
+				return { ...graph, id: graph.id.replace(prod_virtual_prefix, '') };
+			}
+			if (graph.id.startsWith(this.#lib_dir)) {
+				return { ...graph, id: graph.id.replace(this.#lib_dir, '$lib') };
+			}
+
+			return { ...graph, id: path.relative(process.cwd(), graph.id) };
+		});
+
+		const pyramid = stack
+			.map(
+				(file, i) =>
+					`${this.#repeat(' ', i * 2)}- ${file.id} ${
+						file.dynamic ? '(imported by parent dynamically)' : ''
+					}`
+			)
+			.join('\n');
+
+		return `Cannot import ${stack.at(-1)?.id} into client-side code:\n${pyramid}`;
+	}
+}
+
+/** @implements {ImportGraph} */
+export class RollupImportGraph {
+	/** @type {(id: string) => import('rollup').ModuleInfo | null} */
+	#node_getter;
+
+	/** @type {import('rollup').ModuleInfo} */
+	#module_info;
+
+	/** @type {string} */
+	id;
+
+	/** @type {boolean} */
+	dynamic;
+
+	/** @type {Set<string>} */
+	#seen;
+
+	/**
+	 * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
+	 * @param {import('rollup').ModuleInfo} node
+	 */
+	constructor(node_getter, node) {
+		this.#node_getter = node_getter;
+		this.#module_info = node;
+		this.id = remove_query_from_id(normalizePath(node.id));
+		this.dynamic = false;
+		this.#seen = new Set();
+	}
+
+	/**
+	 * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
+	 * @param {import('rollup').ModuleInfo} node
+	 * @param {boolean} dynamic
+	 * @param {Set<string>} seen;
+	 * @returns {RollupImportGraph}
+	 */
+	static #new_internal(node_getter, node, dynamic, seen) {
+		const instance = new RollupImportGraph(node_getter, node);
+		instance.dynamic = dynamic;
+		instance.#seen = seen;
+		return instance;
+	}
+
+	get children() {
+		return this.#children();
+	}
+
+	*#children() {
+		if (this.#seen.has(this.id)) return;
+		this.#seen.add(this.id);
+		for (const id of this.#module_info.importedIds) {
+			const child = this.#node_getter(id);
+			if (child === null) return;
+			yield RollupImportGraph.#new_internal(this.#node_getter, child, false, this.#seen);
+		}
+		for (const id of this.#module_info.dynamicallyImportedIds) {
+			const child = this.#node_getter(id);
+			if (child === null) return;
+			yield RollupImportGraph.#new_internal(this.#node_getter, child, true, this.#seen);
+		}
+	}
+}
+
+/** @implements {ImportGraph} */
+export class ViteImportGraph {
+	/** @type {Set<string>} */
+	#module_types;
+
+	/** @type {import('vite').ModuleNode} */
+	#module_info;
+
+	/** @type {string} */
+	id;
+
+	/** @type {Set<string>} */
+	#seen;
+
+	/**
+	 * @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
+	 * @param {import('vite').ModuleNode} node
+	 */
+	constructor(module_types, node) {
+		this.#module_types = module_types;
+		this.#module_info = node;
+		this.id = remove_query_from_id(normalizePath(node.id ?? ''));
+		this.#seen = new Set();
+	}
+
+	/**
+	 * @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
+	 * @param {import('vite').ModuleNode} node
+	 * @param {Set<string>} seen
+	 * @returns {ViteImportGraph}
+	 */
+	static #new_internal(module_types, node, seen) {
+		const instance = new ViteImportGraph(module_types, node);
+		instance.#seen = seen;
+		return instance;
+	}
+
+	get dynamic() {
+		return false;
+	}
+
+	get children() {
+		return this.#children();
+	}
+
+	*#children() {
+		if (this.#seen.has(this.id)) return;
+		this.#seen.add(this.id);
+		for (const child of this.#module_info.importedModules) {
+			if (!this.#module_types.has(path.extname(this.id))) {
+				continue;
+			}
+			yield ViteImportGraph.#new_internal(this.#module_types, child, this.#seen);
+		}
+	}
+}
+
+/**
+ * Throw an error if a private module is imported from a client-side node.
+ * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
+ * @param {import('rollup').ModuleInfo} node
+ * @param {string} lib_dir
+ * @returns {void}
+ */
+export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
+	const graph = new RollupImportGraph(node_getter, node);
+	const guard = new IllegalModuleGuard(lib_dir);
+	guard.assert_legal(graph);
+}
+
+/**
+ * Throw an error if a private module is imported from a client-side node.
+ * @param {import('vite').ModuleNode} node
+ * @param {string} lib_dir
+ * @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
+ * @returns {void}
+ */
+export function prevent_illegal_vite_imports(node, lib_dir, module_types) {
+	const graph = new ViteImportGraph(get_module_types(module_types), node);
+	const guard = new IllegalModuleGuard(lib_dir);
+	guard.assert_legal(graph);
+}
diff --git a/packages/kit/src/exports/vite/graph_analysis/index.spec.js b/packages/kit/src/exports/vite/graph_analysis/index.spec.js
new file mode 100644
index 000000000..3e2b98c1f
--- /dev/null
+++ b/packages/kit/src/exports/vite/graph_analysis/index.spec.js
@@ -0,0 +1,191 @@
+import { describe } from '../../../utils/unit_test.js';
+import * as assert from 'uvu/assert';
+import { IllegalModuleGuard } from './index.js';
+import path from 'path';
+import { normalizePath } from 'vite';
+
+const CWD = process.cwd();
+const FAKE_LIB_DIR = normalizePath(path.join(CWD, 'lib'));
+const DEV_VIRTUAL_DYNAMIC_ID = '/@id/__x00__$env/dynamic/private';
+const PROD_VIRTUAL_DYNAMIC_ID = '\0$env/dynamic/private';
+const DEV_VIRTUAL_STATIC_ID = '/@id/__x00__$env/static/private';
+const PROD_VIRTUAL_STATIC_ID = '\0$env/static/private';
+const USER_SERVER_ID = normalizePath(path.join(FAKE_LIB_DIR, 'test.server.js'));
+const USER_SERVER_ID_NODE_MODULES = normalizePath(path.join(CWD, 'node_modules', 'test.server.js'));
+const USER_SERVER_ID_OUTSIDE_ROOT = normalizePath(path.join(CWD, '..', 'test.server.js'));
+const USER_SERVER_FOLDER_ID = normalizePath(path.join(FAKE_LIB_DIR, '/server/some/nested/path.js'));
+
+/**
+ * @template {any} T
+ * @param {Array<T>} arr
+ * @returns {Generator<T>}
+ */
+function* generator_from_array(arr) {
+	for (const item of arr) {
+		yield item;
+	}
+}
+
+/**
+ * @param {Array<import('./types').ImportGraph>} nodes_to_insert
+ * @returns {import('./types').ImportGraph}
+ */
+function get_module_graph(...nodes_to_insert) {
+	return {
+		id: 'test.svelte',
+		dynamic: false,
+		children: generator_from_array([
+			{
+				id: 'fine.js',
+				dynamic: false,
+				children: generator_from_array([
+					{
+						id: 'also_fine.js',
+						dynamic: false,
+						children: generator_from_array([
+							{
+								id: 'erstwhile.css',
+								dynamic: false,
+								children: generator_from_array([])
+							},
+							{
+								id: 'gruntled.js',
+								dynamic: false,
+								children: generator_from_array([])
+							}
+						])
+					},
+					{
+						id: 'somewhat_neat.js',
+						dynamic: false,
+						children: generator_from_array([])
+					},
+					{
+						id: 'blah.ts',
+						dynamic: false,
+						children: generator_from_array([])
+					}
+				])
+			},
+			{
+				id: 'something.svelte',
+				dynamic: false,
+				children: generator_from_array(nodes_to_insert)
+			},
+			{
+				id: 'im_not_creative.hamburger',
+				dynamic: false,
+				children: generator_from_array([])
+			}
+		])
+	};
+}
+
+describe('IllegalImportGuard', (test) => {
+	const guard = new IllegalModuleGuard(FAKE_LIB_DIR);
+
+	test('assert succeeds for a graph with no illegal imports', () => {
+		assert.not.throws(() => guard.assert_legal(get_module_graph()));
+	});
+
+	test('assert throws an error when importing $env/static/private in dev', () => {
+		const module_graph = get_module_graph({
+			id: DEV_VIRTUAL_STATIC_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$env\/static\/private into client-side code:.*/gs
+		);
+	});
+
+	test('assert throws an error when importing $env/static/private in prod', () => {
+		const module_graph = get_module_graph({
+			id: PROD_VIRTUAL_STATIC_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$env\/static\/private into client-side code:.*/gs
+		);
+	});
+
+	test('assert throws an error when importing $env/dynamic/private in dev', () => {
+		const module_graph = get_module_graph({
+			id: DEV_VIRTUAL_DYNAMIC_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$env\/dynamic\/private into client-side code:.*/gs
+		);
+	});
+
+	test('assert throws an error when importing $env/dynamic/private in prod', () => {
+		const module_graph = get_module_graph({
+			id: PROD_VIRTUAL_DYNAMIC_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$env\/dynamic\/private into client-side code:.*/gs
+		);
+	});
+
+	test('assert throws an error when importing a single server-only module', () => {
+		const module_graph = get_module_graph({
+			id: USER_SERVER_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$lib\/test.server.js into client-side code:.*/gs
+		);
+	});
+
+	test('assert throws an error when importing a module in the server-only folder', () => {
+		const module_graph = get_module_graph({
+			id: USER_SERVER_FOLDER_ID,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+
+		assert.throws(
+			() => guard.assert_legal(module_graph),
+			/.*Cannot import \$lib\/server\/some\/nested\/path.js into client-side code:.*/gs
+		);
+	});
+
+	test('assert ignores illegal server-only modules in node_modules', () => {
+		const module_graph = get_module_graph({
+			id: USER_SERVER_ID_NODE_MODULES,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+
+		assert.not.throws(() => guard.assert_legal(module_graph));
+	});
+
+	test('assert ignores illegal server-only modules outside the project root', () => {
+		const module_graph = get_module_graph({
+			id: USER_SERVER_ID_OUTSIDE_ROOT,
+			dynamic: false,
+			children: generator_from_array([])
+		});
+
+		assert.not.throws(() => guard.assert_legal(module_graph));
+	});
+});
+
+/*
+We don't have a great way to mock Vite and Rollup's implementations of module graphs, so unit testing
+ViteImportGraph and RollupImportGraph is kind of an exercise in "code coverage hubris" -- they're covered by
+the integration tests, where Vite and Rollup can provide a useful graph implementation. If, in the future, we can find
+a reason to unit test them, we can add those below.
+*/
diff --git a/packages/kit/src/exports/vite/graph_analysis/types.d.ts b/packages/kit/src/exports/vite/graph_analysis/types.d.ts
new file mode 100644
index 000000000..1239fec43
--- /dev/null
+++ b/packages/kit/src/exports/vite/graph_analysis/types.d.ts
@@ -0,0 +1,5 @@
+export interface ImportGraph {
+	readonly id: string;
+	readonly dynamic: boolean;
+	readonly children: Generator<ImportGraph>;
+}
diff --git a/packages/kit/src/exports/vite/graph_analysis/utils.js b/packages/kit/src/exports/vite/graph_analysis/utils.js
new file mode 100644
index 000000000..f2caa3e04
--- /dev/null
+++ b/packages/kit/src/exports/vite/graph_analysis/utils.js
@@ -0,0 +1,30 @@
+const query_pattern = /\?.*$/s;
+
+/** @param {string} path */
+export function remove_query_from_id(path) {
+	return path.replace(query_pattern, '');
+}
+
+/**
+ * Vite does some weird things with import trees in dev
+ * for example, a Tailwind app.css will appear to import
+ * every file in the project. This isn't a problem for
+ * Rollup during build.
+ * @param {Iterable<string>} config_module_types
+ */
+export const get_module_types = (config_module_types) => {
+	return new Set([
+		'',
+		'.ts',
+		'.js',
+		'.svelte',
+		'.mts',
+		'.mjs',
+		'.cts',
+		'.cjs',
+		'.svelte.md',
+		'.svx',
+		'.md',
+		...config_module_types
+	]);
+};
diff --git a/packages/kit/src/exports/vite/graph_analysis/utils.spec.js b/packages/kit/src/exports/vite/graph_analysis/utils.spec.js
new file mode 100644
index 000000000..7aff1b999
--- /dev/null
+++ b/packages/kit/src/exports/vite/graph_analysis/utils.spec.js
@@ -0,0 +1,58 @@
+import { describe } from '../../../utils/unit_test.js';
+import * as assert from 'uvu/assert';
+import { remove_query_from_id, get_module_types } from './utils.js';
+
+describe('remove_query_string_from_path', (test) => {
+	const module_ids = [
+		'$env/static/private',
+		'some-normal-js-module.js',
+		'c:\\\\some\\stupid\\windows\\path.js',
+		'/some/normal/linux/path.js'
+	];
+	const query_module_ids = module_ids.map((module_id) => `${module_id}?hello=world,something=else`);
+
+	test('does nothing to valid IDs', () => {
+		module_ids.forEach((id) => {
+			const query_stringless = remove_query_from_id(id);
+			assert.equal(query_stringless, id);
+		});
+	});
+
+	test('removes querystring from paths with querystrings at the end', () => {
+		query_module_ids.forEach((id, i) => {
+			const query_stringless = remove_query_from_id(id);
+			assert.equal(query_stringless, module_ids[i]);
+		});
+	});
+});
+
+describe('get_module_types', (test) => {
+	const base_expected_extensions = [
+		'',
+		'.ts',
+		'.js',
+		'.svelte',
+		'.mts',
+		'.mjs',
+		'.cts',
+		'.cjs',
+		'.svelte.md',
+		'.svx',
+		'.md'
+	];
+
+	test('returns correct base extensions', () => {
+		const module_types = get_module_types([]);
+		base_expected_extensions.forEach((extension) => {
+			assert.equal(module_types.has(extension), true);
+		});
+	});
+
+	test('correctly extends base extensions', () => {
+		const additional_extensions = ['.foo', '.bar', '.baz'];
+		const module_types = get_module_types(additional_extensions);
+		base_expected_extensions.concat(additional_extensions).forEach((extension) => {
+			assert.equal(module_types.has(extension), true);
+		});
+	});
+});
diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js
index b7eda46b4..c6b99a815 100644
--- a/packages/kit/src/exports/vite/index.js
+++ b/packages/kit/src/exports/vite/index.js
@@ -14,7 +14,8 @@ import { generate_manifest } from '../../core/generate_manifest/index.js';
 import { runtime_directory, logger } from '../../core/utils.js';
 import { find_deps, get_default_build_config } from './build/utils.js';
 import { preview } from './preview/index.js';
-import { get_aliases, prevent_illegal_rollup_imports, get_env } from './utils.js';
+import { get_aliases, get_env } from './utils.js';
+import { prevent_illegal_rollup_imports } from './graph_analysis/index.js';
 import { fileURLToPath } from 'node:url';
 import { create_static_module, create_dynamic_module } from '../../core/env.js';
 
diff --git a/packages/kit/src/exports/vite/utils.js b/packages/kit/src/exports/vite/utils.js
index fc4ff2159..cfbafa7b6 100644
--- a/packages/kit/src/exports/vite/utils.js
+++ b/packages/kit/src/exports/vite/utils.js
@@ -1,232 +1,8 @@
 import path from 'path';
-import { loadConfigFromFile, loadEnv, normalizePath } from 'vite';
+import { loadConfigFromFile, loadEnv } from 'vite';
 import { runtime_directory } from '../../core/utils.js';
 import { posixify } from '../../utils/filesystem.js';
 
-class IllegalModuleGuard {
-	/** @type {string} */
-	#lib_dir;
-
-	/** @type {string} */
-	#server_dir;
-
-	/** @type {string} */
-	#node_modules_dir = normalizePath(path.resolve(process.cwd(), 'node_modules'));
-
-	/** @type {string} */
-	#cwd = normalizePath(process.cwd());
-
-	/** @type {Set<string>} */
-	#illegal_imports = new Set([
-		'/@id/__x00__$env/dynamic/private', //dev
-		'\0$env/dynamic/private', // prod
-		'/@id/__x00__$env/static/private', // dev
-		'\0$env/static/private' // prod
-	]);
-
-	/** @type {Array<import('types').ImportNode>} */
-	#chain = [];
-
-	/**
-	 * @param {string} lib_dir
-	 */
-	constructor(lib_dir) {
-		this.#lib_dir = normalizePath(lib_dir);
-		this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
-	}
-
-	/**
-	 * @param {import('types').ImportNode} node
-	 * @returns {void}
-	 */
-	assert_legal(node) {
-		this.#chain.push(node);
-		for (const child of node.children) {
-			if (this.#is_illegal(child.name)) {
-				this.#chain.push(child);
-				throw new Error(this.#format_illegal_import_chain(this.#chain));
-			}
-			this.assert_legal(child);
-		}
-		this.#chain.pop();
-	}
-
-	/**
-	 * `true` if the provided ID represents a server-only module, else `false`.
-	 * @param {string} module_id
-	 * @returns {boolean}
-	 */
-	#is_illegal(module_id) {
-		if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
-		return false;
-	}
-
-	/**
-	 * `true` if the provided ID represents a Kit-defined server-only module, else `false`.
-	 * @param {string} module_id
-	 * @returns {boolean}
-	 */
-	#is_kit_illegal(module_id) {
-		return this.#illegal_imports.has(module_id);
-	}
-
-	/**
-	 * `true` if the provided ID represents a user-defined server-only module, else `false`.
-	 * @param {string} module_id
-	 * @returns {boolean}
-	 */
-	#is_user_illegal(module_id) {
-		if (module_id.startsWith(this.#server_dir)) return true;
-
-		// files outside the project root are ignored
-		if (!module_id.startsWith(this.#cwd)) return false;
-
-		// so are files inside node_modules
-		if (module_id.startsWith(this.#node_modules_dir)) return false;
-
-		return /.*\.server\..+/.test(path.basename(module_id));
-	}
-
-	/**
-	 * @param {string} str
-	 * @param {number} times
-	 */
-	#repeat(str, times) {
-		return new Array(times + 1).join(str);
-	}
-
-	/**
-	 * Create a formatted error for an illegal import.
-	 * @param {Array<{name: string, dynamic: boolean}>} stack
-	 */
-	#format_illegal_import_chain(stack) {
-		const dev_virtual_prefix = '/@id/__x00__';
-		const prod_virtual_prefix = '\0';
-
-		stack = stack.map((file) => {
-			if (file.name.startsWith(dev_virtual_prefix)) {
-				return { ...file, name: file.name.replace(dev_virtual_prefix, '') };
-			}
-			if (file.name.startsWith(prod_virtual_prefix)) {
-				return { ...file, name: file.name.replace(prod_virtual_prefix, '') };
-			}
-			if (file.name.startsWith(this.#lib_dir)) {
-				return { ...file, name: file.name.replace(this.#lib_dir, '$lib') };
-			}
-
-			return { ...file, name: path.relative(process.cwd(), file.name) };
-		});
-
-		const pyramid = stack
-			.map(
-				(file, i) =>
-					`${this.#repeat(' ', i * 2)}- ${file.name} ${
-						file.dynamic ? '(imported by parent dynamically)' : ''
-					}`
-			)
-			.join('\n');
-
-		return `Cannot import ${stack.at(-1)?.name} into client-side code:\n${pyramid}`;
-	}
-}
-
-class RollupImportGraph {
-	/** @type {(id: string) => import('rollup').ModuleInfo | null} */
-	#node_getter;
-
-	/** @type {import('rollup').ModuleInfo} */
-	#module_info;
-
-	/** @type {string} */
-	name;
-
-	/** @type {boolean} */
-	dynamic;
-
-	/** @type {Set<string>} */
-	#seen;
-
-	/**
-	 * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
-	 * @param {import('rollup').ModuleInfo} node
-	 * @param {boolean} dynamic
-	 * @param {Set<string>} seen
-	 */
-	constructor(node_getter, node, dynamic = false, seen = new Set()) {
-		this.#node_getter = node_getter;
-		this.#module_info = node;
-		this.name = remove_query_from_path(normalizePath(node.id));
-		this.dynamic = dynamic;
-		this.#seen = seen;
-		void (/** @type {import('types').ImportNode} */ (this));
-	}
-
-	get children() {
-		return this.#children();
-	}
-
-	*#children() {
-		if (this.#seen.has(this.name)) return;
-		this.#seen.add(this.name);
-		for (const id of this.#module_info.importedIds) {
-			const child = this.#node_getter(id);
-			if (child === null) return;
-			yield new RollupImportGraph(this.#node_getter, child, false, this.#seen);
-		}
-		for (const id of this.#module_info.dynamicallyImportedIds) {
-			const child = this.#node_getter(id);
-			if (child === null) return;
-			yield new RollupImportGraph(this.#node_getter, child, true, this.#seen);
-		}
-	}
-}
-
-class ViteImportGraph {
-	/** @type {Set<string>} */
-	#module_types;
-
-	/** @type {import('vite').ModuleNode} */
-	#module_info;
-
-	/** @type {string} */
-	name;
-
-	/** @type {Set<string>} */
-	#seen;
-
-	/**
-	 * @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
-	 * @param {import('vite').ModuleNode} node
-	 * @param {Set<string>} seen
-	 */
-	constructor(module_types, node, seen = new Set()) {
-		this.#module_types = module_types;
-		this.#module_info = node;
-		this.name = remove_query_from_path(normalizePath(node.id ?? ''));
-		this.#seen = seen;
-		void (/** @type {import('types').ImportNode} */ (this));
-	}
-
-	get dynamic() {
-		return false;
-	}
-
-	get children() {
-		return this.#children();
-	}
-
-	*#children() {
-		if (this.#seen.has(this.name)) return;
-		this.#seen.add(this.name);
-		for (const child of this.#module_info.importedModules) {
-			if (!this.#module_types.has(path.extname(this.name))) {
-				continue;
-			}
-			yield new ViteImportGraph(this.#module_types, child, this.#seen);
-		}
-	}
-}
-
 /**
  * @param {import('vite').ResolvedConfig} config
  * @param {import('vite').ConfigEnv} config_env
@@ -379,60 +155,3 @@ export function get_env(env_config, mode) {
 		private: Object.fromEntries(entries.filter(([k]) => !k.startsWith(env_config.publicPrefix)))
 	};
 }
-
-const query_pattern = /\?.*$/s;
-
-/** @param {string} path */
-function remove_query_from_path(path) {
-	return path.replace(query_pattern, '');
-}
-
-/**
- * Vite does some weird things with import trees in dev
- * for example, a Tailwind app.css will appear to import
- * every file in the project. This isn't a problem for
- * Rollup during build.
- * @param {Iterable<string>} config_module_types
- */
-const get_module_types = (config_module_types) => {
-	return new Set([
-		'',
-		'.ts',
-		'.js',
-		'.svelte',
-		'.mts',
-		'.mjs',
-		'.cts',
-		'.cjs',
-		'.svelte.md',
-		'.svx',
-		'.md',
-		...config_module_types
-	]);
-};
-
-/**
- * Throw an error if a private module is imported from a client-side node.
- * @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
- * @param {import('rollup').ModuleInfo} node
- * @param {string} lib_dir
- * @returns {void}
- */
-export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
-	const graph = new RollupImportGraph(node_getter, node);
-	const guard = new IllegalModuleGuard(lib_dir);
-	guard.assert_legal(graph);
-}
-
-/**
- * Throw an error if a private module is imported from a client-side node.
- * @param {import('vite').ModuleNode} node
- * @param {string} lib_dir
- * @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
- * @returns {void}
- */
-export function prevent_illegal_vite_imports(node, lib_dir, module_types) {
-	const graph = new ViteImportGraph(get_module_types(module_types), node);
-	const guard = new IllegalModuleGuard(lib_dir);
-	guard.assert_legal(graph);
-}
diff --git a/packages/kit/src/exports/vite/utils.spec.js b/packages/kit/src/exports/vite/utils.spec.js
index 558d5d563..f2160386d 100644
--- a/packages/kit/src/exports/vite/utils.spec.js
+++ b/packages/kit/src/exports/vite/utils.spec.js
@@ -3,15 +3,7 @@ import { test } from 'uvu';
 import * as assert from 'uvu/assert';
 import { validate_config } from '../../core/config/index.js';
 import { posixify } from '../../utils/filesystem.js';
-import {
-	deep_merge,
-	get_aliases,
-	merge_vite_configs,
-	prevent_illegal_rollup_imports,
-	prevent_illegal_vite_imports
-} from './utils.js';
-
-const illegal_id = '/@id/__x00__$env/dynamic/private';
+import { deep_merge, get_aliases, merge_vite_configs } from './utils.js';
 
 test('basic test no conflicts', async () => {
 	const merged = deep_merge(
@@ -240,164 +232,4 @@ test('transform kit.alias to resolve.alias', () => {
 	]);
 });
 
-/** @typedef {{id: string, importedIds: Array<string>, dynamicallyImportedIds: Array<string> }} RollupNode */
-
-/** @type {(id: string) => RollupNode | null} */
-const rollup_node_getter = (id) => {
-	/** @type {{[key: string]: RollupNode}} */
-	const nodes = {
-		'/test/path1.js': {
-			id: '/test/path1.js',
-			importedIds: ['/test/path2.js', '/test/path3.js'],
-			dynamicallyImportedIds: ['/test/path4.js', '/test/path5.js']
-		},
-		'/test/path2.js': {
-			id: '/test/path2.js',
-			importedIds: ['/test/path3.js'],
-			dynamicallyImportedIds: ['/test/path5.js']
-		},
-		'/test/path3.js': {
-			id: '/test/path3.js',
-			importedIds: ['/test/path5.js'],
-			dynamicallyImportedIds: ['/test/path1.js']
-		},
-		'/test/path4.js': {
-			id: '/test/path4.js',
-			importedIds: ['/test/path5.js'],
-			dynamicallyImportedIds: ['/test/path3.js']
-		},
-		'/test/path5.js': {
-			id: '/test/path5.js',
-			importedIds: ['/test/path1.js'],
-			dynamicallyImportedIds: ['/test/path3.js']
-		},
-		'/bad/static.js': {
-			id: '/bad/static.js',
-			importedIds: ['/statically-imports/bad/module.js'],
-			dynamicallyImportedIds: ['/test/path1.js']
-		},
-		'/statically-imports/bad/module.js': {
-			id: '/statically-imports/bad/module.js',
-			importedIds: [illegal_id],
-			dynamicallyImportedIds: ['/test/path2.js']
-		},
-		'/bad/dynamic.js': {
-			id: '/bad/dynamic.js',
-			importedIds: ['/dynamically-imports/bad/module.js'],
-			dynamicallyImportedIds: ['/test/path1.js']
-		},
-		'/dynamically-imports/bad/module.js': {
-			id: '/dynamically-imports/bad/module.js',
-			importedIds: ['/test/path5.js'],
-			dynamicallyImportedIds: ['/test/path2.js', illegal_id]
-		},
-		[illegal_id]: {
-			id: illegal_id,
-			importedIds: [],
-			dynamicallyImportedIds: []
-		}
-	};
-	return nodes[id] ?? null;
-};
-
-const ok_rollup_node = rollup_node_getter('/test/path1.js');
-const bad_rollup_node_static = rollup_node_getter('/bad/static.js');
-const bad_rollup_node_dynamic = rollup_node_getter('/bad/dynamic.js');
-
-test('allows ok rollup imports', () => {
-	assert.not.throws(() => {
-		prevent_illegal_rollup_imports(
-			// @ts-expect-error
-			rollup_node_getter,
-			ok_rollup_node,
-			'should_not_match_anything'
-		);
-	});
-});
-
-test('does not allow bad static rollup imports', () => {
-	assert.throws(() => {
-		prevent_illegal_rollup_imports(
-			// @ts-expect-error
-			rollup_node_getter,
-			bad_rollup_node_static,
-			'should_not_match_anything'
-		);
-	});
-});
-
-test('does not allow bad dynamic rollup imports', () => {
-	assert.throws(() => {
-		prevent_illegal_rollup_imports(
-			// @ts-expect-error
-			rollup_node_getter,
-			bad_rollup_node_dynamic,
-			'should_not_match_anything'
-		);
-	});
-});
-
-/** @typedef {{id: string, importedModules: Set<ViteNode>}} ViteNode */
-
-/** @type {ViteNode} */
-const ok_vite_node = {
-	id: '/test/ok.js',
-	importedModules: new Set([
-		{
-			id: '/test/path1.js',
-			importedModules: new Set([
-				{
-					id: '/test/path2.js',
-					importedModules: new Set()
-				}
-			])
-		},
-		{ id: '/test/path3.js', importedModules: new Set() }
-	])
-};
-
-/** @type {ViteNode} */
-const bad_vite_node = {
-	id: '/test/bad-static.js',
-	importedModules: new Set([
-		{
-			id: '/test/path1.js',
-			importedModules: new Set([
-				{
-					id: '/test/path2.js',
-					importedModules: new Set([
-						{
-							id: illegal_id,
-							importedModules: new Set()
-						}
-					])
-				}
-			])
-		},
-		{ id: '/test/path3.js', importedModules: new Set() }
-	])
-};
-
-test('allows ok vite imports', () => {
-	assert.not.throws(() => {
-		prevent_illegal_vite_imports(
-			// @ts-expect-error
-			ok_vite_node,
-			'should_not_match_anything',
-			[]
-		);
-	});
-});
-
-test('does not allow bad static rollup imports', () => {
-	assert.throws(() => {
-		prevent_illegal_vite_imports(
-			// @ts-expect-error
-			bad_vite_node,
-			'should_not_match_anything',
-			[]
-		);
-	});
-});
-
 test.run();
diff --git a/packages/kit/src/utils/url.spec.js b/packages/kit/src/utils/url.spec.js
index 3d9603055..4c359b224 100644
--- a/packages/kit/src/utils/url.spec.js
+++ b/packages/kit/src/utils/url.spec.js
@@ -1,18 +1,7 @@
-import { suite } from 'uvu';
 import * as assert from 'uvu/assert';
+import { describe } from './unit_test.js';
 import { resolve, normalize_path, make_trackable, disable_search } 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');
diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts
index 6b3d40651..fedab7854 100644
--- a/packages/kit/types/index.d.ts
+++ b/packages/kit/types/index.d.ts
@@ -16,7 +16,7 @@ import {
 	TrailingSlash
 } from './private.js';
 import { SSRNodeLoader, SSRRoute, ValidatedConfig } from './internal.js';
-import { HttpError, Redirect, ValidationError } from '../src/runtime/control.js';
+import { HttpError, Redirect } from '../src/runtime/control.js';
 
 export { PrerenderOption } from './private.js';
 
@@ -39,6 +39,12 @@ export type AwaitedActions<T extends Record<string, (...args: any) => any>> = {
 	[Key in keyof T]: UnpackValidationError<Awaited<ReturnType<T[Key]>>>;
 }[keyof T];
 
+// Needs to be here, else ActionData will be resolved to unknown - probably because of "d.ts file imports .js file" in combination with allowJs
+interface ValidationError<T extends Record<string, unknown> | undefined = undefined> {
+	status: number;
+	data: T;
+}
+
 type UnpackValidationError<T> = T extends ValidationError<infer X> ? X : T;
 
 export interface Builder {
@@ -292,7 +298,7 @@ export interface RequestEvent<
 /**
  * A `(event: RequestEvent) => Response` function exported from a `+server.js` file that corresponds to an HTTP verb (`GET`, `PUT`, `PATCH`, etc) and handles requests with that method.
  *
- * It receives `Params` as the first generic argument, which you can skip by using [generated types](/docs/types#generated-types) instead.
+ * It receives `Params` as the first generic argument, which you can skip by using [generated types](https://kit.svelte.dev/docs/types#generated-types) instead.
  */
 export interface RequestHandler<
 	Params extends Partial<Record<string, string>> = Partial<Record<string, string>>
diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts
index 0e72dda4b..aebf0be71 100644
--- a/packages/kit/types/internal.d.ts
+++ b/packages/kit/types/internal.d.ts
@@ -100,12 +100,6 @@ export interface ClientHooks {
 	handleError: HandleClientError;
 }
 
-export interface ImportNode {
-	readonly name: string;
-	readonly dynamic: boolean;
-	readonly children: Generator<ImportNode>;
-}
-
 export class InternalServer extends Server {
 	init(options: ServerInitOptions): Promise<void>;
 	respond(
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3af108aa8..ba4fc6b0e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -50,12 +50,12 @@ importers:
       '@cloudflare/workers-types': ^3.14.0
       '@types/node': ^16.11.36
       '@types/ws': ^8.5.3
-      esbuild: ^0.14.48
+      esbuild: ^0.15.6
       typescript: ^4.8.2
       worktop: 0.8.0-next.14
     dependencies:
       '@cloudflare/workers-types': 3.14.0
-      esbuild: 0.14.54
+      esbuild: 0.15.6
       worktop: 0.8.0-next.14
     devDependencies:
       '@types/node': 16.11.42
@@ -68,12 +68,12 @@ importers:
       '@cloudflare/workers-types': ^3.14.0
       '@iarna/toml': ^2.2.5
       '@types/node': ^16.11.36
-      esbuild: ^0.14.48
+      esbuild: ^0.15.6
       typescript: ^4.8.2
     dependencies:
       '@cloudflare/workers-types': 3.14.0
       '@iarna/toml': 2.2.5
-      esbuild: 0.14.54
+      esbuild: 0.15.6
     devDependencies:
       '@cloudflare/kv-asset-handler': 0.2.0
       '@types/node': 16.11.42
@@ -89,18 +89,16 @@ importers:
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       '@types/set-cookie-parser': ^2.4.2
-      esbuild: ^0.14.48
+      esbuild: ^0.15.6
       rimraf: ^3.0.2
       rollup: ^2.78.1
       set-cookie-parser: ^2.4.8
-      tiny-glob: ^0.2.9
       typescript: ^4.8.2
       uvu: ^0.5.3
     dependencies:
       '@iarna/toml': 2.2.5
-      esbuild: 0.14.54
+      esbuild: 0.15.6
       set-cookie-parser: 2.5.0
-      tiny-glob: 0.2.9
     devDependencies:
       '@netlify/functions': 1.0.0
       '@rollup/plugin-commonjs': 22.0.1_rollup@2.78.1
@@ -120,7 +118,7 @@ importers:
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       c8: ^7.11.3
-      esbuild: ^0.14.48
+      esbuild: ^0.15.6
       node-fetch: ^3.2.4
       polka: ^1.0.0-next.22
       rimraf: ^3.0.2
@@ -129,7 +127,7 @@ importers:
       typescript: ^4.8.2
       uvu: ^0.5.3
     dependencies:
-      esbuild: 0.14.54
+      esbuild: 0.15.6
     devDependencies:
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
       '@sveltejs/kit': link:../kit
@@ -190,11 +188,11 @@ importers:
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       '@vercel/nft': ^0.22.0
-      esbuild: ^0.14.48
+      esbuild: ^0.15.6
       typescript: ^4.8.2
     dependencies:
       '@vercel/nft': 0.22.0
-      esbuild: 0.14.54
+      esbuild: 0.15.6
     devDependencies:
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
@@ -248,7 +246,7 @@ importers:
       svelte: ^3.48.0
       svelte-preprocess: ^4.10.6
       typescript: ^4.8.2
-      vite: 3.1.0-beta.2
+      vite: ^3.1.0
     dependencies:
       '@fontsource/fira-mono': 4.5.8
       '@lukeed/uuid': 2.0.0
@@ -259,7 +257,7 @@ importers:
       svelte: 3.48.0
       svelte-preprocess: 4.10.7_rzeu6t3zqu2xw2nsnbtx3gkaoe
       typescript: 4.8.2
-      vite: 3.1.0-beta.2
+      vite: 3.1.0
 
   packages/create-svelte/templates/skeleton:
     specifiers:
@@ -504,7 +502,7 @@ importers:
       svelte: ^3.44.0
       svelte-check: ^2.7.1
       typescript: ^4.8.2
-      vite: ^3.1.0-beta.1
+      vite: ^3.1.0
     devDependencies:
       '@sveltejs/kit': link:../../../..
       svelte: 3.48.0
@@ -518,7 +516,7 @@ importers:
       svelte: ^3.44.0
       svelte-check: ^2.7.1
       typescript: ^4.8.2
-      vite: ^3.1.0-beta.1
+      vite: ^3.1.0
     devDependencies:
       '@sveltejs/kit': link:../../../..
       svelte: 3.48.0
@@ -532,13 +530,13 @@ importers:
       svelte: ^3.44.0
       svelte-check: ^2.7.1
       typescript: ^4.8.2
-      vite: ^3.1.0-beta.1
+      vite: ^3.1.0
     devDependencies:
       '@sveltejs/kit': link:../../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.8.2
-      vite: 3.1.0-beta.2
+      vite: 3.1.0
 
   packages/kit/test/build-errors/apps/server-only-module-dynamic-import:
     specifiers:
@@ -546,13 +544,13 @@ importers:
       svelte: ^3.44.0
       svelte-check: ^2.7.1
       typescript: ^4.8.2
-      vite: ^3.1.0-beta.1
+      vite: ^3.1.0
     devDependencies:
       '@sveltejs/kit': link:../../../..
       svelte: 3.48.0
       svelte-check: 2.8.0_svelte@3.48.0
       typescript: 4.8.2
-      vite: 3.1.0-beta.2
+      vite: 3.1.0
 
   packages/kit/test/prerendering/basics:
     specifiers:
@@ -948,15 +946,6 @@ packages:
     resolution: {integrity: sha512-F6lZuzu/vNl9AxOq1U3x2UCi68bcE1O59cKGQ5ntRh3lGQfd3vers6NUag02T7P+qFCHaAp78QN6fRmq12Y3iA==}
     dev: false
 
-  /@esbuild/linux-loong64/0.14.54:
-    resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /@esbuild/linux-loong64/0.15.6:
     resolution: {integrity: sha512-hqmVU2mUjH6J2ZivHphJ/Pdse2ZD+uGCHK0uvsiLDk/JnSedEVj77CiVUnbMKuU4tih1TZZL8tG9DExQg/GZsw==}
     engines: {node: '>=12'}
@@ -1969,15 +1958,6 @@ packages:
     resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
     dev: true
 
-  /esbuild-android-64/0.14.54:
-    resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-android-64/0.15.6:
     resolution: {integrity: sha512-Z1CHSgB1crVQi2LKSBwSkpaGtaloVz0ZIYcRMsvHc3uSXcR/x5/bv9wcZspvH/25lIGTaViosciS/NS09ERmVA==}
     engines: {node: '>=12'}
@@ -1986,15 +1966,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-android-arm64/0.14.54:
-    resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-android-arm64/0.15.6:
     resolution: {integrity: sha512-mvM+gqNxqKm2pCa3dnjdRzl7gIowuc4ga7P7c3yHzs58Im8v/Lfk1ixSgQ2USgIywT48QWaACRa3F4MG7djpSw==}
     engines: {node: '>=12'}
@@ -2003,15 +1974,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-darwin-64/0.14.54:
-    resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-darwin-64/0.15.6:
     resolution: {integrity: sha512-BsfVt3usScAfGlXJiGtGamwVEOTM8AiYiw1zqDWhGv6BncLXCnTg1As+90mxWewdTZKq3iIy8s9g8CKkrrAXVw==}
     engines: {node: '>=12'}
@@ -2020,15 +1982,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-darwin-arm64/0.14.54:
-    resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-darwin-arm64/0.15.6:
     resolution: {integrity: sha512-CnrAeJaEpPakUobhqO4wVSA4Zm6TPaI5UY4EsI62j9mTrjIyQPXA1n4Ju6Iu5TVZRnEqV6q8blodgYJ6CJuwCA==}
     engines: {node: '>=12'}
@@ -2037,15 +1990,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-freebsd-64/0.14.54:
-    resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-freebsd-64/0.15.6:
     resolution: {integrity: sha512-+qFdmqi+jkAsxsNJkaWVrnxEUUI50nu6c3MBVarv3RCDCbz7ZS1a4ZrdkwEYFnKcVWu6UUE0Kkb1SQ1yGEG6sg==}
     engines: {node: '>=12'}
@@ -2054,15 +1998,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-freebsd-arm64/0.14.54:
-    resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-freebsd-arm64/0.15.6:
     resolution: {integrity: sha512-KtQkQOhnNciXm2yrTYZMD3MOm2zBiiwFSU+dkwNbcfDumzzUprr1x70ClTdGuZwieBS1BM/k0KajRQX7r504Xw==}
     engines: {node: '>=12'}
@@ -2071,15 +2006,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-32/0.14.54:
-    resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-32/0.15.6:
     resolution: {integrity: sha512-IAkDNz3TpxwISTGVdQijwyHBZrbFgLlRi5YXcvaEHtgbmayLSDcJmH5nV1MFgo/x2QdKcHBkOYHdjhKxUAcPwg==}
     engines: {node: '>=12'}
@@ -2088,15 +2014,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-64/0.14.54:
-    resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-64/0.15.6:
     resolution: {integrity: sha512-gQPksyrEYfA4LJwyfTQWAZaVZCx4wpaLrSzo2+Xc9QLC+i/sMWmX31jBjrn4nLJCd79KvwCinto36QC7BEIU/A==}
     engines: {node: '>=12'}
@@ -2105,15 +2022,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-arm/0.14.54:
-    resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-arm/0.15.6:
     resolution: {integrity: sha512-xZ0Bq2aivsthDjA/ytQZzxrxIZbG0ATJYMJxNeOIBc1zUjpbVpzBKgllOZMsTSXMHFHGrow6TnCcgwqY0+oEoQ==}
     engines: {node: '>=12'}
@@ -2122,15 +2030,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-arm64/0.14.54:
-    resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-arm64/0.15.6:
     resolution: {integrity: sha512-aovDkclFa6C9EdZVBuOXxqZx83fuoq8097xZKhEPSygwuy4Lxs8J4anHG7kojAsR+31lfUuxzOo2tHxv7EiNHA==}
     engines: {node: '>=12'}
@@ -2139,15 +2038,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-mips64le/0.14.54:
-    resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-mips64le/0.15.6:
     resolution: {integrity: sha512-wVpW8wkWOGizsCqCwOR/G3SHwhaecpGy3fic9BF1r7vq4djLjUcA8KunDaBCjJ6TgLQFhJ98RjDuyEf8AGjAvw==}
     engines: {node: '>=12'}
@@ -2156,15 +2046,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-ppc64le/0.14.54:
-    resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-ppc64le/0.15.6:
     resolution: {integrity: sha512-z6w6gsPH/Y77uchocluDC8tkCg9rfkcPTePzZKNr879bF4tu7j9t255wuNOCE396IYEGxY7y8u2HJ9i7kjCLVw==}
     engines: {node: '>=12'}
@@ -2173,15 +2054,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-riscv64/0.14.54:
-    resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-riscv64/0.15.6:
     resolution: {integrity: sha512-pfK/3MJcmbfU399TnXW5RTPS1S+ID6ra+CVj9TFZ2s0q9Ja1F5A1VirUUvViPkjiw+Kq3zveyn6U09Wg1zJXrw==}
     engines: {node: '>=12'}
@@ -2190,15 +2062,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-linux-s390x/0.14.54:
-    resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-linux-s390x/0.15.6:
     resolution: {integrity: sha512-OZeeDu32liefcwAE63FhVqM4heWTC8E3MglOC7SK0KYocDdY/6jyApw0UDkDHlcEK9mW6alX/SH9r3PDjcCo/Q==}
     engines: {node: '>=12'}
@@ -2207,15 +2070,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-netbsd-64/0.14.54:
-    resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-netbsd-64/0.15.6:
     resolution: {integrity: sha512-kaxw61wcHMyiEsSsi5ut1YYs/hvTC2QkxJwyRvC2Cnsz3lfMLEu8zAjpBKWh9aU/N0O/gsRap4wTur5GRuSvBA==}
     engines: {node: '>=12'}
@@ -2224,15 +2078,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-openbsd-64/0.14.54:
-    resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-openbsd-64/0.15.6:
     resolution: {integrity: sha512-CuoY60alzYfIZapUHqFXqXbj88bbRJu8Fp9okCSHRX2zWIcGz4BXAHXiG7dlCye5nFVrY72psesLuWdusyf2qw==}
     engines: {node: '>=12'}
@@ -2241,15 +2086,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-sunos-64/0.14.54:
-    resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-sunos-64/0.15.6:
     resolution: {integrity: sha512-1ceefLdPWcd1nW/ZLruPEYxeUEAVX0YHbG7w+BB4aYgfknaLGotI/ZvPWUZpzhC8l1EybrVlz++lm3E6ODIJOg==}
     engines: {node: '>=12'}
@@ -2258,15 +2094,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-windows-32/0.14.54:
-    resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-windows-32/0.15.6:
     resolution: {integrity: sha512-pBqdOsKqCD5LRYiwF29PJRDJZi7/Wgkz46u3d17MRFmrLFcAZDke3nbdDa1c8YgY78RiemudfCeAemN8EBlIpA==}
     engines: {node: '>=12'}
@@ -2275,15 +2102,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-windows-64/0.14.54:
-    resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-windows-64/0.15.6:
     resolution: {integrity: sha512-KpPOh4aTOo//g9Pk2oVAzXMpc9Sz9n5A9sZTmWqDSXCiiachfFhbuFlsKBGATYCVitXfmBIJ4nNYYWSOdz4hQg==}
     engines: {node: '>=12'}
@@ -2292,15 +2110,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild-windows-arm64/0.14.54:
-    resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /esbuild-windows-arm64/0.15.6:
     resolution: {integrity: sha512-DB3G2x9OvFEa00jV+OkDBYpufq5x/K7a6VW6E2iM896DG4ZnAvJKQksOsCPiM1DUaa+DrijXAQ/ZOcKAqf/3Hg==}
     engines: {node: '>=12'}
@@ -2309,35 +2118,6 @@ packages:
     requiresBuild: true
     optional: true
 
-  /esbuild/0.14.54:
-    resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/linux-loong64': 0.14.54
-      esbuild-android-64: 0.14.54
-      esbuild-android-arm64: 0.14.54
-      esbuild-darwin-64: 0.14.54
-      esbuild-darwin-arm64: 0.14.54
-      esbuild-freebsd-64: 0.14.54
-      esbuild-freebsd-arm64: 0.14.54
-      esbuild-linux-32: 0.14.54
-      esbuild-linux-64: 0.14.54
-      esbuild-linux-arm: 0.14.54
-      esbuild-linux-arm64: 0.14.54
-      esbuild-linux-mips64le: 0.14.54
-      esbuild-linux-ppc64le: 0.14.54
-      esbuild-linux-riscv64: 0.14.54
-      esbuild-linux-s390x: 0.14.54
-      esbuild-netbsd-64: 0.14.54
-      esbuild-openbsd-64: 0.14.54
-      esbuild-sunos-64: 0.14.54
-      esbuild-windows-32: 0.14.54
-      esbuild-windows-64: 0.14.54
-      esbuild-windows-arm64: 0.14.54
-    dev: false
-
   /esbuild/0.15.6:
     resolution: {integrity: sha512-sgLOv3l4xklvXzzczhRwKRotyrfyZ2i1fCS6PTOLPd9wevDPArGU8HFtHrHCOcsMwTjLjzGm15gvC8uxVzQf+w==}
     engines: {node: '>=12'}
@@ -4864,33 +4644,6 @@ packages:
     optionalDependencies:
       fsevents: 2.3.2
 
-  /vite/3.1.0-beta.2:
-    resolution: {integrity: sha512-JD1I8S29RFAEL94/bamrdJd3VlLQROcGwQxb8X1hRWDtwmPTves8TmZCaQ4g460j6zZxyLYwSVHwkGCQ2k07og==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    hasBin: true
-    peerDependencies:
-      less: '*'
-      sass: '*'
-      stylus: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      less:
-        optional: true
-      sass:
-        optional: true
-      stylus:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      esbuild: 0.15.6
-      postcss: 8.4.16
-      resolve: 1.22.1
-      rollup: 2.78.1
-    optionalDependencies:
-      fsevents: 2.3.2
-    dev: true
-
   /vscode-oniguruma/1.6.2:
     resolution: {integrity: sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==}
     dev: true


Test patch:
diff --git a/packages/kit/src/utils/unit_test.js b/packages/kit/src/utils/unit_test.js
new file mode 100644
index 000000000..eca30f1b4
--- /dev/null
+++ b/packages/kit/src/utils/unit_test.js
@@ -0,0 +1,11 @@
+import { suite } from 'uvu';
+
+/**
+ * @param {string} name
+ * @param {(suite: import('uvu').Test<import('uvu').Context>) => void} fn
+ */
+export function describe(name, fn) {
+	const s = suite(name);
+	fn(s);
+	s.run();
+}
diff --git a/packages/kit/test/build-errors/apps/server-only-folder-dynamic-import/package.json b/packages/kit/test/build-errors/apps/server-only-folder-dynamic-import/package.json
index e407678f5..9f80575ef 100644
--- a/packages/kit/test/build-errors/apps/server-only-folder-dynamic-import/package.json
+++ b/packages/kit/test/build-errors/apps/server-only-folder-dynamic-import/package.json
@@ -14,7 +14,7 @@
 		"svelte": "^3.44.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.8.2",
-		"vite": "^3.1.0-beta.1"
+		"vite": "^3.1.0"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/build-errors/apps/server-only-folder/package.json b/packages/kit/test/build-errors/apps/server-only-folder/package.json
index e7bf50ae9..b547e6422 100644
--- a/packages/kit/test/build-errors/apps/server-only-folder/package.json
+++ b/packages/kit/test/build-errors/apps/server-only-folder/package.json
@@ -14,7 +14,7 @@
 		"svelte": "^3.44.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.8.2",
-		"vite": "^3.1.0-beta.1"
+		"vite": "^3.1.0"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/build-errors/apps/server-only-module-dynamic-import/package.json b/packages/kit/test/build-errors/apps/server-only-module-dynamic-import/package.json
index 0cdc65ca6..2755a61c8 100644
--- a/packages/kit/test/build-errors/apps/server-only-module-dynamic-import/package.json
+++ b/packages/kit/test/build-errors/apps/server-only-module-dynamic-import/package.json
@@ -14,7 +14,7 @@
 		"svelte": "^3.44.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.8.2",
-		"vite": "^3.1.0-beta.1"
+		"vite": "^3.1.0"
 	},
 	"type": "module"
 }
diff --git a/packages/kit/test/build-errors/apps/server-only-module/package.json b/packages/kit/test/build-errors/apps/server-only-module/package.json
index 819943cde..b03d4e027 100644
--- a/packages/kit/test/build-errors/apps/server-only-module/package.json
+++ b/packages/kit/test/build-errors/apps/server-only-module/package.json
@@ -14,7 +14,7 @@
 		"svelte": "^3.44.0",
 		"svelte-check": "^2.7.1",
 		"typescript": "^4.8.2",
-		"vite": "^3.1.0-beta.1"
+		"vite": "^3.1.0"
 	},
 	"type": "module"
 }