Skip to content

Commit

Permalink
breaking: remove baseUrl fallback from generated tsconfig (#11294)
Browse files Browse the repository at this point in the history
- don't generate baseUrl anymore and don't adjust paths anymore depending on whether or not the user has paths in their tsconfig.json
- more strict validation: warn on baseUrl/paths and suggest kit.alias instead

closes #11286
  • Loading branch information
dummdidumm authored Dec 13, 2023
1 parent 0336881 commit 0aee881
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 94 deletions.
5 changes: 5 additions & 0 deletions .changeset/dull-eyes-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": major
---

breaking: remove baseUrl fallback from generated tsconfig
5 changes: 5 additions & 0 deletions .changeset/loud-parrots-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-migrate": minor
---

feat: add sveltekit v2 migration
4 changes: 4 additions & 0 deletions documentation/docs/60-appendix/30-migrating-to-sveltekit-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ In SvelteKit 1, those properties included `form` and `data`. These were deprecat

If a form contains an `<input type="file">` but does not have an `enctype="multipart/form-data"` attribute, non-JS submissions will omit the file. SvelteKit 2 will throw an error if it encounters a form like this during a `use:enhance` submission to ensure that your forms work correctly when JavaScript is not present.

## Generated `tsconfig.json` is more strict

Previously, the generated `tsconfig.json` was trying its best to still produce a somewhat valid config when your `tsconfig.json` included `paths` or `baseUrl`. In SvelteKit 2, the validation is more strict and will warn when you use either `paths` or `baseUrl` in your `tsconfig.json`. These settings are used to generate path aliases and you should use [the `alias` config](configuration#alias) option in your `svelte.config.js` instead, to also create a corresponding alias for the bundler.

## Updated dependency requirements

SvelteKit 2 requires Node `18.13` or higher, and the following minimum dependency versions:
Expand Down
83 changes: 18 additions & 65 deletions packages/kit/src/core/sync/write_tsconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,46 +41,16 @@ export function write_tsconfig(kit, cwd = process.cwd()) {
const out = path.join(kit.outDir, 'tsconfig.json');

const user_config = load_user_tsconfig(cwd);
if (user_config) validate_user_config(kit, cwd, out, user_config);

// only specify baseUrl if a) the user doesn't specify their own baseUrl
// and b) they have non-relative paths. this causes problems with auto-imports,
// so we print a suggestion that they use relative paths instead
// TODO(v2): never include base URL, and skip the check below
let include_base_url = false;

if (user_config && !user_config.options.compilerOptions?.baseUrl) {
const non_relative_paths = new Set();
for (const paths of Object.values(user_config?.options.compilerOptions?.paths || {})) {
for (const path of paths) {
if (!path.startsWith('.')) non_relative_paths.add(path);
}
}

if (non_relative_paths.size) {
include_base_url = true;

console.log(colors.bold().yellow('Please replace non-relative compilerOptions.paths:\n'));

for (const path of non_relative_paths) {
console.log(` - "${path}" -> "./${path}"`);
}

console.log(
'\nDoing so allows us to omit "baseUrl" — which causes problems with imports — from the generated tsconfig.json. See https://github.com/sveltejs/kit/pull/8437 for more information.'
);
}
}
if (user_config) validate_user_config(cwd, out, user_config);

write_if_changed(out, JSON.stringify(get_tsconfig(kit, include_base_url), null, '\t'));
write_if_changed(out, JSON.stringify(get_tsconfig(kit), null, '\t'));
}

/**
* Generates the tsconfig that the user's tsconfig inherits from.
* @param {import('types').ValidatedKitConfig} kit
* @param {boolean} include_base_url
*/
export function get_tsconfig(kit, include_base_url) {
export function get_tsconfig(kit) {
/** @param {string} file */
const config_relative = (file) => posixify(path.relative(kit.outDir, file));

Expand Down Expand Up @@ -122,8 +92,7 @@ export function get_tsconfig(kit, include_base_url) {
const config = {
compilerOptions: {
// generated options
baseUrl: include_base_url ? config_relative('.') : undefined,
paths: get_tsconfig_paths(kit, include_base_url),
paths: get_tsconfig_paths(kit),
rootDirs: [config_relative('.'), './types'],

// essential options
Expand Down Expand Up @@ -166,12 +135,11 @@ function load_user_tsconfig(cwd) {
}

/**
* @param {import('types').ValidatedKitConfig} kit
* @param {string} cwd
* @param {string} out
* @param {{ kind: string, options: any }} config
*/
function validate_user_config(kit, cwd, out, config) {
function validate_user_config(cwd, out, config) {
// we need to check that the user's tsconfig extends the framework config
const extend = config.options.extends;
const extends_framework_config =
Expand All @@ -184,29 +152,17 @@ function validate_user_config(kit, cwd, out, config) {
const options = config.options.compilerOptions || {};

if (extends_framework_config) {
const { paths: user_paths } = options;

if (user_paths && fs.existsSync(kit.files.lib)) {
/** @type {string[]} */
const lib = user_paths['$lib'] || [];
/** @type {string[]} */
const lib_ = user_paths['$lib/*'] || [];

// TODO(v2): check needs to be adjusted when we remove the base path
const missing_lib_paths =
!lib.some((relative) => path.resolve(cwd, relative) === kit.files.lib) ||
!lib_.some((relative) => path.resolve(cwd, relative) === path.join(kit.files.lib, '/*'));

if (missing_lib_paths) {
console.warn(
colors
.bold()
.yellow(`Your compilerOptions.paths in ${config.kind} should include the following:`)
);
let relative = posixify(path.relative('.', kit.files.lib));
if (!relative.startsWith('.')) relative = `./${relative}`;
console.warn(`{\n "$lib":["${relative}"],\n "$lib/*":["${relative}/*"]\n}`);
}
const { paths, baseUrl } = options;

if (baseUrl || paths) {
console.warn(
colors
.bold()
.yellow(
`You have specified a baseUrl and/or paths in your ${config.kind} which interferes with SvelteKit's auto-generated tsconfig.json. ` +
'Remove it to avoid problems with intellisense. For path aliases, use `kit.alias` instead: https://kit.svelte.dev/docs/configuration#alias'
)
);
}
} else {
let relative = posixify(path.relative('.', out));
Expand All @@ -231,9 +187,8 @@ const value_regex = /^(.*?)((\/\*)|(\.\w+))?$/;
* Related to vite alias creation.
*
* @param {import('types').ValidatedKitConfig} config
* @param {boolean} include_base_url
*/
function get_tsconfig_paths(config, include_base_url) {
function get_tsconfig_paths(config) {
/** @param {string} file */
const config_relative = (file) => posixify(path.relative(config.outDir, file));

Expand All @@ -252,9 +207,7 @@ function get_tsconfig_paths(config, include_base_url) {
const value_match = value_regex.exec(value);
if (!value_match) throw new Error(`Invalid alias value: ${value}`);

const rel_path = (include_base_url ? project_relative : config_relative)(
remove_trailing_slashstar(value)
);
const rel_path = config_relative(remove_trailing_slashstar(value));
const slashstar = key_match[2];

if (slashstar) {
Expand Down
33 changes: 4 additions & 29 deletions packages/kit/src/core/sync/write_tsconfig.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test('Creates tsconfig path aliases from kit.alias', () => {
}
});

const { compilerOptions } = get_tsconfig(kit, false);
const { compilerOptions } = get_tsconfig(kit);

// $lib isn't part of the outcome because there's a "path exists"
// check in the implementation
Expand All @@ -27,31 +27,6 @@ test('Creates tsconfig path aliases from kit.alias', () => {
});
});

test('Creates tsconfig path aliases from kit.alias with existing baseUrl', () => {
const { kit } = validate_config({
kit: {
alias: {
simpleKey: 'simple/value',
key: 'value',
'key/*': 'some/other/value/*',
keyToFile: 'path/to/file.ts'
}
}
});

const { compilerOptions } = get_tsconfig(kit, true);

// $lib isn't part of the outcome because there's a "path exists"
// check in the implementation
expect(compilerOptions.paths).toEqual({
simpleKey: ['simple/value'],
'simpleKey/*': ['simple/value/*'],
key: ['value'],
'key/*': ['some/other/value/*'],
keyToFile: ['path/to/file.ts']
});
});

test('Allows generated tsconfig to be mutated', () => {
const { kit } = validate_config({
kit: {
Expand All @@ -63,7 +38,7 @@ test('Allows generated tsconfig to be mutated', () => {
}
});

const config = get_tsconfig(kit, false);
const config = get_tsconfig(kit);

// @ts-expect-error
assert.equal(config.extends, 'some/other/tsconfig.json');
Expand All @@ -81,7 +56,7 @@ test('Allows generated tsconfig to be replaced', () => {
}
});

const config = get_tsconfig(kit, false);
const config = get_tsconfig(kit);

// @ts-expect-error
assert.equal(config.extends, 'some/other/tsconfig.json');
Expand All @@ -96,7 +71,7 @@ test('Creates tsconfig include from kit.files', () => {
}
});

const { include } = get_tsconfig(kit, false);
const { include } = get_tsconfig(kit);

expect(include).toEqual([
'ambient.d.ts',
Expand Down
6 changes: 6 additions & 0 deletions packages/migrate/migrations/sveltekit-2/migrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ export function update_tsconfig_content(content) {
);
}

if (content.includes('"paths":') || content.includes('"baseUrl":')) {
log_migration(
'`paths` and/or `baseUrl` detected in your tsconfig.json - remove it and use `kit.alias` instead: https://kit.svelte.dev/docs/v2-migration-guide#generated-tsconfigjson-is-more-strict'
);
}

return updated;
}

Expand Down

0 comments on commit 0aee881

Please sign in to comment.