Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
30ae1c7
breaking: overhaul tsconfig
Rich-Harris Jul 21, 2026
7226b17
WIP
Rich-Harris Jul 21, 2026
7562c03
fix
Rich-Harris Jul 21, 2026
7beb8f1
fix
Rich-Harris Jul 21, 2026
8ec3b4b
fix
Rich-Harris Jul 21, 2026
6af0b20
fix
Rich-Harris Jul 21, 2026
7e05269
fix
Rich-Harris Jul 21, 2026
200a1b4
fix
Rich-Harris Jul 21, 2026
8125a01
add $app/service-worker and $app/tsconfig/service-worker
Rich-Harris Jul 21, 2026
864eba3
fix
Rich-Harris Jul 22, 2026
5448b91
pacify eslint
Rich-Harris Jul 22, 2026
d20ced2
WIP
Rich-Harris Jul 22, 2026
52a091b
WIP
Rich-Harris Jul 23, 2026
9bde5cc
validation
Rich-Harris Jul 23, 2026
34785ce
WIP
Rich-Harris Jul 23, 2026
8e697bd
move
Rich-Harris Jul 23, 2026
e30e570
update tests
Rich-Harris Jul 23, 2026
42b5552
WIP
Rich-Harris Jul 23, 2026
3df2c0f
merge version-3
Rich-Harris Jul 23, 2026
456ef07
tweak
Rich-Harris Jul 23, 2026
c6be788
lint
Rich-Harris Jul 23, 2026
e77b8d5
some docs
Rich-Harris Jul 23, 2026
fc36e34
docs
Rich-Harris Jul 23, 2026
b07be7c
fixes
Rich-Harris Jul 23, 2026
a0da6b2
fucking windows
Rich-Harris Jul 23, 2026
1b80adb
deprecate typescript.config option
Rich-Harris Jul 23, 2026
5661343
Fix: Leftover WIP code in `$app/service-worker` registers an empty no…
vercel[bot] Jul 23, 2026
822e3e3
changesets
Rich-Harris Jul 23, 2026
7cbc234
Merge branch 'rethink-tsconfig' of https://github.com/sveltejs/kit in…
Rich-Harris Jul 23, 2026
8a4b4c8
Update packages/kit/CHANGELOG.md
Rich-Harris Jul 23, 2026
91e0785
fix
Rich-Harris Jul 23, 2026
a0b82d1
Merge branch 'rethink-tsconfig' of https://github.com/sveltejs/kit in…
Rich-Harris Jul 23, 2026
9a0fb38
fix playground
Rich-Harris Jul 23, 2026
831b534
add comments/descriptions
Rich-Harris Jul 24, 2026
b9a91ee
attempt to explain regexes
Rich-Harris Jul 24, 2026
99fdc90
parent -> id
Rich-Harris Jul 24, 2026
e74bfb3
inline docs
Rich-Harris Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fresh-pots-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': major
---

