Repository: sveltejs/kit (js)

Issue:
SPA mode fails when importing code with client-side only variables (worked prior 1.0.0-next.405)
### Describe the bug

Importing code into a Svelte file that contains client-side only variables like `location` will cause vite errors in dev and build.

### Reproduction

Uses: `@sveltejs/adapter-static` and SSR: false 

https://stackblitz.com/github/rob-balfre/sveltekit-static-bug?file=src%2Froutes%2F%2Bpage.svelte

Running dev will show `location is not defined`.

Only errors if `location` is called via an import. 



### Logs

```shell
❯ npm install && npm run dev
warn preInstall No description field
warn preInstall No repository field
warn preInstall No license field
┌ [1/4] 🔍  Resolving dependencies
└ Completed in 0.064s
┌ [2/4] 🚚  Fetching dependencies
│ info pruneDeps Excluding 13 dependencies. For more information use `--verbose`.
└ Completed in 0.948s
┌ [3/4] 🔗  Linking dependencies
└ Completed in 0.186s
info security We found `install` scripts which turbo skips for security reasons. For more information see
https://turbo.sh/install-scripts.
├─ @sveltejs/kit@1.0.0-next.408
└─ esbuild@0.14.54
info Some packages were automatically replaced with polyfills. For more information see
https://turbo.sh/polyfills.
└─ esbuild@0.14.54 => esbuild-wasm@0.14.54

success Saved lockfile "package-lock.json"
success Updated "package.json"

success Install finished in 1.23s
$ vite dev

  VITE v3.0.7  ready in 1600 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
location is not defined
ReferenceError: location is not defined
    at /src/lib/foo.js:2:10
    at instantiateModule (file:///home/projects/kkviylzwo.github/node_modules/vite/dist/node/chunks/dep-0f13c890.js:50549:15)
```


### System Info

```shell
System:
    OS: macOS 12.5
    CPU: (8) arm64 Apple M1
    Memory: 85.89 MB / 8.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 17.9.0 - /opt/homebrew/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 8.5.5 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 104.0.5112.79
    Firefox: 96.0
    Safari: 15.6
    Safari Technology Preview: 16.0
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.64 
    @sveltejs/adapter-static: ^1.0.0-next.39 => 1.0.0-next.39 
    @sveltejs/kit: 1.0.0-next.408 => 1.0.0-next.408 
    svelte: ^3.44.0 => 3.49.0 
    vite: ^3.0.0 => 3.0.7
```


### Severity

blocking an upgrade

### Additional Information

Worked fine prior to 1.0.0-next.405. 

Pull request description:
[fix] Lazy load Svelte components to reenable no-ssr use cases
Fixes #5909

### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [x] 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
- [ ] 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


Patch:
diff --git a/.changeset/fluffy-crews-fry.md b/.changeset/fluffy-crews-fry.md
new file mode 100644
index 000000000..3437e2c8d
--- /dev/null
+++ b/.changeset/fluffy-crews-fry.md
@@ -0,0 +1,5 @@
+---
+'svelte-migrate': patch
+---
+
+Migrate type comments on arrow functions
diff --git a/.changeset/pre.json b/.changeset/pre.json
index f13e3bb3d..49501cca8 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -280,6 +280,7 @@
     "flat-stingrays-talk",
     "flat-turtles-scream",
     "fluffy-cheetahs-remain",
+    "fluffy-crews-fry",
     "fluffy-dryers-jump",
     "fluffy-seahorses-sell",
     "forty-cycles-punch",
@@ -729,6 +730,7 @@
     "rare-deers-hunt",
     "rare-mice-mate",
     "rare-pots-invite",
+    "rare-spiders-ring",
     "rare-ways-watch",
     "real-bikes-matter",
     "real-cherries-exercise",
@@ -869,6 +871,7 @@
     "smart-pears-accept",
     "smart-peas-compare",
     "smart-planets-beam",
+    "smooth-bags-sell",
     "smooth-cars-build",
     "smooth-cars-reflect",
     "smooth-comics-mate",
