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

Support tsconfig.json & jsconfig.json aliases #1747

Merged
merged 15 commits into from
Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"strip-indent": "^4.0.0",
"supports-esm": "^1.0.0",
"tiny-glob": "^0.2.8",
"tsconfig-resolver": "^3.0.1",
"vite": "^2.6.10",
"yargs-parser": "^20.2.9",
"zod": "^3.8.1"
Expand Down
2 changes: 2 additions & 0 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fileURLToPath } from 'url';
import vite from './vite.js';
import astroVitePlugin from '../vite-plugin-astro/index.js';
import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.js';
import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
import jsxVitePlugin from '../vite-plugin-jsx/index.js';
import fetchVitePlugin from '../vite-plugin-fetch/index.js';
Expand Down Expand Up @@ -47,6 +48,7 @@ export async function createVite(inlineConfig: ViteConfigWithSSR, { astroConfig,
entries: ['src/**/*'], // Try and scan a user’s project (won’t catch everything),
},
plugins: [
configAliasVitePlugin({ config: astroConfig }),
astroVitePlugin({ config: astroConfig, devServer }),
markdownVitePlugin({ config: astroConfig, devServer }),
jsxVitePlugin({ config: astroConfig, logging }),
Expand Down
26 changes: 26 additions & 0 deletions packages/astro/src/vite-plugin-config-alias/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# vite-plugin-config-alias

This adds aliasing support to Vite from `tsconfig.json` or `jsconfig.json` files.

Consider the following example configuration:

```
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"components:*": ["components/*.astro"]
}
}
}
```

With this configuration, the following imports would map to the same location.

```js
import Test from '../components/Test.astro'

import Test from 'components/Test.astro'

import Test from 'components:Test'
```
105 changes: 105 additions & 0 deletions packages/astro/src/vite-plugin-config-alias/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import * as tsr from 'tsconfig-resolver';
import * as path from 'path';
import * as url from 'url';

import type * as vite from 'vite';

/** Result of successfully parsed tsconfig.json or jsconfig.json. */
export declare interface Alias {
find: RegExp;
replacement: string;
}

/** Returns a path with its slashes replaced with posix slashes. */
const normalize = (pathname: string) => String(pathname).split(path.sep).join(path.posix.sep);

/** Returns the results of a config file if it exists, otherwise null. */
const getExistingConfig = (searchName: string, cwd: string | undefined): tsr.TsConfigResultSuccess | null => {
const config = tsr.tsconfigResolverSync({ cwd, searchName });

return config.exists ? config : null;
};

/** Returns a list of compiled aliases. */
const getConfigAlias = (cwd: string | undefined): Alias[] | null => {
/** Closest tsconfig.json or jsconfig.json */
const config = getExistingConfig('tsconfig.json', cwd) || getExistingConfig('jsconfig.json', cwd);

// if no config was found, return null
if (!config) return null;

/** Compiler options from tsconfig.json or jsconfig.json. */
const compilerOptions = Object(config.config.compilerOptions);

// if no compilerOptions.baseUrl was defined, return null
if (!compilerOptions.baseUrl) return null;

// resolve the base url from the configuration file directory
const baseUrl = path.posix.resolve(path.posix.dirname(normalize(config.path)), normalize(compilerOptions.baseUrl));

/** List of compiled alias expressions. */
const aliases: Alias[] = [];

// compile any alias expressions and push them to the list
for (let [alias, values] of Object.entries(Object(compilerOptions.paths) as { [key: string]: string[] })) {
values = [].concat(values as never);
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why this is needed, can you elaborate?


/** Regular Expression used to match a given path. */
const find = new RegExp(`^${[...alias].map((segment) => (segment === '*' ? '(.+)' : segment.replace(/[\\^$*+?.()|[\]{}]/, '\\$&'))).join('')}$`);

/** Internal index used to calculate the matching id in a replacement. */
let matchId = 0;

for (let value of values) {
/** String used to replace a matched path. */
const replacement = [...path.posix.resolve(baseUrl, value)].map((segment) => (segment === '*' ? `$${++matchId}` : segment === '$' ? '$$' : segment)).join('');

aliases.push({ find, replacement });
}
}

// compile the baseUrl expression and push it to the list
// - `baseUrl` changes the way non-relative specifiers are resolved
// - if `baseUrl` exists then all non-relative specifiers are resolved relative to it
aliases.push({
find: /^(?!\.*\/)(.+)$/,
replacement: `${[...baseUrl].map((segment) => (segment === '$' ? '$$' : segment)).join('')}/$1`,
});

return aliases;
};

/** Returns a Vite plugin used to alias pathes from tsconfig.json and jsconfig.json. */
export default function configAliasVitePlugin(astroConfig: { projectRoot?: URL; [key: string]: unknown }): vite.PluginOption {
/** Aliases from the tsconfig.json or jsconfig.json configuration. */
const configAlias = getConfigAlias(astroConfig.projectRoot && url.fileURLToPath(astroConfig.projectRoot));

// if no config alias was found, bypass this plugin
if (!configAlias) return {} as vite.PluginOption;

return {
name: '@astrojs/vite-plugin-config-alias',
enforce: 'pre',
async resolveId(sourceId: string, importer, options) {
/** Resolved ID conditionally handled by any other resolver. (this gives priority to all other resolvers) */
const resolvedId = await this.resolve(sourceId, importer, { skipSelf: true, ...options });

// if any other resolver handles the file, return that resolution
if (resolvedId) return resolvedId;

// conditionally resolve the source ID from any matching alias or baseUrl
for (const alias of configAlias) {
if (alias.find.test(sourceId)) {
/** Processed Source ID with our alias applied. */
const aliasedSourceId = sourceId.replace(alias.find, alias.replacement);

/** Resolved ID conditionally handled by any other resolver. (this also gives priority to all other resolvers) */
const resolvedAliasedId = await this.resolve(aliasedSourceId, importer, { skipSelf: true, ...options });

// if the existing resolvers find the file, return that resolution
if (resolvedAliasedId) return resolvedAliasedId;
}
}
},
};
}
23 changes: 20 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==

"@types/json5@^0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818"
integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==

"@types/mdast@^3.0.0", "@types/mdast@^3.0.3":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
Expand Down Expand Up @@ -1990,7 +1995,7 @@
dependencies:
"@types/node" "*"

"@types/resolve@^1.20.1":
"@types/resolve@^1.17.0", "@types/resolve@^1.20.1":
version "1.20.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.1.tgz#3727e48042fda81e374f5d5cf2fa92288bf698f8"
integrity sha512-Ku5+GPFa12S3W26Uwtw+xyrtIpaZsGYHH6zxNbZlstmlvMYSZRzOwzwsXbxlVUbHyUucctSyuFtu6bNxwYomIw==
Expand Down Expand Up @@ -6458,7 +6463,7 @@ json5@^0.5.1:
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=

json5@^2.1.2:
json5@^2.1.2, json5@^2.1.3:
version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
Expand Down Expand Up @@ -9527,7 +9532,7 @@ resolve-path@^1.4.0:
http-errors "~1.6.2"
path-is-absolute "1.0.1"

resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.20.0, resolve@^1.3.2:
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.3.2:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
Expand Down Expand Up @@ -10608,6 +10613,18 @@ ts-morph@^12.0.0:
"@ts-morph/common" "~0.11.0"
code-block-writer "^10.1.1"

tsconfig-resolver@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/tsconfig-resolver/-/tsconfig-resolver-3.0.1.tgz#c9e62e328ecfbeaae4a4f1131a92cdbed12350c4"
integrity sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==
dependencies:
"@types/json5" "^0.0.30"
"@types/resolve" "^1.17.0"
json5 "^2.1.3"
resolve "^1.17.0"
strip-bom "^4.0.0"
type-fest "^0.13.1"

tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
Expand Down