Skip to content

Commit 2dd52f5

Browse files
Vite: Add support for <style> tags in Astro files (#14340)
This works similar to the Vue setup. The styles that Astro will receive might still contain Tailwind CSS APIs but since it's not picky, we can pass that through to the regular Vite `transform` handlers for now. This, however, will have issues like #14205. We have to fix this together with Vue and other similar extensions later. For now, it will break when syntax is used that lightningcss rewrites (like `@apply text-3xl/tight;`) --------- Co-authored-by: Jordan Pittman <[email protected]>
1 parent 805c8a0 commit 2dd52f5

File tree

4 files changed

+89
-14
lines changed

4 files changed

+89
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Support TypeScript for `@plugin` and `@config` files ([#14317](https://github.com/tailwindlabs/tailwindcss/pull/14317))
1313
- Add `default` option to `@theme` to support overriding default theme values from plugins/JS config files ([#14327](https://github.com/tailwindlabs/tailwindcss/pull/14327))
14+
- Add support for `<style>` tags in Astro files to the Vite plugin ([#14340](https://github.com/tailwindlabs/tailwindcss/pull/14340))
1415

1516
### Fixed
1617

integrations/utils.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -536,32 +536,40 @@ export async function fetchStyles(port: number, path = '/'): Promise<string> {
536536
let index = await fetch(`http://localhost:${port}${path}`)
537537
let html = await index.text()
538538

539-
let regex = /<link rel="stylesheet" href="([a-zA-Z0-9\/_\.\?=%-]+)"/g
539+
let linkRegex = /<link rel="stylesheet" href="([a-zA-Z0-9\/_\.\?=%-]+)"/gi
540+
let styleRegex = /<style\b[^>]*>([\s\S]*?)<\/style>/gi
541+
542+
let stylesheets: string[] = []
540543

541544
let paths: string[] = []
542545
let match
543-
while ((match = regex.exec(html)) !== null) {
546+
for (let match of html.matchAll(linkRegex)) {
544547
let path: string = match[1]
545548
if (path.startsWith('./')) {
546549
path = path.slice(1)
547550
}
548551
paths.push(path)
549552
}
550-
551-
let stylesheets = await Promise.all(
552-
paths.map(async (path) => {
553-
let css = await fetch(`http://localhost:${port}${path}`, {
554-
headers: {
555-
Accept: 'text/css',
556-
},
557-
})
558-
return await css.text()
559-
}),
553+
stylesheets.push(
554+
...(await Promise.all(
555+
paths.map(async (path) => {
556+
let css = await fetch(`http://localhost:${port}${path}`, {
557+
headers: {
558+
Accept: 'text/css',
559+
},
560+
})
561+
return await css.text()
562+
}),
563+
)),
560564
)
561565

566+
for (let match of html.matchAll(styleRegex)) {
567+
stylesheets.push(match[1])
568+
}
569+
562570
return stylesheets.reduce((acc, css) => {
563571
return acc + '\n' + css
564-
})
572+
}, '')
565573
}
566574

567575
async function gracefullyRemove(dir: string) {

integrations/vite/astro.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { expect } from 'vitest'
2+
import { candidate, fetchStyles, html, json, retryAssertion, test, ts } from '../utils'
3+
4+
test.debug(
5+
'dev mode',
6+
{
7+
fs: {
8+
'package.json': json`
9+
{
10+
"type": "module",
11+
"dependencies": {
12+
"astro": "^4.15.2",
13+
"@tailwindcss/vite": "workspace:^",
14+
"tailwindcss": "workspace:^"
15+
}
16+
}
17+
`,
18+
'astro.config.mjs': ts`
19+
import tailwindcss from '@tailwindcss/vite'
20+
import { defineConfig } from 'astro/config'
21+
22+
// https://astro.build/config
23+
export default defineConfig({
24+
vite: {
25+
plugins: [tailwindcss()],
26+
},
27+
})
28+
`,
29+
'src/pages/index.astro': html`
30+
<div class="underline">Hello, world!</div>
31+
32+
<style is:global>
33+
@import 'tailwindcss';
34+
</style>
35+
`,
36+
},
37+
},
38+
async ({ fs, spawn, getFreePort }) => {
39+
let port = await getFreePort()
40+
await spawn(`pnpm astro dev --port ${port}`)
41+
42+
await retryAssertion(async () => {
43+
let css = await fetchStyles(port)
44+
expect(css).toContain(candidate`underline`)
45+
})
46+
47+
await fs.write(
48+
'src/pages/index.astro',
49+
html`
50+
<div class="underline font-bold">Hello, world!</div>
51+
52+
<style is:global>
53+
@import 'tailwindcss';
54+
</style>
55+
`,
56+
)
57+
await retryAssertion(async () => {
58+
let css = await fetchStyles(port)
59+
expect(css).toContain(candidate`underline`)
60+
expect(css).toContain(candidate`font-bold`)
61+
})
62+
},
63+
)

packages/@tailwindcss-vite/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,10 @@ function getExtension(id: string) {
262262

263263
function isPotentialCssRootFile(id: string) {
264264
let extension = getExtension(id)
265-
let isCssFile = extension === 'css' || (extension === 'vue' && id.includes('&lang.css'))
265+
let isCssFile =
266+
extension === 'css' ||
267+
(extension === 'vue' && id.includes('&lang.css')) ||
268+
(extension === 'astro' && id.includes('&lang.css'))
266269
return isCssFile
267270
}
268271

0 commit comments

Comments
 (0)