diff --git a/.changeset/rare-spiders-ring.md b/.changeset/rare-spiders-ring.md
new file mode 100644
index 000000000..45de42c65
--- /dev/null
+++ b/.changeset/rare-spiders-ring.md
@@ -0,0 +1,5 @@
+---
+'svelte-migrate': patch
+---
+
+Use LayoutLoad inside +layout.js files
diff --git a/.changeset/smooth-bags-sell.md b/.changeset/smooth-bags-sell.md
new file mode 100644
index 000000000..e7a5114c5
--- /dev/null
+++ b/.changeset/smooth-bags-sell.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-cloudflare-workers': patch
+---
+
+expose caches on platform
diff --git a/.changeset/tender-bottles-cheer.md b/.changeset/tender-bottles-cheer.md
new file mode 100644
index 000000000..fd86682f2
--- /dev/null
+++ b/.changeset/tender-bottles-cheer.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Lazy load Svelte components to reenable no-ssr use cases
diff --git a/documentation/docs/01-project-structure.md b/documentation/docs/01-project-structure.md
index dff7f3d21..2eac580f2 100644
--- a/documentation/docs/01-project-structure.md
+++ b/documentation/docs/01-project-structure.md
@@ -17,6 +17,8 @@ my-project/
 │ └ hooks.js
 ├ static/
 │ └ [your static assets]
+├ tests/
+│ └ [your tests]
 ├ package.json
 ├ svelte.config.js
 ├ tsconfig.json
@@ -48,6 +50,10 @@ You can use `.ts` files instead of `.js` files, if using TypeScript.
 
 Any static assets that should be served as-is, like `robots.txt` or `favicon.png`, go in here.
 
+#### tests
+
+If you chose to add tests to your project during `npm create svelte@latest`, they will live in this directory.
+
 #### package.json
 
 Your `package.json` file must include `@sveltejs/kit`, `svelte` and `vite` as `devDependencies`.
