diff --git a/.changeset/real-mice-argue.md b/.changeset/real-mice-argue.md new file mode 100644 index 000000000000..9ff3147f15fd --- /dev/null +++ b/.changeset/real-mice-argue.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Add `config.kit.alias` diff --git a/documentation/docs/14-configuration.md b/documentation/docs/14-configuration.md index ac2053fcb6fc..123eb37b9539 100644 --- a/documentation/docs/14-configuration.md +++ b/documentation/docs/14-configuration.md @@ -16,6 +16,7 @@ const config = { kit: { adapter: undefined, + alias: {}, appDir: '_app', browser: { hydrate: true, @@ -91,6 +92,27 @@ export default config; Required when running `svelte-kit build` and determines how the output is converted for different platforms. See [Adapters](/docs/adapters). +### alias + +An object containing zero or more aliases used to replace values in `import` statements. These aliases are automatically passed to Vite and TypeScript. + +For example, you can add aliases to a `components` and `utils` folder: + +```js +/// file: svelte.config.js +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + alias: { + $components: 'src/components', + $utils: 'src/utils' + } + } +}; +``` + +> The built-in `$lib` alias is controlled by `config.kit.files.lib` as it is used for packaging. + ### appDir The directory relative to `paths.assets` where the built JS and CSS (and imported assets) are served from. (The filenames therein contain content-based hashes, meaning they can be cached indefinitely). Must not start or end with `/`. diff --git a/packages/kit/src/core/config/index.spec.js b/packages/kit/src/core/config/index.spec.js index 81ad6ffad2ef..597a5ecf911b 100644 --- a/packages/kit/src/core/config/index.spec.js +++ b/packages/kit/src/core/config/index.spec.js @@ -12,6 +12,7 @@ const get_defaults = (prefix = '') => ({ extensions: ['.svelte'], kit: { adapter: null, + alias: {}, amp: undefined, appDir: '_app', browser: { diff --git a/packages/kit/src/core/config/options.js b/packages/kit/src/core/config/options.js index 2286e4ab39d3..fa40b8feed5b 100644 --- a/packages/kit/src/core/config/options.js +++ b/packages/kit/src/core/config/options.js @@ -39,6 +39,18 @@ const options = object( return input; }), + alias: validate({}, (input, keypath) => { + if (typeof input !== 'object') { + throw new Error(`${keypath} should be an object`); + } + + for (const key in input) { + assert_string(input[key], `${keypath}.${key}`); + } + + return input; + }), + // TODO: remove this for the 1.0 release amp: error( (keypath) => diff --git a/packages/kit/src/core/sync/write_tsconfig.js b/packages/kit/src/core/sync/write_tsconfig.js index d231b35c3957..e35f717ed197 100644 --- a/packages/kit/src/core/sync/write_tsconfig.js +++ b/packages/kit/src/core/sync/write_tsconfig.js @@ -34,6 +34,19 @@ export function write_tsconfig(config, cwd = process.cwd()) { include.push(config_relative(`${dir}/**/*.svelte`)); }); + /** @type {Record} */ + const paths = {}; + const alias = { + $lib: project_relative(config.kit.files.lib), + ...config.kit.alias + }; + for (const [key, value] of Object.entries(alias)) { + if (fs.existsSync(project_relative(value))) { + paths[key] = [project_relative(value)]; + paths[key + '/*'] = [project_relative(value) + '/*']; + } + } + write_if_changed( out, JSON.stringify( @@ -41,12 +54,7 @@ export function write_tsconfig(config, cwd = process.cwd()) { compilerOptions: { // generated options baseUrl: config_relative('.'), - paths: fs.existsSync(config.kit.files.lib) - ? { - $lib: [project_relative(config.kit.files.lib)], - '$lib/*': [project_relative(config.kit.files.lib + '/*')] - } - : {}, + paths, rootDirs: [config_relative('.'), './types'], // essential options diff --git a/packages/kit/src/core/utils.js b/packages/kit/src/core/utils.js index 934afd0618b1..642a7e7b2064 100644 --- a/packages/kit/src/core/utils.js +++ b/packages/kit/src/core/utils.js @@ -80,11 +80,19 @@ export function get_mime_lookup(manifest_data) { /** @param {import('types').ValidatedConfig} config */ export function get_aliases(config) { + /** @type {Record} */ const alias = { __GENERATED__: path.posix.join(config.kit.outDir, 'generated'), $app: `${get_runtime_path(config)}/app`, + + // For now, we handle `$lib` specially here rather than make it a default value for + // `config.kit.alias` since it has special meaning for packaging, etc. $lib: config.kit.files.lib }; + for (const [key, value] of Object.entries(config.kit.alias)) { + alias[key] = path.resolve(value); + } + return alias; } diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 302020246fbb..b2b46d27bbb8 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -93,6 +93,7 @@ export interface Config { extensions?: string[]; kit?: { adapter?: Adapter; + alias?: Record; appDir?: string; browser?: { hydrate?: boolean;