-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
jonathantneal
merged 15 commits into
withastro:main
from
jonathantneal:jn.resolve-from-ts-js-config
Nov 9, 2021
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
7dd7d72
Resolve paths from tsconfig or jsconfig
jonathantneal 71fdfe9
edit: rename plugin to `@astrojs/vite-plugin-tsconfig-alias`
jonathantneal 7f5201e
edit: switch from `ps` to `path.posix`
jonathantneal b97bcf7
edit: move sanitization of paths to loop
jonathantneal 1f24aea
edit: rename `resolveConfigPaths` to `configAliasVitePlugin`
jonathantneal b4a14c8
edit: update implementation based on feedback
jonathantneal f65de59
prettier
jonathantneal c046caa
edit: rename `matchTailingAsterisk` to `matchTrailingAsterisk`
jonathantneal 7252dce
edit: cleanup with comments
jonathantneal f2ec843
edit: spellcheck `condition` to `conditionally`
jonathantneal ed1613b
edit: refactor based on feedback
jonathantneal 5a9020a
edit: Update README.md
jonathantneal a4ffc5b
edit: cleanup baseUrl transformation and add explainer comments
jonathantneal 360c2c5
edit: cleanup resolutions and add commenting
jonathantneal d67bf6a
yarn lint
jonathantneal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
|
||
/** 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; | ||
} | ||
} | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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?