Repository: sveltejs/kit
Pull request #6917 (2022-09-20 13:44:14)

Include ambient.d.ts files in adapter packages.
Fixes automatic typing for Cloudflare caches and similar stuff.

### 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.
- [ ] 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: c2661916a2d5569a1990e15460ee2c7802aeaf9b

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

<details><summary>This PR includes changesets to release 6 packages</summary>

  | Name                                 | Type  |
| ------------------------------------ | ----- |
| @sveltejs/adapter-cloudflare         | Patch |
| @sveltejs/adapter-cloudflare-workers | Patch |
| @sveltejs/adapter-netlify            | Patch |
| @sveltejs/adapter-node               | Patch |
| @sveltejs/adapter-vercel             | Patch |
| @sveltejs/adapter-auto               | 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/SG60/kit/new/fix-adapters-ambient.d.ts?filename=.changeset/twelve-jeans-swim.md&value=---%0A%22%40sveltejs%2Fadapter-cloudflare-workers%22%3A%20patch%0A%22%40sveltejs%2Fadapter-cloudflare%22%3A%20patch%0A%22%40sveltejs%2Fadapter-netlify%22%3A%20patch%0A%22%40sveltejs%2Fadapter-node%22%3A%20patch%0A%22%40sveltejs%2Fadapter-vercel%22%3A%20patch%0A---%0A%0AInclude%20ambient.d.ts%20files%20in%20adapter%20packages.%0A)


SG60: Ah ok! Sorry, didn't realise that. Thanks for making the changes.

Patch:
diff --git a/.changeset/dull-cows-sneeze.md b/.changeset/dull-cows-sneeze.md
new file mode 100644
index 000000000..fd084fe7d
--- /dev/null
+++ b/.changeset/dull-cows-sneeze.md
@@ -0,0 +1,6 @@
+---
+'@sveltejs/adapter-cloudflare': patch
+'@sveltejs/adapter-cloudflare-workers': patch
+---
+
+Include ambient.d.ts files in adapter packages.
diff --git a/.changeset/early-olives-burn.md b/.changeset/early-olives-burn.md
new file mode 100644
index 000000000..ae81419bf
--- /dev/null
+++ b/.changeset/early-olives-burn.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-node': patch
+---
+
+Add missing Rollup dependency
diff --git a/.changeset/odd-beds-smile.md b/.changeset/odd-beds-smile.md
new file mode 100644
index 000000000..63aa75272
--- /dev/null
+++ b/.changeset/odd-beds-smile.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/adapter-node': patch
+---
+
+Bundle with rollup instead of esbuild
diff --git a/.changeset/pre.json b/.changeset/pre.json
index ff8dd1048..9605d6d04 100644
--- a/.changeset/pre.json
+++ b/.changeset/pre.json
@@ -179,6 +179,7 @@
     "cold-shirts-lick",
     "cold-tables-shake",
     "cool-bananas-share",
+    "cool-beans-only",
     "cool-birds-attack",
     "cool-crabs-listen",
     "cool-drinks-press",
@@ -215,6 +216,7 @@
     "cyan-roses-act",
     "cyan-schools-kiss",
     "cyan-seals-trade",
+    "cyan-years-live",
     "dirty-bikes-join",
     "dirty-ligers-protect",
     "dry-baboons-turn",
@@ -235,6 +237,7 @@
     "early-eagles-boil",
     "early-lemons-collect",
     "early-news-taste",
+    "early-olives-burn",
     "early-pants-unite",
     "early-snakes-peel",
     "early-wasps-obey",
@@ -723,6 +726,7 @@
     "ninety-tables-switch",
     "ninety-vans-talk",
     "ninety-walls-heal",
+    "odd-beds-smile",
     "odd-bottles-drop",
     "odd-coats-shake",
     "odd-coins-lie",
@@ -969,6 +973,7 @@
     "shy-toes-punch",
     "silent-crews-change",
     "silent-cycles-reply",