diff --git a/documentation/docs/19-accessibility.md b/documentation/docs/19-accessibility.md
new file mode 100644
index 000000000..b2ca4c9aa
--- /dev/null
+++ b/documentation/docs/19-accessibility.md
@@ -0,0 +1,88 @@
+---
+title: Accessibility
+---
+
+SvelteKit strives to provide an accessible platform for your app by default. Svelte's [compile-time accessibility checks](https://svelte.dev/docs#accessibility-warnings) will also apply to any SvelteKit application you build.
+
+Here's how SvelteKit's built-in accessibility features work and what you need to do to help these features to work as well as possible. Keep in mind that while SvelteKit provides an accessible foundation, you are still responsible for making sure your application code is accessible. If you're new to accessibility, see the ["further reading"](/docs/accessibility#further-reading) section of this guide for additional resources.
+
+We recognize that accessibility can be hard to get right. If you want to suggest improvements to how SvelteKit handles accessibility, please [open a GitHub issue](https://github.com/sveltejs/kit/issues).
+
+### Route announcements
+
+In traditional server-rendered applications, every navigation (e.g. clicking on an `<a>` tag) triggers a full page reload. When this happens, screen readers and other assistive technology will read out the new page's title so that users understand that the page has changed.
+
+Since navigation between pages in SvelteKit happens without reloading the page (known as [client-side routing](/docs/appendix#routing)), SvelteKit injects a [live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) onto the page that will read out the new page name after each navigation. This determines the page name to announce by inspecting the `<title>` element.
+
+Because of this behavior, every page in your app should have a unique, descriptive title. In SvelteKit, you can do this by placing a `<svelte:head>` element on each page:
+
+```svelte
+/// file: src/routes/+page.svelte
+<svelte:head>
+	<title>Todo List</title>
+</svelte:head>
+```
+
+This will allow screen readers and other assistive technology to identify the new page after a navigation occurs. Providing a descriptive title is also important for [SEO](/docs/seo#manual-setup-title-and-meta).
+
+### Focus management
+
+In traditional server-rendered applications, every navigation will reset focus to the top of the page. This ensures that people browsing the web with a keyboard or screen reader will start interacting with the page from the beginning.
+
+To simulate this behavior during client-side routing, SvelteKit focuses the `<body>` element after each navigation. If you want to customize this behavior, you can implement custom focus management logic using the `afterNavigate` hook:
+
+```js
+/// <reference types="@sveltejs/kit" />
+// ---cut---
+import { afterNavigate } from '$app/navigation';
+
+afterNavigate(() => {
+	/** @type {HTMLElement | null} */
+	const to_focus = document.querySelector('.focus-me');
+	to_focus?.focus();
+});
+```
+
+You can also programmatically navigate to a different page using the [`goto`](/docs/modules#$app-navigation-goto) function. By default, this will have the same client-side routing behavior as clicking on a link. However, `goto` also accepts a `keepfocus` option that will preserve the currently-focused element instead of resetting focus. If you enable this option, make sure the currently-focused element still exists on the page after navigation. If the element no longer exists, the user's focus will be lost, making for a confusing experience for assistive technology users.
+
+### The "lang" attribute
+
+By default, SvelteKit's page template sets the default language of the document to English. If your content is not in English, you should update the `<html>` element in `src/app.html` to have the correct [`lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang#accessibility) attribute. This will ensure that any assistive technology reading the document uses the correct pronunciation. For example, if your content is in German, you should update `app.html` to the following:
+
+```html
+/// file: src/app.html
+<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#handle):
+
+```html
+/// file: src/app.html
+<html lang="%lang%">
+```
+
+```js
+/// file: src/hooks.js
+/**
+ * @param {import('@sveltejs/kit').RequestEvent} event
+ * @returns {string}
+ */
+function get_lang(event) {
+	return 'en';
+}
+// ---cut---
+/** @type {import('@sveltejs/kit').Handle} */
+export function handle({ event, resolve }) {
+	return resolve(event, {
+		transformPageChunk: ({ html }) => html.replace('%lang%', get_lang(event))
+	});
+}
+```
+
+### Further reading
+
+For the most part, building an accessible SvelteKit app is the same as building an accessible web app. You should be able to apply information from the following general accessibility resources to any web experience you build:
+
+- [MDN Web Docs: Accessibility](https://developer.mozilla.org/en-US/docs/Learn/Accessibility)
+- [The A11y Project](https://www.a11yproject.com/)
+- [How to Meet WCAG (Quick Reference)](https://www.w3.org/WAI/WCAG21/quickref/)
diff --git a/package.json b/package.json
index 4bf2b64b6..3aa8f7a12 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
 		"@rollup/plugin-json": "^4.1.0",
 		"@rollup/plugin-node-resolve": "^13.3.0",
 		"@svitejs/changesets-changelog-github-compact": "^0.1.1",
-		"playwright": "^1.23.4",
+		"playwright": "^1.25.0",
 		"prettier": "^2.6.2",
 		"rollup": "^2.75.7",
 		"svelte": "^3.48.0",
diff --git a/packages/adapter-cloudflare-workers/CHANGELOG.md b/packages/adapter-cloudflare-workers/CHANGELOG.md
index 71b73f105..916480c4e 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.53
+
+### Patch Changes
+
+- expose caches on platform ([#5887](https://github.com/sveltejs/kit/pull/5887))
+
 ## 1.0.0-next.52
 
 ### Patch Changes
diff --git a/packages/adapter-cloudflare-workers/files/entry.js b/packages/adapter-cloudflare-workers/files/entry.js
index cd784e5d3..0646c7acc 100644
--- a/packages/adapter-cloudflare-workers/files/entry.js
+++ b/packages/adapter-cloudflare-workers/files/entry.js
@@ -67,7 +67,7 @@ export default {
 
 		// dynamically-generated pages
 		return await server.respond(req, {
-			platform: { env, context },
+			platform: { env, context, caches },
 			getClientAddress() {
 				return req.headers.get('cf-connecting-ip');
 			}
diff --git a/packages/adapter-cloudflare-workers/package.json b/packages/adapter-cloudflare-workers/package.json
index 42b9d1542..fcc8cbce0 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.52",
+	"version": "1.0.0-next.53",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/adapter-static/package.json b/packages/adapter-static/package.json
index bc7eef732..271b8b051 100644
--- a/packages/adapter-static/package.json
+++ b/packages/adapter-static/package.json
@@ -27,7 +27,7 @@
 	"devDependencies": {
 		"@sveltejs/kit": "workspace:*",
 		"@types/node": "^16.11.36",
-		"playwright-chromium": "^1.23.4",
+		"playwright-chromium": "^1.25.0",
 		"sirv": "^2.0.2",
 		"svelte": "^3.48.0",
 		"typescript": "^4.7.4",
diff --git a/packages/create-svelte/package.json b/packages/create-svelte/package.json
index 075cbe91a..523f092c3 100644
--- a/packages/create-svelte/package.json
+++ b/packages/create-svelte/package.json
@@ -15,7 +15,7 @@
 		"prompts": "^2.4.2"
 	},
 	"devDependencies": {
-		"@playwright/test": "^1.23.4",
+		"@playwright/test": "^1.25.0",
 		"@sveltejs/kit": "workspace:*",
 		"@types/gitignore-parser": "^0.0.0",
 		"@types/prettier": "^2.6.3",
diff --git a/packages/create-svelte/shared/+playwright/package.json b/packages/create-svelte/shared/+playwright/package.json
index f74139d99..884fcc10a 100644
--- a/packages/create-svelte/shared/+playwright/package.json
+++ b/packages/create-svelte/shared/+playwright/package.json
@@ -1,6 +1,6 @@
 {
 	"devDependencies": {
-		"@playwright/test": "^1.22.2"
+		"@playwright/test": "^1.25.0"
 	},
 	"scripts": {
 		"test": "playwright test"
diff --git a/packages/kit/package.json b/packages/kit/package.json
index c58e25f45..a58cc1041 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -25,7 +25,7 @@
 		"undici": "^5.8.1"
 	},
 	"devDependencies": {
-		"@playwright/test": "^1.23.4",
+		"@playwright/test": "^1.25.0",
 		"@types/connect": "^3.4.35",
 		"@types/cookie": "^0.5.1",
 		"@types/marked": "^4.0.3",
diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js
index ea4969da9..1e1fc04b8 100644
--- a/packages/kit/src/runtime/server/page/render.js
+++ b/packages/kit/src/runtime/server/page/render.js
@@ -79,20 +79,6 @@ export async function render_response({
 	}
 
 	if (resolve_opts.ssr) {
-		for (const { node } of branch) {
-			if (node.imports) {
-				node.imports.forEach((url) => modulepreloads.add(url));
-			}
-
-			if (node.stylesheets) {
-				node.stylesheets.forEach((url) => stylesheets.add(url));
-			}
-
-			if (node.inline_styles) {
-				Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
-			}
-		}
-
 		const session = writable($session);
 
 		/** @type {Record<string, any>} */
@@ -112,7 +98,7 @@ export async function render_response({
 				url: state.prerendering ? new PrerenderingURL(event.url) : event.url,
 				data: branch.reduce((acc, { data }) => (Object.assign(acc, data), acc), {})
 			},
-			components: branch.map(({ node }) => node.component)
+			components: await Promise.all(branch.map(({ node }) => node.component()))
 		};
 
 		// TODO remove this for 1.0
@@ -143,6 +129,20 @@ export async function render_response({
 		}
 
 		rendered = options.root.render(props);
+
+		for (const { node } of branch) {
+			if (node.imports) {
+				node.imports.forEach((url) => modulepreloads.add(url));
+			}
+
+			if (node.stylesheets) {
+				node.stylesheets.forEach((url) => stylesheets.add(url));
+			}
+
+			if (node.inline_styles) {
+				Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
+			}
+		}
 	} else {
 		rendered = { head: '', html: '', css: { code: '', map: null } };
 	}
diff --git a/packages/kit/src/vite/build/build_server.js b/packages/kit/src/vite/build/build_server.js
index 7e3df1a9d..e7c358fda 100644
--- a/packages/kit/src/vite/build/build_server.js
+++ b/packages/kit/src/vite/build/build_server.js
@@ -239,6 +239,8 @@ export async function build_server(options, client) {
 		/** @type {string[]} */
 		const imports = [];
 
+		// String representation of
+		/** @type {import('types').SSRNode} */
 		/** @type {string[]} */
 		const exports = [`export const index = ${i};`];
 
@@ -255,7 +257,9 @@ export async function build_server(options, client) {
 			stylesheets.push(...entry.stylesheets);
 
 			exports.push(
-				`export { default as component } from '../${vite_manifest[node.component].file}';`,
+				`export const component = async () => (await import('../${
+					vite_manifest[node.component].file
+				}')).default;`,
 				`export const file = '${entry.file}';` // TODO what is this?
 			);
 		}
diff --git a/packages/kit/src/vite/dev/index.js b/packages/kit/src/vite/dev/index.js
index 5b1968236..438c94fb0 100644
--- a/packages/kit/src/vite/dev/index.js
+++ b/packages/kit/src/vite/dev/index.js
@@ -82,19 +82,23 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) {
 						result.stylesheets = [];
 
 						if (node.component) {
-							const { module, module_node, url } = await resolve(node.component);
-
-							module_nodes.push(module_node);
-
-							result.component = module.default;
-							result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
-
-							prevent_illegal_vite_imports(
-								module_node,
-								illegal_imports,
-								extensions,
-								svelte_config.kit.outDir
-							);
+							result.component = async () => {
+								const { module_node, module, url } = await resolve(
+									/** @type {string} */ (node.component)
+								);
+
+								module_nodes.push(module_node);
+								result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
+
+								prevent_illegal_vite_imports(
+									module_node,
+									illegal_imports,
+									extensions,
+									svelte_config.kit.outDir
+								);
+
+								return module.default;
+							};
 						}
 
 						if (node.shared) {
diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts
index 059e8e078..c6f2d141e 100644
--- a/packages/kit/types/internal.d.ts
+++ b/packages/kit/types/internal.d.ts
@@ -196,7 +196,7 @@ export interface SSREndpoint {
 }
 
 export interface SSRNode {
-	component: SSRComponent;
+	component: SSRComponentLoader;
 	/** index into the `components` array in client-manifest.js */
 	index: number;
 	/** client-side module URL for this component */
@@ -281,11 +281,6 @@ export interface SSRErrorPage {
 	id: '__error';
 }
 
-export interface SSRPagePart {
-	id: string;
-	load: SSRComponentLoader;
-}
-
 export type SSRRoute = SSREndpoint | SSRPage;
 
 export interface SSRState {
diff --git a/packages/migrate/CHANGELOG.md b/packages/migrate/CHANGELOG.md
index fe3be1a34..162617aac 100644
--- a/packages/migrate/CHANGELOG.md
+++ b/packages/migrate/CHANGELOG.md
@@ -1,5 +1,13 @@
 # svelte-migrate
 
+## 1.0.0-next.7
+
+### Patch Changes
+
+- Migrate type comments on arrow functions ([#5933](https://github.com/sveltejs/kit/pull/5933))
+
+* Use LayoutLoad inside +layout.js files ([#5931](https://github.com/sveltejs/kit/pull/5931))
+
 ## 1.0.0-next.6
 
 ### Patch Changes
diff --git a/packages/migrate/migrations/routes/migrate_page_js/index.js b/packages/migrate/migrations/routes/migrate_page_js/index.js
index 5f60b7d49..308a9b9d0 100644
--- a/packages/migrate/migrations/routes/migrate_page_js/index.js
+++ b/packages/migrate/migrations/routes/migrate_page_js/index.js
@@ -37,8 +37,8 @@ export function migrate_page(content, filename) {
 		return content;
 	}
 
-	const match = /\+(?:(page)|(layout(?:-([^.@]+))?))/.exec(filename);
-	const load_name = match?.[3] ? `LayoutLoad.${match[3]}` : match?.[2] ? `LayoutLoad` : 'PageLoad';
+	const match = /__layout(?:-([^.@]+))?/.exec(filename);
+	const load_name = match?.[1] ? `LayoutLoad.${match[1]}` : match ? `LayoutLoad` : 'PageLoad';
 
 	for (const statement of file.ast.statements) {
 		const fn = name ? get_function_node(statement, name) : undefined;
diff --git a/packages/migrate/migrations/routes/migrate_page_js/samples.md b/packages/migrate/migrations/routes/migrate_page_js/samples.md
index 0e4c36826..3f72c848a 100644
--- a/packages/migrate/migrations/routes/migrate_page_js/samples.md
+++ b/packages/migrate/migrations/routes/migrate_page_js/samples.md
@@ -191,6 +191,7 @@ export function load() {
 ## Arrow function load
 
 ```js before
+/** @type {import('./$types').Load} */
 export const load = () => ({
 	props: {
 		a: 1
@@ -199,6 +200,7 @@ export const load = () => ({
 ```
 
 ```js after
+/** @type {import('./$types').PageLoad} */
 export const load = () => ({
 	a: 1
 });
diff --git a/packages/migrate/migrations/routes/migrate_page_server/samples.md b/packages/migrate/migrations/routes/migrate_page_server/samples.md
index 85c4ddb9d..3d717164d 100644
--- a/packages/migrate/migrations/routes/migrate_page_server/samples.md
+++ b/packages/migrate/migrations/routes/migrate_page_server/samples.md
@@ -92,6 +92,7 @@ export function load() {
 ## Arrow function GET
 
 ```js before
+/** @type {import('./$types').RequestHandler} */
 export const GET = () => ({
 	body: {
 		a: 1
@@ -100,6 +101,7 @@ export const GET = () => ({
 ```
 
 ```js after
+/** @type {import('./$types').PageServerLoad} */
 export const load = () => ({
 	a: 1
 });
diff --git a/packages/migrate/migrations/routes/utils.js b/packages/migrate/migrations/routes/utils.js
index 8152f9d91..0b2bb99c9 100644
--- a/packages/migrate/migrations/routes/utils.js
+++ b/packages/migrate/migrations/routes/utils.js
@@ -473,9 +473,10 @@ export function read_samples(test_file) {
  */
 export function rewrite_type(node, code, old_type, new_type) {
 	// @ts-ignore
-	if (node.jsDoc) {
+	let jsDoc = node.jsDoc || node.parent?.parent?.parent?.jsDoc;
+	if (jsDoc) {
 		// @ts-ignore
-		for (const comment of node.jsDoc) {
+		for (const comment of jsDoc) {
 			const str = comment.getText();
 			const index = str.indexOf(old_type);
 
diff --git a/packages/migrate/package.json b/packages/migrate/package.json
index 4404cab09..ced007ffc 100644
--- a/packages/migrate/package.json
+++ b/packages/migrate/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "svelte-migrate",
-	"version": "1.0.0-next.6",
+	"version": "1.0.0-next.7",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6932337cd..9e91bea04 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,7 +9,7 @@ importers:
       '@rollup/plugin-json': ^4.1.0
       '@rollup/plugin-node-resolve': ^13.3.0
       '@svitejs/changesets-changelog-github-compact': ^0.1.1
-      playwright: ^1.23.4
+      playwright: ^1.25.0
       prettier: ^2.6.2
       rollup: ^2.75.7
       svelte: ^3.48.0
@@ -22,7 +22,7 @@ importers:
       '@rollup/plugin-json': 4.1.0_rollup@2.75.7
       '@rollup/plugin-node-resolve': 13.3.0_rollup@2.75.7
       '@svitejs/changesets-changelog-github-compact': 0.1.1
-      playwright: 1.23.4
+      playwright: 1.25.0
       prettier: 2.7.1
       rollup: 2.75.7
       svelte: 3.48.0
@@ -144,7 +144,7 @@ importers:
     specifiers:
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
-      playwright-chromium: ^1.23.4
+      playwright-chromium: ^1.25.0
       sirv: ^2.0.2
       svelte: ^3.48.0
       typescript: ^4.7.4
@@ -153,7 +153,7 @@ importers:
     devDependencies:
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
-      playwright-chromium: 1.23.4
+      playwright-chromium: 1.25.0
       sirv: 2.0.2
       svelte: 3.48.0
       typescript: 4.7.4
@@ -204,7 +204,7 @@ importers:
 
   packages/create-svelte:
     specifiers:
-      '@playwright/test': ^1.23.4
+      '@playwright/test': ^1.25.0
       '@sveltejs/kit': workspace:*
       '@types/gitignore-parser': ^0.0.0
       '@types/prettier': ^2.6.3
@@ -223,7 +223,7 @@ importers:
       kleur: 4.1.5
       prompts: 2.4.2
     devDependencies:
-      '@playwright/test': 1.23.4
+      '@playwright/test': 1.25.0
       '@sveltejs/kit': link:../kit
       '@types/gitignore-parser': 0.0.0
       '@types/prettier': 2.6.3
@@ -268,7 +268,7 @@ importers:
 
   packages/kit:
     specifiers:
-      '@playwright/test': ^1.23.4
+      '@playwright/test': ^1.25.0
       '@sveltejs/vite-plugin-svelte': ^1.0.1
       '@types/connect': ^3.4.35
       '@types/cookie': ^0.5.1
@@ -312,7 +312,7 @@ importers:
       tiny-glob: 0.2.9
       undici: 5.8.1
     devDependencies:
-      '@playwright/test': 1.23.4
+      '@playwright/test': 1.25.0
       '@types/connect': 3.4.35
       '@types/cookie': 0.5.1
       '@types/marked': 4.0.3
@@ -897,13 +897,13 @@ packages:
       fastq: 1.13.0
     dev: true
 
-  /@playwright/test/1.23.4:
-    resolution: {integrity: sha512-iIsoMJDS/lyuhw82FtcV/B3PXikgVD3hNe5hyvOpRM0uRr1OIpN3LgPeRbBjhzBWmyf6RgRg5fqK5sVcpA03yA==}
+  /@playwright/test/1.25.0:
+    resolution: {integrity: sha512-j4EZhTTQI3dBeWblE21EV//swwmBtOpIrLdOIJIRv4uqsLdHgBg1z+JtTg+AeC5o2bAXIE26kDNW5A0TimG8Bg==}
     engines: {node: '>=14'}
     hasBin: true
     dependencies:
       '@types/node': 18.0.0
-      playwright-core: 1.23.4
+      playwright-core: 1.25.0
     dev: true
 
   /@polka/url/1.0.0-next.21:
@@ -3222,28 +3222,28 @@ packages:
       find-up: 4.1.0
     dev: true
 
-  /playwright-chromium/1.23.4:
-    resolution: {integrity: sha512-aqiOpX76107knxZqydyd0snNHiU6wgGwmQUFA8MEbG6sVjvjF8fS8Uy6n39z9U52pSpRFGPBP8dfkTkXBokkqQ==}
+  /playwright-chromium/1.25.0:
+    resolution: {integrity: sha512-FH9ho3noAWVStCJx4XW78+D8QW0A99WDp53DDkYeVdEpJqCmAIKHCSE6dl5XtaDKrZPYC1ZG5hGXQh1K5H/p+g==}
     engines: {node: '>=14'}
     hasBin: true
     requiresBuild: true
     dependencies:
-      playwright-core: 1.23.4
+      playwright-core: 1.25.0
     dev: true
 
-  /playwright-core/1.23.4:
-    resolution: {integrity: sha512-h5V2yw7d8xIwotjyNrkLF13nV9RiiZLHdXeHo+nVJIYGVlZ8U2qV0pMxNJKNTvfQVT0N8/A4CW6/4EW2cOcTiA==}
+  /playwright-core/1.25.0:
+    resolution: {integrity: sha512-kZ3Jwaf3wlu0GgU0nB8UMQ+mXFTqBIFz9h1svTlNduNKjnbPXFxw7mJanLVjqxHJRn62uBfmgBj93YHidk2N5Q==}
     engines: {node: '>=14'}
     hasBin: true
     dev: true
 
-  /playwright/1.23.4:
-    resolution: {integrity: sha512-NUPOLMpd8WydmwZFllST/YZ7cImgDDDrvcaq7Gj2vAjNg0jYCndFJt6HHtbkOPSIlRo4BaQYlbFx6meq1r1FXQ==}
+  /playwright/1.25.0:
+    resolution: {integrity: sha512-Z+pQNWI17Qx/tHhnmgMmPsptsisXpKgAnUvYv98kctlHUJaqMt2400P8kTw9vEPoC0xdxqu0JhxO7pDTmaaIKw==}
     engines: {node: '>=14'}
     hasBin: true
     requiresBuild: true
     dependencies:
-      playwright-core: 1.23.4
+      playwright-core: 1.25.0
     dev: true
 
   /polka/1.0.0-next.22:
diff --git a/sites/kit.svelte.dev/src/routes/+page.svelte b/sites/kit.svelte.dev/src/routes/+page.svelte
index 0207d1761..3aa00a046 100644
--- a/sites/kit.svelte.dev/src/routes/+page.svelte
+++ b/sites/kit.svelte.dev/src/routes/+page.svelte
@@ -66,10 +66,7 @@
 			</p>
 
 			<p>
-				Read the <a href="https://svelte.dev/blog/whats-the-deal-with-sveltekit" class="cta"
-					>introductory blog</a
-				>
-				post to learn more.
+				<a href="https://node.new/sveltekit">Try it on StackBlitz</a> or create a project locally.
 			</p>
 		</div>
 


Test patch:
diff --git a/packages/create-svelte/test/check.js b/packages/create-svelte/test/check.js
index 5e9fdd8bb..2fa477952 100644
--- a/packages/create-svelte/test/check.js
+++ b/packages/create-svelte/test/check.js
@@ -5,22 +5,25 @@ import { test } from 'uvu';
 import * as assert from 'uvu/assert';
 import { create } from '../index.js';
 import { fileURLToPath } from 'url';
+import glob from 'tiny-glob';
 // use a directory outside of packages to ensure it isn't added to the pnpm workspace
 const test_workspace_dir = fileURLToPath(
 	new URL('../../../.test-tmp/create-svelte/', import.meta.url)
 );
-const overrides = {};
-['kit', 'adapter-auto', 'adapter-cloudflare', 'adapter-netlify', 'adapter-vercel'].forEach(
-	(pkg) => {
-		overrides[`@sveltejs/${pkg}`] = `${path.resolve(
-			test_workspace_dir,
-			'..',
-			'..',
-			'packages',
-			pkg
-		)}`; //'workspace:*';
-	}
-);
+
+const existing_workspace_overrides = JSON.parse(
+	fs.readFileSync(fileURLToPath(new URL('../../../package.json', import.meta.url)), 'utf-8')
+).pnpm?.overrides;
+
+const overrides = { ...existing_workspace_overrides };
+
+(
+	await glob(fileURLToPath(new URL('../../../packages', import.meta.url)) + '/*/package.json')
+).forEach((pkgPath) => {
+	const name = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).name;
+	overrides[name] = path.dirname(path.resolve(pkgPath));
+});
+
 test.before(() => {
 	try {
 		// prepare test pnpm workspace
@@ -69,6 +72,13 @@ for (const template of fs.readdirSync('templates')) {
 				if (pkg.dependencies?.[key]) {
 					pkg.dependencies[key] = value;
 				}
+				if (!pkg.pnpm) {
+					pkg.pnpm = {};
+				}
+				if (!pkg.pnpm.overrides) {
+					pkg.pnpm.overrides = {};
+				}
+				pkg.pnpm.overrides = { ...pkg.pnpm.overrides, ...overrides };
 			});
 			pkg.private = true;
 			fs.writeFileSync(path.join(cwd, 'package.json'), JSON.stringify(pkg, null, '\t') + '\n');
diff --git a/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte b/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte
new file mode 100644
index 000000000..2e48a4f8e
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/no-ssr/browser-only-global/+page.svelte
@@ -0,0 +1,5 @@
+<script context="module">
+	document;
+</script>
+
+<p>Works</p>
diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js
index 4326213bc..cef1f3721 100644
--- a/packages/kit/test/apps/basics/test/client.test.js
+++ b/packages/kit/test/apps/basics/test/client.test.js
@@ -110,10 +110,13 @@ test.describe('Scrolling', () => {
 		const originalScrollY = /** @type {number} */ (await page.evaluate(() => scrollY));
 		await clicknav('#routing-page');
 		await page.goBack();
+		await page.waitForLoadState('networkidle');
 		expect(page.url()).toBe(baseURL + '/anchor#last-anchor-2');
 		expect(await page.evaluate(() => scrollY)).toEqual(originalScrollY);
 
 		await page.goBack();
+		await page.waitForLoadState('networkidle');
+
 		expect(page.url()).toBe(baseURL + '/anchor');
 		expect(await page.evaluate(() => scrollY)).toEqual(0);
 	});
@@ -349,6 +352,7 @@ test.describe('Load', () => {
 		await page.goto('/load/change-detection/session/used');
 		expect(await page.textContent('h2')).toBe('1');
 		await page.click('button');
+		await page.waitForLoadState('networkidle');
 		expect(await page.textContent('h2')).toBe('2');
 
 		await page.goto('/load/change-detection/session/unused');
@@ -375,6 +379,7 @@ test.describe('Load', () => {
 		await clicknav('[href="/load/layout-props/b"]');
 		expect(await page.textContent('h1')).toBe('1');
 		await page.click('button');
+		await page.waitForLoadState('networkidle');
 		expect(await page.textContent('h1')).toBe('2');
 	});
 
@@ -535,7 +540,7 @@ test.describe('Routing', () => {
 		await clicknav('a[href="/routing/a"]');
 		expect(await page.textContent('h1')).toBe('a');
 
-		expect(requests).toEqual([]);
+		expect(requests.filter((url) => !url.endsWith('/favicon.png'))).toEqual([]);
 	});
 
 	test('navigates programmatically', async ({ page, app }) => {
@@ -563,7 +568,7 @@ test.describe('Routing', () => {
 		const urls = [];
 
 		const { port, close } = await start_server((req, res) => {
-			urls.push(req.url);
+			if (req.url !== '/favicon.ico') urls.push(req.url);
 			res.end('ok');
 		});
 
@@ -607,6 +612,7 @@ test.describe('Page Store', () => {
 		);
 
 		await page.click('button');
+		await page.waitForLoadState('networkidle');
 
 		expect(await page.textContent('#page-data')).toBe('{"answer":1337}');
 		expect(await page.textContent('#store-data')).toBe(
@@ -614,3 +620,9 @@ test.describe('Page Store', () => {
 		);
 	});
 });
+
+test('Can use browser-only global on client-only page', async ({ page, read_errors }) => {
+	await page.goto('/no-ssr/browser-only-global');
+	await expect(page.locator('p')).toHaveText('Works');
+	expect(read_errors('/no-ssr/browser-only-global')).toBe(undefined);
+});
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index b5dad6f1f..75f6c7a8a 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -1446,6 +1446,7 @@ test.describe('Routing', () => {
 		await clicknav('[href="/routing/a"]');
 
 		await page.goBack();
+		await page.waitForLoadState('networkidle');
 		expect(await page.textContent('h1')).toBe('Great success!');
 	});