Repository: sveltejs/kit (js)

Issue:
`data-sveltekit-preload-code` not working with static adapter and custom base path
### Describe the bug

The `data-sveltekit-preload-code` attribute doesn't work on links when built with the static adapter and a custom base path.

### Reproduction

Example repo: https://github.com/cnanney/sv-preload-code

I started from a fresh `npm create svelte@latest`, and configured for static output on GitHub Pages, following example on https://kit.svelte.dev/docs/adapter-static#github-pages.

This demo app has a simple page with 6 links each nested in a single `div`, with varying combinations of setting the preload attribute on the link itself and its parent:

https://github.com/cnanney/sv-preload-code/blob/ebfdd82c7c644c1256f803e6d01806818376c29f/src/routes/%2Bpage.svelte#L9-L26

When ran locally via `dev`, all 6 links will trigger a preload on hover. But on `build && preview`, links with only `data-sveltekit-preload-code` (numbers 3 and 6) will not trigger.

You can see the issue here: https://cnanney.github.io/sv-preload-code/

### Logs

_No response_

### System Info

```Shell
System:
    OS: Linux 5.15 Ubuntu 18.04.2 LTS (Bionic Beaver)
    CPU: (12) x64 AMD Ryzen 5 3600X 6-Core Processor
    Memory: 13.12 GB / 15.59 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 16.19.0 - ~/.nvm/versions/node/v16.19.0/bin/node
    npm: 8.19.3 - ~/.nvm/versions/node/v16.19.0/bin/npm
  npmPackages:
    @sveltejs/adapter-auto: ^1.0.0 => 1.0.2
    @sveltejs/adapter-static: ^1.0.5 => 1.0.5
    @sveltejs/kit: ^1.0.0 => 1.3.1
    svelte: ^3.54.0 => 3.55.1
    vite: ^4.0.0 => 4.0.4
```


### Severity

Minor (can still use `preload-data` until fixed)

### Additional Information

I saw in the docs that `data-sveltekit-preload-data` inherently has to `preload-code` as well, so nesting the two for a single link is pointless, but I wanted to verify all possible interactions in the test.

Pull request description:
fix: take base path into account when preloading code
fixes #8747

