mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Add integration tests for multi-root builds (#14564)
When your Vite or postcss project has multiple Tailwind CSS roots with different configs, they should not influence each other (with the exception of the same candidates being used).
This commit is contained in:
parent
3813f03b79
commit
3f85b74611
50
integrations/postcss/multi-root.test.ts
Normal file
50
integrations/postcss/multi-root.test.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { candidate, css, html, js, json, test } from '../utils'
|
||||
|
||||
test(
|
||||
'production build',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"postcss": "^8",
|
||||
"postcss-cli": "^10",
|
||||
"tailwindcss": "workspace:^",
|
||||
"@tailwindcss/postcss": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'postcss.config.js': js`
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
`,
|
||||
'index.html': html`
|
||||
<div class="one:underline two:underline"></div>
|
||||
`,
|
||||
'src/shared.css': css`
|
||||
@import 'tailwindcss/theme' theme(reference);
|
||||
@import 'tailwindcss/utilities';
|
||||
`,
|
||||
'src/root1.css': css`
|
||||
@import './shared.css';
|
||||
@variant one (&:is([data-root='1']));
|
||||
`,
|
||||
'src/root2.css': css`
|
||||
@import './shared.css';
|
||||
@variant two (&:is([data-root='2']));
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ fs, exec }) => {
|
||||
await exec('pnpm postcss src/*.css -d dist')
|
||||
|
||||
await fs.expectFileToContain('dist/root1.css', [candidate`one:underline`])
|
||||
await fs.expectFileNotToContain('dist/root1.css', [candidate`two:underline`])
|
||||
|
||||
await fs.expectFileNotToContain('dist/root2.css', [candidate`one:underline`])
|
||||
await fs.expectFileToContain('dist/root2.css', [candidate`two:underline`])
|
||||
},
|
||||
)
|
||||
164
integrations/vite/multi-root.test.ts
Normal file
164
integrations/vite/multi-root.test.ts
Normal file
@ -0,0 +1,164 @@
|
||||
import { expect } from 'vitest'
|
||||
import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils'
|
||||
|
||||
test(
|
||||
`production build`,
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.3.5"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'vite.config.ts': ts`
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import path from 'node:path'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
cssMinify: false,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
root1: path.resolve(__dirname, 'root1.html'),
|
||||
root2: path.resolve(__dirname, 'root2.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [tailwindcss()],
|
||||
})
|
||||
`,
|
||||
'root1.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/root1.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="one:underline two:underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/shared.css': css`
|
||||
@import 'tailwindcss/theme' theme(reference);
|
||||
@import 'tailwindcss/utilities';
|
||||
`,
|
||||
'src/root1.css': css`
|
||||
@import './shared.css';
|
||||
@variant one (&:is([data-root='1']));
|
||||
`,
|
||||
'root2.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/root2.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="one:underline two:underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/root2.css': css`
|
||||
@import './shared.css';
|
||||
@variant two (&:is([data-root='2']));
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ fs, exec }) => {
|
||||
await exec('pnpm vite build')
|
||||
|
||||
let files = await fs.glob('dist/**/*.css')
|
||||
expect(files).toHaveLength(2)
|
||||
|
||||
let root1 = files.find(([filename]) => filename.includes('root1'))
|
||||
let root2 = files.find(([filename]) => filename.includes('root2'))
|
||||
|
||||
expect(root1).toBeDefined()
|
||||
expect(root2).toBeDefined()
|
||||
|
||||
expect(root1![1]).toContain(candidate`one:underline`)
|
||||
expect(root1![1]).not.toContain(candidate`two:underline`)
|
||||
|
||||
expect(root2![1]).not.toContain(candidate`one:underline`)
|
||||
expect(root2![1]).toContain(candidate`two:underline`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
`dev mode`,
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "workspace:^",
|
||||
"tailwindcss": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^5.3.5"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'vite.config.ts': ts`
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import path from 'node:path'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: { cssMinify: false },
|
||||
plugins: [tailwindcss()],
|
||||
})
|
||||
`,
|
||||
'root1.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/root1.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="one:underline two:underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/shared.css': css`
|
||||
@import 'tailwindcss/theme' theme(reference);
|
||||
@import 'tailwindcss/utilities';
|
||||
`,
|
||||
'src/root1.css': css`
|
||||
@import './shared.css';
|
||||
@variant one (&:is([data-root='1']));
|
||||
`,
|
||||
'root2.html': html`
|
||||
<head>
|
||||
<link rel="stylesheet" href="./src/root2.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="one:underline two:underline">Hello, world!</div>
|
||||
</body>
|
||||
`,
|
||||
'src/root2.css': css`
|
||||
@import './shared.css';
|
||||
@variant two (&:is([data-root='2']));
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ root, spawn, getFreePort, fs }) => {
|
||||
let port = await getFreePort()
|
||||
await spawn(`pnpm vite dev --port ${port}`)
|
||||
|
||||
// Candidates are resolved lazily, so the first visit of index.html
|
||||
// will only have candidates from this file.
|
||||
await retryAssertion(async () => {
|
||||
let styles = await fetchStyles(port, '/root1.html')
|
||||
expect(styles).toContain(candidate`one:underline`)
|
||||
expect(styles).not.toContain(candidate`two:underline`)
|
||||
})
|
||||
|
||||
// Going to about.html will extend the candidate list to include
|
||||
// candidates from about.html.
|
||||
await retryAssertion(async () => {
|
||||
let styles = await fetchStyles(port, '/root2.html')
|
||||
expect(styles).not.toContain(candidate`one:underline`)
|
||||
expect(styles).toContain(candidate`two:underline`)
|
||||
})
|
||||
},
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user