+    "silent-jeans-vanish",
     "silly-ants-battle",
     "silly-grapes-cover",
     "silly-jokes-hug",
@@ -1015,6 +1020,7 @@
     "smart-apes-drum",
     "smart-bears-leave",
     "smart-deers-approve",
+    "smart-forks-double",
     "smart-humans-eat",
     "smart-mugs-chew",
     "smart-nails-work",
@@ -1364,6 +1370,7 @@
     "young-pumpkins-approve",
     "young-scissors-collect",
     "young-students-chew",
+    "young-students-relate",
     "young-swans-burn",
     "young-ways-fail"
   ]
diff --git a/.changeset/silent-jeans-vanish.md b/.changeset/silent-jeans-vanish.md
new file mode 100644
index 000000000..44b09d9c1
--- /dev/null
+++ b/.changeset/silent-jeans-vanish.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] symlink routes
diff --git a/.changeset/smart-forks-double.md b/.changeset/smart-forks-double.md
new file mode 100644
index 000000000..e98f3bbab
--- /dev/null
+++ b/.changeset/smart-forks-double.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/package': patch
+---
+
+fix check for undefined on application/ strip
diff --git a/packages/adapter-cloudflare-workers/package.json b/packages/adapter-cloudflare-workers/package.json
index f856b8e32..10516e173 100644
--- a/packages/adapter-cloudflare-workers/package.json
+++ b/packages/adapter-cloudflare-workers/package.json
@@ -19,6 +19,7 @@
 	"main": "index.js",
 	"types": "index.d.ts",
 	"files": [
+		"ambient.d.ts",
 		"files",
 		"index.d.ts"
 	],
diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json
index a27f5eaac..d25d66fa3 100644
--- a/packages/adapter-cloudflare/package.json
+++ b/packages/adapter-cloudflare/package.json
@@ -20,7 +20,8 @@
 	"files": [
 		"files",
 		"index.js",
-		"index.d.ts"
+		"index.d.ts",
+		"ambient.d.ts"
 	],
 	"main": "index.js",
 	"scripts": {
diff --git a/packages/adapter-node/CHANGELOG.md b/packages/adapter-node/CHANGELOG.md
index 43ac0fa07..ef2976151 100644
--- a/packages/adapter-node/CHANGELOG.md
+++ b/packages/adapter-node/CHANGELOG.md
@@ -1,5 +1,17 @@
 # @sveltejs/adapter-node
 
+## 1.0.0-next.94
+
+### Patch Changes
+
+- Add missing Rollup dependency ([#6927](https://github.com/sveltejs/kit/pull/6927))
+
+## 1.0.0-next.93
+
+### Patch Changes
+
+- Bundle with rollup instead of esbuild ([#6896](https://github.com/sveltejs/kit/pull/6896))
+
 ## 1.0.0-next.92
 
 ### Patch Changes
diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js
index cc3d0da78..17bb5310c 100644
--- a/packages/adapter-node/index.js
+++ b/packages/adapter-node/index.js
@@ -1,6 +1,9 @@
 import { readFileSync, writeFileSync } from 'fs';
 import { fileURLToPath } from 'url';
-import * as esbuild from 'esbuild';
+import { rollup } from 'rollup';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import json from '@rollup/plugin-json';
 
 const files = fileURLToPath(new URL('./files', import.meta.url).href);
 
@@ -49,16 +52,23 @@ export default function (opts = {}) {
 
 			const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
 
-			await esbuild.build({
-				platform: 'node',
-				sourcemap: 'linked',
-				target: 'es2022',
-				entryPoints: [`${tmp}/index.js`, `${tmp}/manifest.js`],
-				outdir: `${out}/server`,
-				splitting: true,
+			// we bundle the Vite output so that deployments only need
+			// their production dependencies. Anything in devDependencies
+			// will get included in the bundled code
+			const bundle = await rollup({
+				input: {
+					index: `${tmp}/index.js`,
+					manifest: `${tmp}/manifest.js`
+				},
+				external: [...Object.keys(pkg.dependencies || {})],
+				plugins: [nodeResolve(), commonjs(), json()]
+			});
+
+			await bundle.write({
+				dir: `${out}/server`,
 				format: 'esm',
-				bundle: true,
-				external: [...Object.keys(pkg.dependencies || {})]
+				sourcemap: true,
+				chunkFileNames: `chunks/[name]-[hash].js`
 			});
 
 			builder.copy(files, out, {
diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json
index c5d40c7fb..828853a80 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.92",
+	"version": "1.0.0-next.94",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
@@ -32,19 +32,20 @@
 		"prepublishOnly": "npm run build"
 	},
 	"devDependencies": {
-		"@rollup/plugin-json": "^4.1.0",
 		"@sveltejs/kit": "workspace:*",
 		"@types/node": "^16.11.36",
 		"c8": "^7.11.3",
 		"node-fetch": "^3.2.4",
 		"polka": "^1.0.0-next.22",
 		"rimraf": "^3.0.2",
-		"rollup": "^2.78.1",
 		"sirv": "^2.0.2",
 		"typescript": "^4.8.2",
 		"uvu": "^0.5.3"
 	},
 	"dependencies": {
-		"esbuild": "^0.15.7"
+		"@rollup/plugin-commonjs": "^22.0.1",
+		"@rollup/plugin-json": "^4.1.0",
+		"@rollup/plugin-node-resolve": "^14.1.0",
+		"rollup": "^2.78.1"
 	}
 }
diff --git a/packages/kit/CHANGELOG.md b/packages/kit/CHANGELOG.md
index 6724737a4..b7f63620b 100644
--- a/packages/kit/CHANGELOG.md
+++ b/packages/kit/CHANGELOG.md
@@ -1,5 +1,21 @@
 # @sveltejs/kit
 
+## 1.0.0-next.491
+
+### Patch Changes
+
+- [fix] symlink routes ([#6796](https://github.com/sveltejs/kit/pull/6796))
+
+## 1.0.0-next.490
+
+### Patch Changes
+
+- fix `write_types` on windows using posixify() ([#6913](https://github.com/sveltejs/kit/pull/6913))
+
+* Prevent caching of `__data.js` files ([#6904](https://github.com/sveltejs/kit/pull/6904))
+
+- Make url property getters non-enumerable ([#6909](https://github.com/sveltejs/kit/pull/6909))
+
 ## 1.0.0-next.489
 
 ### Patch Changes
diff --git a/packages/kit/package.json b/packages/kit/package.json
index 6e8a24bb0..5dba00e88 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/kit",
-	"version": "1.0.0-next.489",
+	"version": "1.0.0-next.491",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/kit/src/core/generate_manifest/index.js b/packages/kit/src/core/generate_manifest/index.js
index d0e35d59f..91ec76997 100644
--- a/packages/kit/src/core/generate_manifest/index.js
+++ b/packages/kit/src/core/generate_manifest/index.js
@@ -1,5 +1,6 @@
 import { s } from '../../utils/misc.js';
 import { get_mime_lookup } from '../utils.js';
+import { resolve_symlinks } from '../../exports/vite/build/utils.js';
 
 /**
  * Generates the data used to write the server-side manifest.js file. This data is used in the Vite
@@ -65,7 +66,7 @@ export function generate_manifest({ build_data, relative_path, routes, format =
 					names: ${s(route.names)},
 					types: ${s(route.types)},
 					page: ${route.page ? `{ layouts: ${get_nodes(route.page.layouts)}, errors: ${get_nodes(route.page.errors)}, leaf: ${route.page.leaf} }` : 'null'},
-					endpoint: ${route.endpoint ? loader(`${relative_path}/${build_data.server.vite_manifest[route.endpoint.file].file}`) : 'null'}
+					endpoint: ${route.endpoint ? loader(`${relative_path}/${resolve_symlinks(build_data.server.vite_manifest, route.endpoint.file).chunk.file}`) : 'null'}
 				}`;
 				}).filter(Boolean).join(',\n\t\t\t\t')}
 			],
diff --git a/packages/kit/src/core/sync/create_manifest_data/index.js b/packages/kit/src/core/sync/create_manifest_data/index.js
index 563c391b0..e9cd7205e 100644
--- a/packages/kit/src/core/sync/create_manifest_data/index.js
+++ b/packages/kit/src/core/sync/create_manifest_data/index.js
@@ -164,13 +164,16 @@ function create_routes_and_nodes(cwd, config, fallback) {
 
 			const dir = path.join(cwd, routes_base, id);
 
-			const files = fs.readdirSync(dir, {
-				withFileTypes: true
-			});
+			// We can't use withFileTypes because of a NodeJs bug which returns wrong results
+			// with isDirectory() in case of symlinks: https://github.com/nodejs/node/issues/30646
+			const files = fs.readdirSync(dir).map((name) => ({
+				is_dir: fs.statSync(path.join(dir, name)).isDirectory(),
+				name
+			}));
 
 			// process files first
 			for (const file of files) {
-				if (file.isDirectory()) continue;
+				if (file.is_dir) continue;
 				if (!file.name.startsWith('+')) continue;
 				if (!valid_extensions.find((ext) => file.name.endsWith(ext))) continue;
 
@@ -213,7 +216,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
 
 			// then handle children
 			for (const file of files) {
-				if (file.isDirectory()) {
+				if (file.is_dir) {
 					walk(depth + 1, path.posix.join(id, file.name), file.name, route);
 				}
 			}
diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js
index 1b53cd9fb..9b116d423 100644
--- a/packages/kit/src/exports/vite/build/build_server.js
+++ b/packages/kit/src/exports/vite/build/build_server.js
@@ -4,7 +4,13 @@ import { mkdirp, posixify, resolve_entry } from '../../../utils/filesystem.js';
 import { get_vite_config, merge_vite_configs } from '../utils.js';
 import { load_error_page, load_template } from '../../../core/config/index.js';
 import { runtime_directory } from '../../../core/utils.js';
-import { create_build, find_deps, get_default_build_config, is_http_method } from './utils.js';
+import {
+	create_build,
+	find_deps,
+	get_default_build_config,
+	is_http_method,
+	resolve_symlinks
+} from './utils.js';
 import { s } from '../../../utils/misc.js';
 
 /**
@@ -285,7 +291,7 @@ export async function build_server(options, client) {
 
 			exports.push(
 				`export const component = async () => (await import('../${
-					vite_manifest[node.component].file
+					resolve_symlinks(vite_manifest, node.component).chunk.file
 				}')).default;`,
 				`export const file = '${entry.file}';` // TODO what is this?
 			);
diff --git a/packages/kit/src/exports/vite/build/utils.js b/packages/kit/src/exports/vite/build/utils.js
index 4a0e19e4a..da3134c31 100644
--- a/packages/kit/src/exports/vite/build/utils.js
+++ b/packages/kit/src/exports/vite/build/utils.js
@@ -1,3 +1,5 @@
+import fs from 'fs';
+import path from 'path';
 import * as vite from 'vite';
 import { get_aliases } from '../utils.js';
 
@@ -44,14 +46,14 @@ export function find_deps(manifest, entry, add_dynamic_css) {
 	const stylesheets = new Set();
 
 	/**
-	 * @param {string} file
+	 * @param {string} current
 	 * @param {boolean} add_js
 	 */
-	function traverse(file, add_js) {
-		if (seen.has(file)) return;
-		seen.add(file);
+	function traverse(current, add_js) {
+		if (seen.has(current)) return;
+		seen.add(current);
 
-		const chunk = manifest[file];
+		const { chunk } = resolve_symlinks(manifest, current);
 
 		if (add_js) imports.add(chunk.file);
 
@@ -68,15 +70,31 @@ export function find_deps(manifest, entry, add_dynamic_css) {
 		}
 	}
 
-	traverse(entry, true);
+	const { chunk, file } = resolve_symlinks(manifest, entry);
+
+	traverse(file, true);
 
 	return {
-		file: manifest[entry].file,
+		file: chunk.file,
 		imports: Array.from(imports),
 		stylesheets: Array.from(stylesheets)
 	};
 }
 
+/**
+ * @param {import('vite').Manifest} manifest
+ * @param {string} file
+ */
+export function resolve_symlinks(manifest, file) {
+	while (!manifest[file]) {
+		file = path.relative('.', fs.realpathSync(file));
+	}
+
+	const chunk = manifest[file];
+
+	return { chunk, file };
+}
+
 /**
  * The Vite configuration that we use by default.
  * @param {{
diff --git a/packages/package/CHANGELOG.md b/packages/package/CHANGELOG.md
index 0fbb8b088..2d6c7cb57 100644
--- a/packages/package/CHANGELOG.md
+++ b/packages/package/CHANGELOG.md
@@ -1,5 +1,11 @@
 # @sveltejs/package
 
+## 1.0.0-next.5
+
+### Patch Changes
+
+- fix check for undefined on application/ strip ([#6932](https://github.com/sveltejs/kit/pull/6932))
+
 ## 1.0.0-next.4
 
 ### Patch Changes
diff --git a/packages/package/package.json b/packages/package/package.json
index b5bf86863..731fa5ec7 100644
--- a/packages/package/package.json
+++ b/packages/package/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "@sveltejs/package",
-	"version": "1.0.0-next.4",
+	"version": "1.0.0-next.5",
 	"repository": {
 		"type": "git",
 		"url": "https://github.com/sveltejs/kit",
diff --git a/packages/package/src/utils.js b/packages/package/src/utils.js
index 0b263857b..001970610 100644
--- a/packages/package/src/utils.js
+++ b/packages/package/src/utils.js
@@ -52,7 +52,7 @@ export function strip_lang_tags(content) {
 		.replace(
 			/(<!--[^]*?-->)|(<script[^>]*?)\s(?:type|lang)=(["'])(.*?)\3/g,
 			// things like application/ld+json should be kept as-is. Preprocessed languages are "ts" etc
-			(match, s1, s2, _, s4) => (s4.startsWith('application/') ? match : (s1 ?? '') + (s2 ?? ''))
+			(match, s1, s2, _, s4) => (s4?.startsWith('application/') ? match : (s1 ?? '') + (s2 ?? ''))
 		)
 		.replace(/(<!--[^]*?-->)|(<style[^>]*?)\s(?:type|lang)=(["']).*?\3/g, '$1$2');
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4f29e6486..f1a309a23 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -114,11 +114,12 @@ importers:
 
   packages/adapter-node:
     specifiers:
+      '@rollup/plugin-commonjs': ^22.0.1
       '@rollup/plugin-json': ^4.1.0
+      '@rollup/plugin-node-resolve': ^14.1.0
       '@sveltejs/kit': workspace:*
       '@types/node': ^16.11.36
       c8: ^7.11.3
-      esbuild: ^0.15.7
       node-fetch: ^3.2.4
       polka: ^1.0.0-next.22
       rimraf: ^3.0.2
@@ -127,16 +128,17 @@ importers:
       typescript: ^4.8.2
       uvu: ^0.5.3
     dependencies:
-      esbuild: 0.15.7
-    devDependencies:
+      '@rollup/plugin-commonjs': 22.0.1_rollup@2.78.1
       '@rollup/plugin-json': 4.1.0_rollup@2.78.1
+      '@rollup/plugin-node-resolve': 14.1.0_rollup@2.78.1
+      rollup: 2.78.1
+    devDependencies:
       '@sveltejs/kit': link:../kit
       '@types/node': 16.11.42
       c8: 7.11.3
       node-fetch: 3.2.6
       polka: 1.0.0-next.22
       rimraf: 3.0.2
-      rollup: 2.78.1
       sirv: 2.0.2
       typescript: 4.8.2
       uvu: 0.5.4
@@ -1085,9 +1087,8 @@ packages:
       glob: 7.2.3
       is-reference: 1.2.1
       magic-string: 0.25.9
-      resolve: 1.22.0
+      resolve: 1.22.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/plugin-json/4.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==}
@@ -1096,7 +1097,6 @@ packages:
     dependencies:
       '@rollup/pluginutils': 3.1.0_rollup@2.78.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/plugin-node-resolve/14.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==}
@@ -1111,7 +1111,6 @@ packages:
       is-module: 1.0.0
       resolve: 1.22.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/pluginutils/3.1.0_rollup@2.78.1:
     resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
@@ -1123,7 +1122,6 @@ packages:
       estree-walker: 1.0.1
       picomatch: 2.3.1
       rollup: 2.78.1
-    dev: true
 
   /@rollup/pluginutils/4.2.1:
     resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
@@ -1183,11 +1181,9 @@ packages:
 
   /@types/estree/0.0.39:
     resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
-    dev: true
 
   /@types/estree/0.0.52:
     resolution: {integrity: sha512-BZWrtCU0bMVAIliIV+HJO1f1PR41M7NKjfxrFJwwhKI1KwhwOxYw1SXg9ao+CIMt774nFuGiG6eU+udtbEI9oQ==}
-    dev: true
 
   /@types/gitignore-parser/0.0.0:
     resolution: {integrity: sha512-qxOKILdhl4e639fWdkMySS4tBkRYHkrU2ZNScsMu84EPicliFRr+gAXCLPrs7kTFWdDpgAIlxtUr+YCRtVjsKw==}
@@ -1229,7 +1225,6 @@ packages:
 
   /@types/node/18.0.0:
     resolution: {integrity: sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==}
-    dev: true
 
   /@types/normalize-package-data/2.4.1:
     resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@@ -1253,7 +1248,6 @@ packages:
     resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
     dependencies:
       '@types/node': 18.0.0
-    dev: true
 
   /@types/sade/1.7.4:
     resolution: {integrity: sha512-6ys13kmtlY0aIOz4KtMdeBD9BHs6vSE3aRcj4vAZqXjypT2el8WZt6799CMjElVgh1cbOH/t3vrpQ4IpwytcPA==}
@@ -1504,7 +1498,6 @@ packages:
   /builtin-modules/3.3.0:
     resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
     engines: {node: '>=6'}
-    dev: true
 
   /c8/7.11.3:
     resolution: {integrity: sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==}
@@ -1693,7 +1686,6 @@ packages:
 
   /commondir/1.0.1:
     resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
-    dev: true
 
   /concat-map/0.0.1:
     resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
@@ -2168,7 +2160,6 @@ packages:
 
   /estree-walker/1.0.1:
     resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
-    dev: true
 
   /estree-walker/2.0.2:
     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
@@ -2622,7 +2613,6 @@ packages:
     engines: {node: '>=6'}
     dependencies:
       builtin-modules: 3.3.0
-    dev: true
 
   /is-callable/1.2.4:
     resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==}
@@ -2641,12 +2631,6 @@ packages:
     dependencies:
       has: 1.0.3
 
-  /is-core-module/2.9.0:
-    resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==}
-    dependencies:
-      has: 1.0.3
-    dev: true
-
   /is-date-object/1.0.5:
     resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
     engines: {node: '>= 0.4'}
@@ -2682,7 +2666,6 @@ packages:
 
   /is-module/1.0.0:
     resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
-    dev: true
 
   /is-negative-zero/2.0.2:
     resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
@@ -2713,7 +2696,6 @@ packages:
     resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
     dependencies:
       '@types/estree': 0.0.52
-    dev: true
 
   /is-regex/1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
@@ -2922,7 +2904,6 @@ packages:
     resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
     dependencies:
       sourcemap-codec: 1.4.8
-    dev: true
 
   /magic-string/0.26.2:
     resolution: {integrity: sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==}
@@ -3658,15 +3639,6 @@ packages:
     deprecated: https://github.com/lydell/resolve-url#deprecated
     dev: true
 
-  /resolve/1.22.0:
-    resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
-    hasBin: true
-    dependencies:
-      is-core-module: 2.9.0
-      path-parse: 1.0.7
-      supports-preserve-symlinks-flag: 1.0.0
-    dev: true
-
   /resolve/1.22.1:
     resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
     hasBin: true


Test patch:
diff --git a/packages/kit/test/apps/basics/.gitignore b/packages/kit/test/apps/basics/.gitignore
index fa2f5a579..fad4d3e15 100644
--- a/packages/kit/test/apps/basics/.gitignore
+++ b/packages/kit/test/apps/basics/.gitignore
@@ -1,2 +1,3 @@
 /test/errors.json
 !/.env
+/src/routes/routing/symlink-from
\ No newline at end of file
diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json
index c3da79b25..76e9cf5b7 100644
--- a/packages/kit/test/apps/basics/package.json
+++ b/packages/kit/test/apps/basics/package.json
@@ -7,7 +7,7 @@
 		"build": "vite build",
 		"preview": "vite preview",
 		"check": "svelte-kit sync && tsc && svelte-check",
-		"test": "npm run test:dev && npm run test:build",
+		"test": "node test/setup.js && npm run test:dev && npm run test:build",
 		"test:dev": "rimraf test/errors.json && cross-env DEV=true playwright test",
 		"test:build": "rimraf test/errors.json && playwright test"
 	},
diff --git a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte
index 61f62ec6f..1d300bf63 100644
--- a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte
+++ b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte
@@ -6,6 +6,7 @@
 
 <a href="/routing/a">a</a>
 <a href="/routing/ambiguous/ok.json" rel="external">ok</a>
+<a href="/routing/symlink-from">symlinked</a>
 <a href="http://localhost:{$page.url.searchParams.get('port')}">elsewhere</a>
 <a href="/static.json">static.json</a>
 
diff --git a/packages/kit/test/apps/basics/src/routes/routing/symlink-to/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/symlink-to/+page.svelte
new file mode 100644
index 000000000..d80b82ddf
--- /dev/null
+++ b/packages/kit/test/apps/basics/src/routes/routing/symlink-to/+page.svelte
@@ -0,0 +1,1 @@
+<h1>symlinked</h1>
diff --git a/packages/kit/test/apps/basics/test/setup.js b/packages/kit/test/apps/basics/test/setup.js
new file mode 100644
index 000000000..9be580053
--- /dev/null
+++ b/packages/kit/test/apps/basics/test/setup.js
@@ -0,0 +1,7 @@
+import fs from 'fs';
+
+if (process.platform !== 'win32') {
+	process.chdir('src/routes/routing');
+	fs.rmSync('symlink-from', { recursive: true, force: true });
+	fs.symlinkSync('symlink-to', 'symlink-from', 'dir');
+}
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index 1ce41289c..e63236b8b 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -1639,6 +1639,15 @@ test.describe('Routing', () => {
 		expect(await page.textContent('h1')).toBe('404');
 		expect(await page.textContent('p')).toBe('This is your custom error page saying: "Not Found"');
 	});
+
+	if (process.platform !== 'win32') {
+		test('Respects symlinks', async ({ page, clicknav }) => {
+			await page.goto('/routing');
+			await clicknav('[href="/routing/symlink-from"]');
+
+			expect(await page.textContent('h1')).toBe('symlinked');
+		});
+	}
 });
 
 test.describe('Matchers', () => {