### 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
- [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. Changesets that add features should be `minor` and those that fix bugs should be `patch`. Please prefix changeset messages with `feat:`, `fix:`, or `chore:`.


Patch:
diff --git a/.changeset/chilly-hats-wait.md b/.changeset/chilly-hats-wait.md
new file mode 100644
index 000000000..c89407c1e
--- /dev/null
+++ b/.changeset/chilly-hats-wait.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: take base path into account when preloading code
diff --git a/documentation/docs/20-core-concepts/20-load.md b/documentation/docs/20-core-concepts/20-load.md
index b1e80fb15..7095cc22f 100644
--- a/documentation/docs/20-core-concepts/20-load.md
+++ b/documentation/docs/20-core-concepts/20-load.md
@@ -415,6 +415,8 @@ export function load({ locals }) {
 }
 ```
 
+> Make sure you're not catching the thrown redirect, which results in a noop.
+
 ## Promise unwrapping
 
 Top-level promises will be awaited, which makes it easy to return multiple promises without creating a waterfall:
diff --git a/package.json b/package.json
index c4f878da5..6dd9a7d7e 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
 		"tiny-glob": "^0.2.9",
 		"typescript": "^4.9.4"
 	},
-	"packageManager": "pnpm@7.26.0",
+	"packageManager": "pnpm@7.26.1",
 	"engines": {
 		"pnpm": "^7.0.0"
 	},
diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js
index dbe070aa3..e74085ab3 100644
--- a/packages/kit/src/runtime/client/client.js
+++ b/packages/kit/src/runtime/client/client.js
@@ -984,7 +984,7 @@ export function create_client({ target, base }) {
 	function get_navigation_intent(url, invalidating) {
 		if (is_external_url(url, base)) return;
 
-		const path = decode_pathname(url.pathname.slice(base.length) || '/');
+		const path = get_url_path(url);
 
 		for (const route of routes) {
 			const params = route.exec(path);
@@ -998,6 +998,11 @@ export function create_client({ target, base }) {
 		}
 	}
 
+	/** @param {URL} url */
+	function get_url_path(url) {
+		return decode_pathname(url.pathname.slice(base.length) || '/');
+	}
+
 	/**
 	 * @param {{
 	 *   url: URL;
@@ -1175,7 +1180,9 @@ export function create_client({ target, base }) {
 			(entries) => {
 				for (const entry of entries) {
 					if (entry.isIntersecting) {
-						preload_code(new URL(/** @type {HTMLAnchorElement} */ (entry.target).href).pathname);
+						preload_code(
+							get_url_path(new URL(/** @type {HTMLAnchorElement} */ (entry.target).href))
+						);
 						observer.unobserve(entry.target);
 					}
 				}
@@ -1200,7 +1207,7 @@ export function create_client({ target, base }) {
 				if (priority <= options.preload_data) {
 					preload_data(/** @type {URL} */ (url));
 				} else if (priority <= options.preload_code) {
-					preload_code(/** @type {URL} */ (url).pathname);
+					preload_code(get_url_path(/** @type {URL} */ (url)));
 				}
 			}
 		}
@@ -1220,7 +1227,7 @@ export function create_client({ target, base }) {
 				}
 
 				if (options.preload_code === PRELOAD_PRIORITIES.eager) {
-					preload_code(/** @type {URL} */ (url).pathname);
+					preload_code(get_url_path(/** @type {URL} */ (url)));
 				}
 			}
 		}
diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts
index 4d0f5823e..d7f0fb599 100644
--- a/packages/kit/types/index.d.ts
+++ b/packages/kit/types/index.d.ts
@@ -1087,7 +1087,8 @@ export type ActionResult<
 /**
  * Creates an `HttpError` object with an HTTP status code and an optional message.
  * This object, if thrown during request handling, will cause SvelteKit to
- * return an error response without invoking `handleError`
+ * return an error response without invoking `handleError`.
+ * Make sure you're not catching the thrown error, which results in a noop.
  * @param status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
  * @param body An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
  */
@@ -1110,6 +1111,7 @@ export interface HttpError {
 
 /**
  * Create a `Redirect` object. If thrown during request handling, SvelteKit will return a redirect response.
+ * Make sure you're not catching the thrown redirect, which results in a noop.
  * @param status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). Must be in the range 300-308.
  * @param location The location to redirect to.
  */


Test patch:
diff --git a/packages/kit/test/apps/options/source/pages/preloading/+page.svelte b/packages/kit/test/apps/options/source/pages/preloading/+page.svelte
index 10d9cdce5..81aee0ffd 100644
--- a/packages/kit/test/apps/options/source/pages/preloading/+page.svelte
+++ b/packages/kit/test/apps/options/source/pages/preloading/+page.svelte
@@ -1,1 +1,2 @@
 <a data-sveltekit-preload-data href="/path-base/preloading/preloaded">click me</a>
+<a data-sveltekit-preload-code href="/path-base/preloading/code">click me 2</a>
diff --git a/packages/kit/test/apps/options/source/pages/preloading/code/+page.svelte b/packages/kit/test/apps/options/source/pages/preloading/code/+page.svelte
new file mode 100644
index 000000000..0e1d4dcf4
--- /dev/null
+++ b/packages/kit/test/apps/options/source/pages/preloading/code/+page.svelte
@@ -0,0 +1,1 @@
+<h1>Should preload my code</h1>
diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js
index c79e42758..026d847f4 100644
--- a/packages/kit/test/apps/options/test/test.js
+++ b/packages/kit/test/apps/options/test/test.js
@@ -242,6 +242,33 @@ test.describe('trailingSlash', () => {
 		await app.goto('/path-base/preloading/preloaded');
 		expect(requests).toEqual([]);
 	});
+
+	test('accounts for base path when running data-sveltekit-preload-code', async ({
+		page,
+		javaScriptEnabled
+	}) => {
+		if (!javaScriptEnabled) return;
+
+		await page.goto('/path-base/preloading');
+
+		/** @type {string[]} */
+		let requests = [];
+		page.on('request', (r) => requests.push(new URL(r.url()).pathname));
+
+		await page.hover('a[href="/path-base/preloading/code"]');
+		await page.waitForTimeout(100);
+
+		// svelte request made is environment dependent
+		if (process.env.DEV) {
+			expect(requests.filter((req) => req.endsWith('.svelte')).length).toBe(1);
+		} else {
+			expect(requests.filter((req) => req.endsWith('.js')).length).toBeGreaterThan(0);
+		}
+
+		requests = [];
+		await page.click('a[href="/path-base/preloading/code"]');
+		expect(requests).toEqual([]);
+	});
 });
 
 if (!process.env.DEV) {