breaking: write tsconfig to `node_modules/$app/tsconfig`
5 changes: 5 additions & 0 deletions .changeset/moody-bags-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: `$app/service-worker` module
5 changes: 5 additions & 0 deletions .changeset/plain-jobs-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: better tsconfig validation
6 changes: 4 additions & 2 deletions documentation/docs/10-getting-started/30-project-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ my-project/
│ │ └ [your param matchers]
│ ├ routes/
│ │ └ [your routes]
│ ├ service-worker/
│ │ ├ index.js
│ │ └ tsconfig.json
│ ├ app.html
│ ├ error.html
│ ├ hooks.client.js
│ ├ hooks.server.js
│ ├ service-worker.js
│ └ instrumentation.server.js
├ static/
│ └ [your static assets]
Expand Down Expand Up @@ -52,7 +54,7 @@ The `src` directory contains the meat of your project. Everything except `src/ro
- `%sveltekit.error.message%` — the error message
- `hooks.client.js` contains your client [hooks](hooks)
- `hooks.server.js` contains your server [hooks](hooks)
- `service-worker.js` contains your [service worker](service-workers)
- `service-worker` contains your [service worker](service-workers)
- `instrumentation.server.js` contains your [observability](observability) setup and instrumentation code
- Requires adapter support. If your adapter supports it, it is guaranteed to run prior to loading and running your application code.

Expand Down
7 changes: 7 additions & 0 deletions documentation/docs/98-reference/20-$app-service-worker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: $app/service-worker
---

This module can only be imported in service workers.

> MODULE: $app/service-worker
14 changes: 14 additions & 0 deletions documentation/docs/98-reference/20-$app-tsconfig-service-worker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: $app/tsconfig/service-worker
---

This module contains TypeScript configuration tailored for your service worker:

```json
/// file: src/service-worker/tsconfig.json
{
"extends": "$app/tsconfig/service-worker"
}
```

You can extend this configuration with your own `compilerOptions`, adhering to the same restrictions as [`$app/tsconfig`]($app-tsconfig).
23 changes: 23 additions & 0 deletions documentation/docs/98-reference/20-$app-tsconfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: $app/tsconfig
---

This module contains TypeScript configuration tailored for your app. Your own config should extend it — a typical `tsconfig.json` looks like this:

```json
/// file: tsconfig.json
{
"extends": "$app/tsconfig",
"includes": ["src", "test"],
"excludes": ["src/service-worker"]
}
```

You can extend this configuration with your own `compilerOptions`. Overriding the following properties may cause things to break — SvelteKit will warn you if this happens:

- `paths` — this is derived from the (deprecated) [`alias`](configuration#alias) config option, together with any [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) specified in your `package.json`, to align behaviour between Vite and TypeScript. Ideally, configure subpath imports rather than using `paths` directly
- `types` — your app needs to be able to 'see' generated module declarations for things like [environment variables](environment-variables), and as such this array must include `"$app/types"`
- `isolatedModules` — must be `true`, as Vite compiles modules one at a time
- `verbatimModuleSyntax` — must be `true`, so that you can safely use type imports in `.svelte` files

Note that the example configuration above excludes `src/service-worker`, because service workers need to be in their own TypeScript project. If you are using a service worker, create a `src/service-worker/tsconfig.json` that extends [`$app/tsconfig/service-worker`]($app-tsconfig-service-worker).
75 changes: 2 additions & 73 deletions documentation/docs/98-reference/54-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,80 +119,9 @@ Starting with version 2.16.0, two additional helper types are provided: `PagePro
> </script>
> ```
> [!NOTE] For this to work, your own `tsconfig.json` or `jsconfig.json` should extend from the generated `.svelte-kit/tsconfig.json` (where `.svelte-kit` is your [`outDir`](configuration#outDir)):
> [!NOTE] For this to work, your own `tsconfig.json` or `jsconfig.json` should extend from the generated `$app/types`:
>
> `{ "extends": "./.svelte-kit/tsconfig.json" }`
### Default tsconfig.json
The generated `.svelte-kit/tsconfig.json` file contains a mixture of options. Some are generated programmatically based on your project configuration, and should generally not be overridden without good reason:
```json
/// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
"paths": {
"#lib": ["../src/lib/index.js"],
"#lib/*": ["../src/lib/*"]
},
"rootDirs": ["..", "./types"]
},
"include": [
"ambient.d.ts",
"non-ambient.d.ts",
"./types/**/$types.d.ts",
"../vite.config.js",
"../vite.config.ts",
"../src/**/*.js",
"../src/**/*.ts",
"../src/**/*.svelte",
"../tests/**/*.js",
"../tests/**/*.ts",
"../tests/**/*.svelte"
],
"exclude": [
"../node_modules/**",
"../src/service-worker.js",
"../src/service-worker/**/*.js",
"../src/service-worker.ts",
"../src/service-worker/**/*.ts",
"../src/service-worker.d.ts",
"../src/service-worker/**/*.d.ts"
]
}
```
Others are required for SvelteKit to work properly, and should also be left untouched unless you know what you're doing:

```json
/// file: .svelte-kit/tsconfig.json
{
"compilerOptions": {
// this ensures that types are explicitly
// imported with `import type`, which is
// necessary as Svelte/Vite cannot
// otherwise compile components correctly
"verbatimModuleSyntax": true,

// Vite compiles one TypeScript module
// at a time, rather than compiling
// the entire module graph
"isolatedModules": true,

// Tell TS it's used only for type-checking
"noEmit": true,

// This ensures both `vite build`
// and `svelte-package` work correctly
"lib": ["esnext", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"module": "esnext",
"target": "esnext"
}
}
```

Use the [`typescript.config` setting](configuration#typescript) of the SvelteKit plugin in `vite.config.js` to extend or modify the generated `tsconfig.json`.
> `{ "extends": "$app/tsconfig" }`
## app.d.ts
Expand Down
4 changes: 3 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ export default [
{
languageOptions: {
parserOptions: {
projectService: true
projectService: {
allowDefaultProject: ['packages/kit/src/runtime/app/service-worker/index.js']
}
}
},
rules: {
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-cloudflare/test/apps/pages/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
2 changes: 1 addition & 1 deletion packages/adapter-netlify/test/apps/basic/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
2 changes: 1 addition & 1 deletion packages/adapter-netlify/test/apps/edge/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"strict": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
2 changes: 1 addition & 1 deletion packages/adapter-netlify/test/apps/split/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
2 changes: 1 addition & 1 deletion packages/adapter-node/test/apps/basic/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"sourceMap": true,
"moduleResolution": "bundler"
},
"extends": "./.svelte-kit/tsconfig.json"
"extends": "$app/tsconfig"
}
2 changes: 1 addition & 1 deletion packages/adapter-static/test/apps/spa/jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"extends": "$app/tsconfig",
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
}
2 changes: 1 addition & 1 deletion packages/adapter-vercel/test/apps/basic/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"extends": "$app/tsconfig",
"compilerOptions": {
"rewriteRelativeImportExtensions": true,
"allowJs": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/enhanced-img/test/apps/basics/jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"extends": "$app/tsconfig",
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte", "*.js", "test/*.js"]
}
14 changes: 12 additions & 2 deletions packages/kit/scripts/generate-dts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createBundle } from 'dts-buddy';
import { readFileSync } from 'node:fs';
import { readFileSync, writeFileSync } from 'node:fs';

await createBundle({
output: 'types/index.d.ts',
Expand All @@ -14,6 +14,7 @@ await createBundle({
'$app/navigation': 'src/runtime/app/navigation.js',
'$app/paths': 'src/runtime/app/paths/public.d.ts',
'$app/server': 'src/runtime/app/server/index.js',
'$app/service-worker': 'src/runtime/app/service-worker/index.js',
'$app/state': 'src/runtime/app/state/index.js'
},
include: ['src'],
Expand All @@ -24,10 +25,19 @@ await createBundle({
});

// dts-buddy doesn't inline imports of module declaration in ambient-private.d.ts but also doesn't include them, resulting in broken types - guard against that
const types = readFileSync('./types/index.d.ts', 'utf-8');
let types = readFileSync('types/index.d.ts', 'utf-8');

if (types.includes('__sveltekit/')) {
throw new Error(
'Found __sveltekit/ in types/index.d.ts - make sure to hide internal modules by not just reexporting them. Contents:\n\n' +
types
);
}

// this line causes type-checking to fail — simplest fix is to ignore it
types = types.replace(
'export const self: ServiceWorkerGlobalScope;',
'// @ts-ignore\n\texport const self: ServiceWorkerGlobalScope;'
Comment thread
Rich-Harris marked this conversation as resolved.
);

writeFileSync('types/index.d.ts', types);
16 changes: 8 additions & 8 deletions packages/kit/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ if (!command) {
}

if (command === 'sync') {
// create placeholder .svelte-kit/tsconfig.json if necessary, to squelch warnings.
// create placeholder node_modules/$app/tsconfig/tsconfig.json if necessary, to squelch warnings.
// this isn't bulletproof — if someone has some esoteric config, it will continue
// to harmlessly warn — but we handle the 90% case and clean up after ourselves
const sveltekit_dir = '.svelte-kit';
const base_tsconfig = `${sveltekit_dir}/tsconfig.json`;
const dir = 'node_modules/$app/tsconfig';
const base_tsconfig = `${dir}/tsconfig.json`;
const base_tsconfig_json = '{}';

const sveltekit_dir_exists = fs.existsSync(sveltekit_dir);
const sveltekit_dir_exists = fs.existsSync(dir);
const base_tsconfig_exists = fs.existsSync(base_tsconfig);

if (!base_tsconfig_exists) {
try {
fs.mkdirSync('.svelte-kit');
fs.mkdirSync(dir, { recursive: true });
} catch {
// ignore
}
Expand All @@ -100,7 +100,7 @@ if (command === 'sync') {
const sveltekit_config = extract_svelte_config(vite_config);

const sync = await import('./core/sync/sync.js');
sync.all_types(sveltekit_config);
sync.all_types(sveltekit_config, vite_config.root);

const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config.kit);
await sync.env(sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
Expand All @@ -113,8 +113,8 @@ if (command === 'sync') {
fs.unlinkSync(base_tsconfig);
}

if (!sveltekit_dir_exists && fs.readdirSync(sveltekit_dir).length === 0) {
fs.rmSync(sveltekit_dir, { recursive: true });
if (!sveltekit_dir_exists && fs.readdirSync(dir).length === 0) {
fs.rmSync(dir, { recursive: true });
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
export const SVELTE_KIT_ASSETS = '/_svelte_kit_assets';

export const GENERATED_COMMENT = '// this file is generated — do not edit it\n';
export const GENERATED_COMMENT = '// this file is generated — do not edit it';

export const ENDPOINT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];

Expand Down
11 changes: 8 additions & 3 deletions packages/kit/src/core/config/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,14 @@ export const validate_kit_options = object({
server: boolean(false)
}),

typescript: object({
config: fun((config) => config)
}),
typescript: deprecate(
object({
config: fun((config) => config)
}),
(keypath) => {
return `The \`${keypath}\` option is deprecated, and will be removed in a future version. Add configuration to tsconfig.json directly`;
}
),

version: object({
name: string(Date.now().toString()),
Expand Down
Loading
Loading