Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generated tsconfig.json #4118

Merged
merged 11 commits into from
Feb 28, 2022
6 changes: 6 additions & 0 deletions .changeset/silver-horses-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'create-svelte': patch
'@sveltejs/kit': patch
---

Extend user tsconfig from generated .svelte-kit/tsconfig.json
benmccann marked this conversation as resolved.
Show resolved Hide resolved
35 changes: 1 addition & 34 deletions packages/create-svelte/shared/+typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,36 +1,3 @@
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"lib": ["es2020", "DOM"],
"target": "es2020",
/**
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
to enforce using \`import type\` instead of \`import\` for Types.
*/
"importsNotUsedAsValues": "error",
/**
TypeScript doesn't know about import usages in the template because it only sees the
script of a Svelte file. Therefore preserve all value imports. Requires TS 4.5 or higher.
*/
"preserveValueImports": true,
"isolatedModules": true,
"resolveJsonModule": true,
/**
To have warnings/errors of the Svelte compiler at the correct position,
enable source maps by default.
*/
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"allowJs": true,
"checkJs": true,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
"extends": "./.svelte-kit/tsconfig.json"
}
9 changes: 1 addition & 8 deletions packages/create-svelte/shared/-typescript/jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
"extends": "./.svelte-kit/tsconfig.json"
}
3 changes: 3 additions & 0 deletions packages/kit/src/core/build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { generate_manifest } from '../generate_manifest/index.js';
import { build_service_worker } from './build_service_worker.js';
import { build_client } from './build_client.js';
import { build_server } from './build_server.js';
import { generate_tsconfig } from '../tsconfig.js';

/**
* @param {import('types').ValidatedConfig} config
Expand All @@ -24,6 +25,8 @@ export async function build(config) {
rimraf(output_dir);
mkdirp(output_dir);

generate_tsconfig(config);

const options = {
cwd,
config,
Expand Down
3 changes: 3 additions & 0 deletions packages/kit/src/core/dev/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { print_config_conflicts } from '../config/index.js';
import { SVELTE_KIT } from '../constants.js';
import { copy_assets, get_aliases, runtime } from '../utils.js';
import { create_plugin } from './plugin.js';
import { generate_tsconfig } from '../tsconfig.js';

/**
* @typedef {{
Expand All @@ -22,6 +23,8 @@ import { create_plugin } from './plugin.js';
export async function dev({ cwd, port, host, https, config }) {
copy_assets(`${SVELTE_KIT}/runtime`);

generate_tsconfig(config);

const [vite_config] = deep_merge(
{
server: {
Expand Down
116 changes: 116 additions & 0 deletions packages/kit/src/core/tsconfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import fs from 'fs';
import path from 'path';
import colors from 'kleur';
import { mkdirp } from '../utils/filesystem.js';
import { SVELTE_KIT } from './constants.js';

/** @param {string} file */
const exists = (file) => fs.existsSync(file) && file;

/** @param {import('types').ValidatedConfig} config */
export function generate_tsconfig(config) {
const out = path.resolve(SVELTE_KIT, 'tsconfig.json');
const user_file = exists('tsconfig.json') || exists('jsconfig.json');

if (user_file) validate(config, out, user_file);

mkdirp(SVELTE_KIT);

/** @param {string} file */
const project_relative = (file) => path.relative('.', file);

/** @param {string} file */
const config_relative = (file) => path.relative(SVELTE_KIT, file);

fs.writeFileSync(
`${SVELTE_KIT}/tsconfig.json`,
JSON.stringify(
{
compilerOptions: {
moduleResolution: 'node',
module: 'es2020',
lib: ['es2020', 'DOM'],
target: 'es2020',
// svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we worried about losing these comments in the generated tsconfig file that gets included? Does tooling generally provide a way to look at the file being extended, and do we care if that becomes less readable.

Or, another way of asking it: was the only reason for the user-visible comments so that people could know which config options not to mess with?

Also sort of relatedly: Do you foresee us potentially wanting to warn or error out if the user config does override certain essential values from the generated config?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not particularly worried about the comments. Though I do think it's probably a good idea to warn if the user specifies incompatible values (as already happens with compilerOptions.paths)

// to enforce using \`import type\` instead of \`import\` for Types.
importsNotUsedAsValues: 'error',
// TypeScript doesn't know about import usages in the template because it only sees the
// script of a Svelte file. Therefore preserve all value imports. Requires TS 4.5 or higher.
preserveValueImports: true,
isolatedModules: true,
resolveJsonModule: true,
// To have warnings/errors of the Svelte compiler at the correct position,
// enable source maps by default.
sourceMap: true,
esModuleInterop: true,
skipLibCheck: true,
forceConsistentCasingInFileNames: true,
baseUrl: config_relative('.'),
allowJs: true,
checkJs: true,
paths: {
$lib: [project_relative(config.kit.files.lib)],
'$lib/*': [project_relative(config.kit.files.lib + '/*')]
}
},
include: ['**/*.d.ts', '**/*.js', '**/*.ts', '**/*.svelte'].map(config_relative),
exclude: ['node_modules/**'].map(config_relative)
},
null,
'\t'
)
);
}

/**
* @param {import('types').ValidatedConfig} config
* @param {string} out
* @param {string} user_file
*/
function validate(config, out, user_file) {
// we have to eval the file, since it's not parseable as JSON (contains comments)
const user_tsconfig_json = fs.readFileSync(user_file, 'utf-8');
const user_tsconfig = (0, eval)(`(${user_tsconfig_json})`);

// we need to check that the user's tsconfig extends the framework config
const extend = user_tsconfig.extends;
const extends_framework_config = extend && path.resolve('.', extend) === out;

if (extends_framework_config) {
const { paths: user_paths } = user_tsconfig.compilerOptions || {};

if (user_paths) {
const lib = user_paths['$lib'] || [];
const lib_ = user_paths['$lib/*'] || [];

const missing_lib_paths =
!lib.some(
(/** @type {string} */ relative) => path.resolve('.', relative) === config.kit.files.lib
) ||
!lib_.some(
(/** @type {string} */ relative) =>
path.resolve('.', relative) === config.kit.files.lib + '/*'
);

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

console.warn(
colors
.bold()
.yellow(`Your ${user_file} should extend the configuration generated by SvelteKit:`)
);
console.warn(`{\n "extends": "${relative}"\n}`);
}
}