diff --git a/.changeset/tall-adults-film.md b/.changeset/tall-adults-film.md new file mode 100644 index 000000000000..647d5e91cf05 --- /dev/null +++ b/.changeset/tall-adults-film.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': major +--- + +add support for svelte.config.ts diff --git a/packages/kit/src/core/config/fixtures/typescript/svelte.config.ts b/packages/kit/src/core/config/fixtures/typescript/svelte.config.ts new file mode 100644 index 000000000000..ff8b4c56321a --- /dev/null +++ b/packages/kit/src/core/config/fixtures/typescript/svelte.config.ts @@ -0,0 +1 @@ +export default {}; diff --git a/packages/kit/src/core/config/index.js b/packages/kit/src/core/config/index.js index 7d4817fce5dc..fc2160f46d8b 100644 --- a/packages/kit/src/core/config/index.js +++ b/packages/kit/src/core/config/index.js @@ -2,6 +2,8 @@ import fs from 'node:fs'; import path from 'node:path'; import * as url from 'node:url'; import options from './options.js'; +import pkg from 'typescript'; +const { transpileModule } = pkg; /** * Loads the template (src/app.html by default) and validates that it has the @@ -56,26 +58,48 @@ export function load_error_page(config) { } /** - * Loads and validates svelte.config.js + * Loads and validates svelte.config.js or svelte.config.ts * @param {{ cwd?: string }} options * @returns {Promise} */ export async function load_config({ cwd = process.cwd() } = {}) { - const config_file = path.join(cwd, 'svelte.config.js'); + const js_config_file = path.join(cwd, 'svelte.config.js'); + const ts_config_file = path.join(cwd, 'svelte.config.ts'); - if (!fs.existsSync(config_file)) { - return process_config({}, { cwd }); + if (fs.existsSync(js_config_file)) { + const config = await import(`${url.pathToFileURL(js_config_file).href}?ts=${Date.now()}`); + return process_config(config.default, { cwd }); } - const config = await import(`${url.pathToFileURL(config_file).href}?ts=${Date.now()}`); + if (fs.existsSync(ts_config_file)) { + const config = await load_ts_config(ts_config_file); + return process_config(config.default, { cwd }); + } + + return process_config({}, { cwd }); +} +/** + * Loads and transpiles the TypeScript configuration file + * @param {string} ts_config_file + * @returns {Promise} + */ +async function load_ts_config(ts_config_file) { try { - return process_config(config.default, { cwd }); + const ts_code = fs.readFileSync(ts_config_file, 'utf-8'); + const js_code = transpileModule(ts_code, { + compilerOptions: { module: 99, target: 99 } + }).outputText; + + const config = await import( + `data:text/javascript;base64,${Buffer.from(js_code).toString('base64')}` + ); + return config; } catch (e) { const error = /** @type {Error} */ (e); // redact the stack trace — it's not helpful to users - error.stack = `Could not load svelte.config.js: ${error.message}\n`; + error.stack = `Could not load svelte.config.ts: ${error.message}\n`; throw error; } } @@ -110,7 +134,7 @@ function process_config(config, { cwd = process.cwd() } = {}) { export function validate_config(config) { if (typeof config !== 'object') { throw new Error( - 'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs/configuration' + 'svelte.config.js or svelte.config.ts must have a configuration object as its default export. See https://kit.svelte.dev/docs/configuration' ); } diff --git a/packages/kit/src/core/config/index.spec.js b/packages/kit/src/core/config/index.spec.js index e5639defc4c2..da39ae39bc48 100644 --- a/packages/kit/src/core/config/index.spec.js +++ b/packages/kit/src/core/config/index.spec.js @@ -360,6 +360,18 @@ test('load default config (esm)', async () => { expect(config).toEqual(defaults); }); +test('load default typescript config (esm)', async () => { + const cwd = join(__dirname, 'fixtures/typescript'); + + const config = await load_config({ cwd }); + remove_keys(config, ([, v]) => typeof v === 'function'); + + const defaults = get_defaults(cwd + '/'); + defaults.kit.version.name = config.kit.version.name; + + expect(config).toEqual(defaults); +}); + test('errors on loading config with incorrect default export', async () => { let message = null; @@ -372,6 +384,6 @@ test('errors on loading config with incorrect default export', async () => { assert.equal( message, - 'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs/configuration' + 'svelte.config.js or svelte.config.ts must have a configuration object as its default export. See https://kit.svelte.dev/docs/configuration' ); }); diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index e3bf549b2407..91d447e829f0 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1840,7 +1840,7 @@ declare module '@sveltejs/kit' { class Redirect_1 { constructor(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308, location: string); - status: 301 | 302 | 303 | 307 | 308 | 300 | 304 | 305 | 306; + status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308; location: string; } }