tailwindcss/integrations/vite/astro.test.ts
Andrey Viktorov bc6e4b85bf
Fallback to config.createResolver for client and ssr environments in @tailwindcss/vite (#19679)
<!--

👋 Hey, thanks for your interest in contributing to Tailwind!

**Please ask first before starting work on any significant new
features.**

It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create a discussion to
first discuss any significant new features.

For more info, check out the contributing guide:


https://github.com/tailwindcss/tailwindcss/blob/main/.github/CONTRIBUTING.md

-->

## Summary

Sometimes even if Vite Envrionment API is available, some plugins are
still override `config.createResolver` function to inject own aliases

Since technically `config.createResolver` was only [properly
deprecated](https://github.com/vitejs/vite/pull/20031) in Vite 7.0.0,
it's still a valid(-ish) to do so, even if it wasn't ever officially
supported

Vite already handles this in its internal css resolvers, but not exposes
the code to do so as part of public API, so I've copied and adapted it

Fixes #19677

## Test plan

Tested by copying built package into my repro from the issue, also ran
vite integration tests

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2026-02-17 19:59:57 +00:00

201 lines
5.1 KiB
TypeScript

import { candidate, css, fetchStyles, html, js, json, retryAssertion, test, ts } from '../utils'
test(
'dev mode',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"astro": "^4.15.2",
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
}
}
`,
'astro.config.mjs': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'astro/config'
// https://astro.build/config
export default defineConfig({
vite: { plugins: [tailwindcss()] },
build: { inlineStylesheets: 'never' },
})
`,
'src/pages/index.astro': html`
<div class="underline">Hello, world!</div>
<style is:global>
@import 'tailwindcss';
</style>
`,
},
},
async ({ fs, spawn, expect }) => {
let process = await spawn('pnpm astro dev')
await process.onStdout((m) => m.includes('ready in'))
let url = ''
await process.onStdout((m) => {
let match = /Local\s*(http.*)\//.exec(m)
if (match) url = match[1]
return Boolean(url)
})
await process.onStdout((m) => m.includes('watching for file changes'))
await retryAssertion(async () => {
let css = await fetchStyles(url)
expect(css).toContain(candidate`underline`)
})
await retryAssertion(async () => {
await fs.write(
'src/pages/index.astro',
html`
<div class="underline font-bold">Hello, world!</div>
<style is:global>
@import 'tailwindcss';
</style>
`,
)
let css = await fetchStyles(url)
expect(css).toContain(candidate`underline`)
expect(css).toContain(candidate`font-bold`)
})
},
)
test(
'build mode',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"astro": "^4.15.2",
"react": "^19",
"react-dom": "^19",
"@astrojs/react": "^4",
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
}
}
`,
'astro.config.mjs': ts`
import tailwindcss from '@tailwindcss/vite'
import react from '@astrojs/react'
import { defineConfig } from 'astro/config'
// https://astro.build/config
export default defineConfig({
vite: { plugins: [tailwindcss()] },
integrations: [react()],
build: { inlineStylesheets: 'never' },
})
`,
// prettier-ignore
'src/pages/index.astro': html`
---
import ClientOnly from './client-only';
---
<div class="underline">Hello, world!</div>
<ClientOnly client:only="react" />
<style is:global>
@import 'tailwindcss';
</style>
`,
'src/pages/client-only.jsx': js`
export default function ClientOnly() {
return <div className="overline">Hello, world!</div>
}
`,
},
},
async ({ fs, exec, expect }) => {
await exec('pnpm astro build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
await fs.expectFileToContain(files[0][0], [candidate`underline`, candidate`overline`])
},
)
// https://github.com/tailwindlabs/tailwindcss/issues/19677
test(
'import aliases should work in <style> blocks',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"astro": "^5",
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
}
}
`,
'astro.config.mjs': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'astro/config'
// https://astro.build/config
export default defineConfig({
vite: { plugins: [tailwindcss()] },
})
`,
'tsconfig.json': json`
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
"paths": {
"@styles/*": ["./src/styles/*"]
}
}
}
`,
// prettier-ignore
'src/pages/index.astro': html`
---
import '@styles/global.css'
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
<style>
@reference "@styles/global.css";
</style>
</head>
<body>
<h1 class="underline">Astro</h1>
</body>
</html>
`,
'src/styles/global.css': css`@import 'tailwindcss';`,
},
},
async ({ fs, exec, expect }) => {
await exec('pnpm astro build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
await fs.expectFileToContain(files[0][0], [candidate`underline`])
},
)