diff --git a/.changeset/sharp-timers-lick.md b/.changeset/sharp-timers-lick.md new file mode 100644 index 0000000000..721f850d8c --- /dev/null +++ b/.changeset/sharp-timers-lick.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix failed `astro sync` call when running `astro check`. This change also reverts alias support in CSS styles. diff --git a/packages/astro/src/vite-plugin-config-alias/index.ts b/packages/astro/src/vite-plugin-config-alias/index.ts index 29fc23abc6..ab4547cc67 100644 --- a/packages/astro/src/vite-plugin-config-alias/index.ts +++ b/packages/astro/src/vite-plugin-config-alias/index.ts @@ -1,19 +1,47 @@ -import path from 'path'; +import * as path from 'path'; import type { AstroSettings } from '../@types/astro'; -import slash from 'slash'; -import type { TsConfigJson } from 'tsconfig-resolver'; -import type { Alias, Plugin as VitePlugin } from 'vite'; +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 a list of compiled aliases. */ -const getConfigAlias = ( - paths: NonNullable, - baseUrl: NonNullable -): Alias[] => { +const getConfigAlias = (settings: AstroSettings): Alias[] | null => { + /** Closest tsconfig.json or jsconfig.json */ + const config = settings.tsConfig; + const configPath = settings.tsConfigPath; + + // if no config was found, return null + if (!config || !configPath) return null; + + /** Compiler options from tsconfig.json or jsconfig.json. */ + const compilerOptions = Object(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(configPath).replace(/^\/?/, '/')), + normalize(compilerOptions.baseUrl) + ); + + /** List of compiled alias expressions. */ const aliases: Alias[] = []; // compile any alias expressions and push them to the list - for (const [alias, values] of Object.entries(paths)) { + 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] @@ -26,7 +54,7 @@ const getConfigAlias = ( /** Internal index used to calculate the matching id in a replacement. */ let matchId = 0; - for (const value of values) { + 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)) @@ -36,6 +64,14 @@ const getConfigAlias = ( } } + // 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; }; @@ -44,45 +80,40 @@ export default function configAliasVitePlugin({ settings, }: { settings: AstroSettings; -}): VitePlugin | null { - const { tsConfig, tsConfigPath } = settings; - if (!tsConfig || !tsConfigPath || !tsConfig.compilerOptions) return null; +}): vite.PluginOption { + const { config } = settings; + /** Aliases from the tsconfig.json or jsconfig.json configuration. */ + const configAlias = getConfigAlias(settings); - const { baseUrl, paths } = tsConfig.compilerOptions; - if (!baseUrl || !paths) return null; - - // resolve the base url from the configuration file directory - const resolvedBaseUrl = path.posix.resolve( - path.posix.dirname(slash(tsConfigPath).replace(/^\/?/, '/')), - slash(baseUrl) - ); - - const configAlias = getConfigAlias(paths, resolvedBaseUrl); + // if no config alias was found, bypass this plugin + if (!configAlias) return {} as vite.PluginOption; return { name: 'astro:tsconfig-alias', enforce: 'pre', - config() { - if (configAlias.length) { - return { - resolve: { - alias: configAlias, - }, - }; + 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; + } } }, - async resolveId(id, importer, options) { - if (id.startsWith('.') || path.isAbsolute(id)) return; - - // Handle baseUrl mapping for non-relative and non-root imports. - // Since TypeScript only applies `baseUrl` autocompletions for files that exist - // in the filesystem only, we can use this heuristic to skip resolve if needed. - const resolved = path.posix.join(resolvedBaseUrl, id); - - return await this.resolve(resolved, importer, { - skipSelf: true, - ...options, - }); - }, }; } diff --git a/packages/astro/test/alias-tsconfig.test.js b/packages/astro/test/alias-tsconfig.test.js index 0a683e086c..1468aabeb5 100644 --- a/packages/astro/test/alias-tsconfig.test.js +++ b/packages/astro/test/alias-tsconfig.test.js @@ -34,26 +34,5 @@ describe('Aliases with tsconfig.json', () => { const scripts = $('script').toArray(); expect(scripts.length).to.be.greaterThan(0); }); - - it('can load via baseUrl', async () => { - const html = await fixture.fetch('/').then((res) => res.text()); - const $ = cheerio.load(html); - - expect($('#foo').text()).to.equal('foo'); - }); - - it('works in css @import', async () => { - const html = await fixture.fetch('/').then((res) => res.text()); - // imported css should be bundled - expect(html).to.include('#style-red'); - expect(html).to.include('#style-blue'); - }); - - it('can load load typescript files without .ts or .d.ts extensions', async () => { - const html = await fixture.fetch('/').then((res) => res.text()); - const $ = cheerio.load(html); - - expect($('#mistery').text()).to.equal("I'm a TypeScript file!"); - }); }); }); diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro b/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro deleted file mode 100644 index 42bd5c2a53..0000000000 --- a/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro +++ /dev/null @@ -1 +0,0 @@ -

foo

\ No newline at end of file diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/components/Style.astro b/packages/astro/test/fixtures/alias-tsconfig/src/components/Style.astro deleted file mode 100644 index 0d8e06ae34..0000000000 --- a/packages/astro/test/fixtures/alias-tsconfig/src/components/Style.astro +++ /dev/null @@ -1,2 +0,0 @@ -

i am blue

-

i am red

diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro index 7b43a56712..c00b9f0836 100644 --- a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro +++ b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro @@ -1,24 +1,15 @@ --- -import Client from '@components/Client.svelte'; -import Foo from 'src/components/Foo.astro'; -import StyleComp from 'src/components/Style.astro'; -import '@styles/main.css'; -import { whoImI } from 'src/ts-file'; -const mistery = whoImI(); +import Client from '@components/Client.svelte' --- - - - - - Aliases using tsconfig - - -
- - - -
{mistery}
-
- + + + + Aliases using tsconfig + + +
+ +
+ diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css b/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css deleted file mode 100644 index c2e822c5d5..0000000000 --- a/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css +++ /dev/null @@ -1,3 +0,0 @@ -#style-red { - color: red; -} diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/styles/main.css b/packages/astro/test/fixtures/alias-tsconfig/src/styles/main.css deleted file mode 100644 index 77e2f77db6..0000000000 --- a/packages/astro/test/fixtures/alias-tsconfig/src/styles/main.css +++ /dev/null @@ -1,5 +0,0 @@ -@import "@styles/extra.css"; - -#style-blue { - color: blue; -} diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/ts-file.ts b/packages/astro/test/fixtures/alias-tsconfig/src/ts-file.ts deleted file mode 100644 index 834f20e9a0..0000000000 --- a/packages/astro/test/fixtures/alias-tsconfig/src/ts-file.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function whoImI() { - return "I'm a TypeScript file!"; -} diff --git a/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json index 0e86e12493..01dd88abee 100644 --- a/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json +++ b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json @@ -5,9 +5,12 @@ "@components/*": [ "src/components/*" ], - "@styles/*": [ - "src/styles/*" - ] + "@layouts/*": [ + "src/layouts/*" + ], + "@assets/*": [ + "src/assets/*" + ], } } }