summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/empty-ravens-complain.md5
-rw-r--r--packages/astro/src/vite-plugin-config-alias/index.ts116
-rw-r--r--packages/astro/test/alias-tsconfig.test.js15
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro1
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/src/components/Style.astro2
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro5
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css3
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/src/styles/main.css5
-rw-r--r--packages/astro/test/fixtures/alias-tsconfig/tsconfig.json9
9 files changed, 81 insertions, 80 deletions
diff --git a/.changeset/empty-ravens-complain.md b/.changeset/empty-ravens-complain.md
new file mode 100644
index 000000000..807882437
--- /dev/null
+++ b/.changeset/empty-ravens-complain.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Support tsconfig aliases in styles
diff --git a/packages/astro/src/vite-plugin-config-alias/index.ts b/packages/astro/src/vite-plugin-config-alias/index.ts
index ab4547cc6..52325904a 100644
--- a/packages/astro/src/vite-plugin-config-alias/index.ts
+++ b/packages/astro/src/vite-plugin-config-alias/index.ts
@@ -1,47 +1,20 @@
-import * as path from 'path';
+import fs from 'fs';
+import path from 'path';
import type { AstroSettings } from '../@types/astro';
-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);
+import type { Alias, Plugin as VitePlugin } from 'vite';
+import type { TsConfigJson } from 'tsconfig-resolver';
+import slash from 'slash';
/** Returns a list of compiled aliases. */
-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 getConfigAlias = (
+ paths: NonNullable<TsConfigJson.CompilerOptions['paths']>,
+ baseUrl: NonNullable<TsConfigJson.CompilerOptions['baseUrl']>
+): Alias[] => {
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);
-
+ for (const [alias, values] of Object.entries(paths)) {
/** Regular Expression used to match a given path. */
const find = new RegExp(
`^${[...alias]
@@ -54,7 +27,7 @@ const getConfigAlias = (settings: AstroSettings): Alias[] | null => {
/** Internal index used to calculate the matching id in a replacement. */
let matchId = 0;
- for (let value of values) {
+ for (const value of values) {
/** String used to replace a matched path. */
const replacement = [...path.posix.resolve(baseUrl, value)]
.map((segment) => (segment === '*' ? `$${++matchId}` : segment === '$' ? '$$' : segment))
@@ -64,14 +37,6 @@ const getConfigAlias = (settings: AstroSettings): Alias[] | null => {
}
}
- // 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;
};
@@ -80,39 +45,42 @@ export default function configAliasVitePlugin({
settings,
}: {
settings: AstroSettings;
-}): vite.PluginOption {
- const { config } = settings;
- /** Aliases from the tsconfig.json or jsconfig.json configuration. */
- const configAlias = getConfigAlias(settings);
+}): VitePlugin | null {
+ const { tsConfig, tsConfigPath } = settings;
+ if (!tsConfig || !tsConfigPath || !tsConfig.compilerOptions) return null;
+
+ 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)
+ );
- // if no config alias was found, bypass this plugin
- if (!configAlias) return {} as vite.PluginOption;
+ const configAlias = getConfigAlias(paths, resolvedBaseUrl);
return {
name: 'astro:tsconfig-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;
- }
+ config() {
+ if (configAlias.length) {
+ return {
+ resolve: {
+ alias: configAlias,
+ },
+ };
+ }
+ },
+ resolveId(id) {
+ if (id.startsWith('.') || id.startsWith('/')) 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);
+ if (fs.existsSync(resolved)) {
+ return resolved;
}
},
};
diff --git a/packages/astro/test/alias-tsconfig.test.js b/packages/astro/test/alias-tsconfig.test.js
index 1468aabeb..c6aa98284 100644
--- a/packages/astro/test/alias-tsconfig.test.js
+++ b/packages/astro/test/alias-tsconfig.test.js
@@ -34,5 +34,20 @@ 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());
+ console.log(html)
+ // imported css should be bundled
+ expect(html).to.include('#style-red');
+ expect(html).to.include('#style-blue');
+ });
});
});
diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro b/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro
new file mode 100644
index 000000000..42bd5c2a5
--- /dev/null
+++ b/packages/astro/test/fixtures/alias-tsconfig/src/components/Foo.astro
@@ -0,0 +1 @@
+<p id="foo">foo</p> \ 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
new file mode 100644
index 000000000..0d8e06ae3
--- /dev/null
+++ b/packages/astro/test/fixtures/alias-tsconfig/src/components/Style.astro
@@ -0,0 +1,2 @@
+<p id="style-blue">i am blue</p>
+<p id="style-red">i am red</p>
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 c00b9f083..20727cd6e 100644
--- a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro
+++ b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro
@@ -1,5 +1,8 @@
---
import Client from '@components/Client.svelte'
+import Foo from 'src/components/Foo.astro';
+import StyleComp from 'src/components/Style.astro';
+import '@styles/main.css'
---
<html lang="en">
<head>
@@ -10,6 +13,8 @@ import Client from '@components/Client.svelte'
<body>
<main>
<Client client:load />
+ <Foo />
+ <StyleComp />
</main>
</body>
</html>
diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css b/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css
new file mode 100644
index 000000000..c2e822c5d
--- /dev/null
+++ b/packages/astro/test/fixtures/alias-tsconfig/src/styles/extra.css
@@ -0,0 +1,3 @@
+#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
new file mode 100644
index 000000000..77e2f77db
--- /dev/null
+++ b/packages/astro/test/fixtures/alias-tsconfig/src/styles/main.css
@@ -0,0 +1,5 @@
+@import "@styles/extra.css";
+
+#style-blue {
+ color: blue;
+}
diff --git a/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json
index 01dd88abe..0e86e1249 100644
--- a/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json
+++ b/packages/astro/test/fixtures/alias-tsconfig/tsconfig.json
@@ -5,12 +5,9 @@
"@components/*": [
"src/components/*"
],
- "@layouts/*": [
- "src/layouts/*"
- ],
- "@assets/*": [
- "src/assets/*"
- ],
+ "@styles/*": [
+ "src/styles/*"
+ ]
}
}
}