Skip to content

Commit 19a9597

Browse files
dominikgeltigerchinobenmccann
authored
feat: Support svelte.config.ts (#13935)
Co-authored-by: Tee Ming <[email protected]> Co-authored-by: Ben McCann <[email protected]>
1 parent 06e1d2c commit 19a9597

File tree

27 files changed

+185
-22
lines changed

27 files changed

+185
-22
lines changed

.changeset/twenty-pants-fetch.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@sveltejs/package': minor
3+
'@sveltejs/kit': minor
4+
---
5+
6+
feat: support svelte.config.ts
7+
8+
> **NOTE**
9+
>
10+
> Your runtime has to support importing TypeScript files for `svelte.config.ts` to work.
11+
> In Node.js, the feature is supported with the `--experimental-strip-types` flag starting in Node 22.6.0 and supported without a flag starting in Node 23.6.0.

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ jobs:
7474
- run: pnpm playwright install ${{ matrix.e2e-browser }}
7575
- run: pnpm run sync-all
7676
- run: pnpm test:kit
77+
env:
78+
NODE_OPTIONS: ${{matrix.node-version == 22 && '--experimental-strip-types' || ''}} # allows loading svelte.config.ts
7779
- name: Print flaky test report
7880
run: node scripts/print-flaky-test-report.js
7981
- name: Archive test results
@@ -181,14 +183,19 @@ jobs:
181183
path: test-results-server-side-route-resolution-${{ matrix.mode }}.tar.gz
182184
test-others:
183185
runs-on: ubuntu-latest
186+
strategy:
187+
matrix:
188+
node-version: [18, 20, 22, 24]
184189
steps:
185190
- uses: actions/checkout@v4
186191
- uses: pnpm/[email protected]
187192
- uses: actions/setup-node@v4
188193
with:
189-
node-version: 18
194+
node-version: ${{matrix.node-version}}
190195
cache: pnpm
191196
- run: pnpm install --frozen-lockfile
192197
- run: pnpm playwright install chromium
193198
- run: cd packages/kit && pnpm prepublishOnly
194199
- run: pnpm run test:others
200+
env:
201+
NODE_OPTIONS: ${{matrix.node-version == 22 && '--experimental-strip-types' || ''}} # allows loading svelte.config.ts

eslint.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ export default [
1414
'**/test-results',
1515
'**/build',
1616
'**/.custom-out-dir',
17-
'packages/adapter-*/files'
17+
'packages/adapter-*/files',
18+
'packages/kit/src/core/config/fixtures/multiple', // dir contains svelte config with multiple extensions tripping eslint
19+
'packages/package/test/fixtures/typescript-svelte-config/expected'
1820
]
1921
},
2022
{

packages/kit/src/cli.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import fs from 'node:fs';
2-
import path from 'node:path';
32
import process from 'node:process';
43
import colors from 'kleur';
54
import sade from 'sade';
@@ -28,8 +27,11 @@ prog
2827
.describe('Synchronise generated type definitions')
2928
.option('--mode', 'Specify a mode for loading environment variables', 'development')
3029
.action(async ({ mode }) => {
31-
if (!fs.existsSync('svelte.config.js')) {
32-
console.warn(`Missing ${path.resolve('svelte.config.js')} — skipping`);
30+
const config_files = ['js', 'ts']
31+
.map((ext) => `svelte.config.${ext}`)
32+
.filter((f) => fs.existsSync(f));
33+
if (config_files.length === 0) {
34+
console.warn(`Missing Svelte config file in ${process.cwd()} — skipping`);
3335
return;
3436
}
3537

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default {};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// invalid export is on purpose to ensure that this file is not preferred over svelte.config.js
2+
export default 'invalid';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default {};

packages/kit/src/core/config/index.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,24 @@ export function load_error_page(config) {
5757
}
5858

5959
/**
60-
* Loads and validates svelte.config.js
60+
* Loads and validates Svelte config file
6161
* @param {{ cwd?: string }} options
6262
* @returns {Promise<import('types').ValidatedConfig>}
6363
*/
6464
export async function load_config({ cwd = process.cwd() } = {}) {
65-
const config_file = path.join(cwd, 'svelte.config.js');
65+
const config_files = ['js', 'ts']
66+
.map((ext) => path.join(cwd, `svelte.config.${ext}`))
67+
.filter((f) => fs.existsSync(f));
6668

67-
if (!fs.existsSync(config_file)) {
69+
if (config_files.length === 0) {
6870
return process_config({}, { cwd });
6971
}
70-
72+
const config_file = config_files[0];
73+
if (config_files.length > 1) {
74+
console.log(
75+
`Found multiple Svelte config files in ${cwd}: ${config_files.map((f) => path.basename(f)).join(', ')}. Using ${path.basename(config_file)}`
76+
);
77+
}
7178
const config = await import(`${url.pathToFileURL(config_file).href}?ts=${Date.now()}`);
7279

7380
try {
@@ -76,7 +83,7 @@ export async function load_config({ cwd = process.cwd() } = {}) {
7683
const error = /** @type {Error} */ (e);
7784

7885
// redact the stack trace — it's not helpful to users
79-
error.stack = `Could not load svelte.config.js: ${error.message}\n`;
86+
error.stack = `Could not load ${config_file}: ${error.message}\n`;
8087
throw error;
8188
}
8289
}
@@ -111,7 +118,7 @@ function process_config(config, { cwd = process.cwd() } = {}) {
111118
export function validate_config(config) {
112119
if (typeof config !== 'object') {
113120
throw new Error(
114-
'svelte.config.js must have a configuration object as its default export. See https://svelte.dev/docs/kit/configuration'
121+
'The Svelte config file must have a configuration object as its default export. See https://svelte.dev/docs/kit/configuration'
115122
);
116123
}
117124

packages/kit/src/core/config/index.spec.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,30 @@ test('load default config (esm)', async () => {
365365
expect(config).toEqual(defaults);
366366
});
367367

368+
test('load default config (esm) with .ts extensions', async () => {
369+
const cwd = join(__dirname, 'fixtures/typescript');
370+
371+
const config = await load_config({ cwd });
372+
remove_keys(config, ([, v]) => typeof v === 'function');
373+
374+
const defaults = get_defaults(cwd + '/');
375+
defaults.kit.version.name = config.kit.version.name;
376+
377+
expect(config).toEqual(defaults);
378+
});
379+
380+
test('load .js config when both .js and .ts configs are present', async () => {
381+
const cwd = join(__dirname, 'fixtures/multiple');
382+
383+
const config = await load_config({ cwd });
384+
remove_keys(config, ([, v]) => typeof v === 'function');
385+
386+
const defaults = get_defaults(cwd + '/');
387+
defaults.kit.version.name = config.kit.version.name;
388+
389+
expect(config).toEqual(defaults);
390+
});
391+
368392
test('errors on loading config with incorrect default export', async () => {
369393
let message = null;
370394

@@ -377,6 +401,6 @@ test('errors on loading config with incorrect default export', async () => {
377401

378402
assert.equal(
379403
message,
380-
'svelte.config.js must have a configuration object as its default export. See https://svelte.dev/docs/kit/configuration'
404+
'The Svelte config file must have a configuration object as its default export. See https://svelte.dev/docs/kit/configuration'
381405
);
382406
});

packages/kit/src/core/sync/create_manifest_data/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
361361
const root = routes[0];
362362
if (!root.leaf && !root.error && !root.layout && !root.endpoint) {
363363
throw new Error(
364-
'No routes found. If you are using a custom src/routes directory, make sure it is specified in svelte.config.js'
364+
'No routes found. If you are using a custom src/routes directory, make sure it is specified in your Svelte config file'
365365
);
366366
}
367367
}

0 commit comments

Comments
 (0)