diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d616d340..f6fbd9bd7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- _Experimental_: add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901))
+### Fixed
+
+- Ensure imports in `@import` and `@plugin` still resolve correctly when using Vite aliases in `@tailwindcss/vite` ([#19947](https://github.com/tailwindlabs/tailwindcss/pull/19947))
+
## [4.2.3] - 2026-04-20
### Fixed
diff --git a/integrations/vite/resolvers.test.ts b/integrations/vite/resolvers.test.ts
index 79ce57553..f2f4b8a0b 100644
--- a/integrations/vite/resolvers.test.ts
+++ b/integrations/vite/resolvers.test.ts
@@ -164,6 +164,130 @@ test(
},
)
+test(
+ 'resolves at-sign aliases in production build',
+ {
+ fs: {
+ 'package.json': json`
+ {
+ "type": "module",
+ "dependencies": {
+ "@tailwindcss/vite": "workspace:^",
+ "tailwindcss": "workspace:^"
+ },
+ "devDependencies": {
+ "vite": "^8"
+ }
+ }
+ `,
+ 'vite.config.ts': ts`
+ import tailwindcss from '@tailwindcss/vite'
+ import { defineConfig } from 'vite'
+ import { fileURLToPath } from 'node:url'
+
+ export default defineConfig({
+ build: { cssMinify: false },
+ plugins: [tailwindcss()],
+ resolve: {
+ alias: [{ find: '@', replacement: fileURLToPath(new URL('.', import.meta.url)) }],
+ },
+ })
+ `,
+ 'index.html': html`
+
+
+
+
+ Hello, world!
+
+ `,
+ 'src/index.css': css`
+ @import '@/src/styles/base.css';
+ @plugin '@/src/plugin.js';
+ `,
+ 'src/styles/base.css': css`
+ @reference 'tailwindcss/theme';
+ @import 'tailwindcss/utilities';
+ `,
+ 'src/plugin.js': js`
+ export default function ({ addUtilities }) {
+ addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } })
+ }
+ `,
+ },
+ },
+ async ({ fs, exec, expect }) => {
+ await exec('pnpm vite build')
+
+ let files = await fs.glob('dist/**/*.css')
+ expect(files).toHaveLength(1)
+ let [filename] = files[0]
+
+ await fs.expectFileToContain(filename, [candidate`underline`, candidate`custom-underline`])
+ },
+)
+
+test(
+ 'resolves package plugins in production build with at-sign aliases',
+ {
+ fs: {
+ 'package.json': json`
+ {
+ "type": "module",
+ "dependencies": {
+ "@tailwindcss/vite": "workspace:^",
+ "tailwindcss": "workspace:^"
+ },
+ "devDependencies": {
+ "tailwind-scrollbar": "^4.0.2",
+ "tailwindcss-motion": "^1.1.1",
+ "vite": "^8"
+ }
+ }
+ `,
+ 'vite.config.ts': ts`
+ import tailwindcss from '@tailwindcss/vite'
+ import { defineConfig } from 'vite'
+ import { fileURLToPath } from 'node:url'
+
+ export default defineConfig({
+ build: { cssMinify: false },
+ plugins: [tailwindcss()],
+ resolve: {
+ alias: [{ find: '@', replacement: fileURLToPath(new URL('.', import.meta.url)) }],
+ },
+ })
+ `,
+ 'index.html': html`
+
+
+
+
+ Hello, world!
+
+ `,
+ 'src/index.css': css`
+ @import 'tailwindcss';
+ @plugin 'tailwind-scrollbar';
+ @plugin 'tailwindcss-motion';
+ `,
+ },
+ },
+ async ({ fs, exec, expect }) => {
+ await exec('pnpm vite build')
+
+ let files = await fs.glob('dist/**/*.css')
+ expect(files).toHaveLength(1)
+ let [filename] = files[0]
+
+ await fs.expectFileToContain(filename, [
+ candidate`scrollbar`,
+ candidate`scrollbar-thumb-red-500`,
+ candidate`motion-preset-fade`,
+ ])
+ },
+)
+
describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
test(
'resolves aliases in production build',
diff --git a/integrations/vite/sveltekit.test.ts b/integrations/vite/sveltekit.test.ts
new file mode 100644
index 000000000..92e855da9
--- /dev/null
+++ b/integrations/vite/sveltekit.test.ts
@@ -0,0 +1,80 @@
+import { candidate, css, html, js, json, test, ts } from '../utils'
+
+test(
+ 'sveltekit build resolves package plugins',
+ {
+ fs: {
+ 'package.json': json`
+ {
+ "type": "module",
+ "scripts": {
+ "prepare": "svelte-kit sync || echo ''"
+ },
+ "dependencies": {
+ "svelte": "^5",
+ "tailwindcss": "workspace:^"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^6",
+ "@sveltejs/kit": "^2",
+ "@tailwindcss/forms": "^0.5.11",
+ "@tailwindcss/vite": "workspace:^",
+ "vite": "^8"
+ }
+ }
+ `,
+ 'svelte.config.js': js`
+ import adapter from '@sveltejs/adapter-auto'
+
+ export default {
+ kit: {
+ adapter: adapter(),
+ },
+ }
+ `,
+ 'vite.config.ts': ts`
+ import tailwindcss from '@tailwindcss/vite'
+ import { sveltekit } from '@sveltejs/kit/vite'
+ import { defineConfig } from 'vite'
+
+ export default defineConfig({
+ build: { cssMinify: false },
+ plugins: [tailwindcss(), sveltekit()],
+ })
+ `,
+ 'src/app.html': html`
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
+ `,
+ 'src/routes/+layout.svelte': html`
+
+
+
+ `,
+ 'src/routes/+page.svelte': html`
+ Hello, world!
+ `,
+ 'src/app.css': css`
+ @import 'tailwindcss';
+ @plugin '@tailwindcss/forms';
+ `,
+ },
+ },
+ async ({ exec, fs, expect }) => {
+ await exec('pnpm vite build')
+
+ let files = await fs.glob('.svelte-kit/output/client/**/*.css')
+ expect(files.length).toBeGreaterThan(0)
+
+ await fs.expectFileToContain(files[0][0], [candidate`form-input`])
+ },
+)
diff --git a/packages/@tailwindcss-postcss/README.md b/packages/@tailwindcss-postcss/README.md
index 981ffc42d..3facf2887 100644
--- a/packages/@tailwindcss-postcss/README.md
+++ b/packages/@tailwindcss-postcss/README.md
@@ -109,4 +109,3 @@ export default {
],
}
```
-
diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts
index ac3e1c33c..5b376937c 100644
--- a/packages/@tailwindcss-vite/src/index.ts
+++ b/packages/@tailwindcss-vite/src/index.ts
@@ -64,10 +64,19 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
customCssResolver = async (id: string, base: string) => {
let resolved = await cssResolver(id, base, false, isSSR)
- if (resolved && !resolved.endsWith('.css')) return undefined
+ if (!resolved) return
+ if (resolved === id) return
+ if (!path.isAbsolute(resolved)) return
+ if (!resolved.endsWith('.css')) return
+ return resolved
+ }
+ customJsResolver = async (id: string, base: string) => {
+ let resolved = await jsResolver(id, base, false, isSSR)
+ if (!resolved) return
+ if (resolved === id) return
+ if (!path.isAbsolute(resolved)) return
return resolved
}
- customJsResolver = (id: string, base: string) => jsResolver(id, base, false, isSSR)
} else {
type ResolveIdFn = (
environment: Environment,
@@ -111,10 +120,19 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
customCssResolver = async (id: string, base: string) => {
let resolved = await cssResolver(env, id, base, false)
- if (resolved && !resolved.endsWith('.css')) return undefined
+ if (!resolved) return
+ if (resolved === id) return
+ if (!path.isAbsolute(resolved)) return
+ if (!resolved.endsWith('.css')) return
+ return resolved
+ }
+ customJsResolver = async (id: string, base: string) => {
+ let resolved = await jsResolver(env, id, base, false)
+ if (!resolved) return
+ if (resolved === id) return
+ if (!path.isAbsolute(resolved)) return
return resolved
}
- customJsResolver = (id: string, base: string) => jsResolver(env, id, base, false)
}
return new Root(