tailwindcss/integrations/vite/svelte.test.ts
Philipp Spiess 78f5b087d4
Add @import "…" reference (#15228)
Closes #15219

This PR adds a new feature, `@import "…" reference` that can be used to
load Tailwind CSS configuration files without adding any style rules to
the CSS.

The idea is that you can use this in combination with your Tailwind CSS
root file when you need to have access to your full CSS config outside
of the main stylesheet. A common example is for Vue, Svelte, or CSS
modules:

```css
@import "./tailwind.css" reference;

.link {
  @apply underline;
}
```

Importing a file as a reference will convert all `@theme` block to be
`reference`, so no CSS variables will be emitted. Furthermore it will
strip out all custom styles from the stylesheet. Furthermore plugins
registered via `@plugin` or `@config` inside reference-mode files will
not add any content to the CSS file via `addBase()`.

## Test Plan

Added unit test for when we handle the import resolution and when
`postcss-import` does it outside of Tailwind CSS. I also changed the
Svelte and Vue integration tests to use this new syntax to ensure it
works end to end.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-12-03 14:15:24 +01:00

252 lines
6.6 KiB
TypeScript

import { expect } from 'vitest'
import { candidate, css, html, json, retryAssertion, test, ts } from '../utils'
test(
'production build',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"svelte": "^5",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5",
"@tailwindcss/vite": "workspace:^",
"vite": "^6"
}
}
`,
'vite.config.ts': ts`
import { defineConfig } from 'vite'
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
svelte({
preprocess: [vitePreprocess()],
}),
tailwindcss(),
],
})
`,
'index.html': html`
<!doctype html>
<html>
<body>
<div id="app"></div>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
`,
'src/main.ts': ts`
import App from './App.svelte'
const app = new App({
target: document.body,
})
`,
'src/index.css': css`@import 'tailwindcss' reference;`,
'src/App.svelte': html`
<script>
import './index.css'
let name = 'world'
</script>
<h1 class="global local underline">Hello {name}!</h1>
<style>
@import 'tailwindcss/theme' theme(reference);
@import './other.css';
</style>
`,
'src/other.css': css`
.local {
@apply text-red-500;
animation: 2s ease-in-out 0s infinite localKeyframes;
}
:global(.global) {
@apply text-green-500;
animation: 2s ease-in-out 0s infinite globalKeyframes;
}
@keyframes -global-globalKeyframes {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
@keyframes localKeyframes {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
`,
},
},
async ({ fs, exec }) => {
await exec('pnpm vite build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
await fs.expectFileToContain(files[0][0], [
candidate`underline`,
'.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}',
/\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/,
/@keyframes globalKeyframes\{/,
/@keyframes svelte-.*-localKeyframes\{/,
])
},
)
test(
'watch mode',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"svelte": "^5",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5",
"@tailwindcss/vite": "workspace:^",
"vite": "^6"
}
}
`,
'vite.config.ts': ts`
import { defineConfig } from 'vite'
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
svelte({
preprocess: [vitePreprocess()],
}),
tailwindcss(),
],
})
`,
'index.html': html`
<!doctype html>
<html>
<body>
<div id="app"></div>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
`,
'src/main.ts': ts`
import App from './App.svelte'
const app = new App({
target: document.body,
})
`,
'src/App.svelte': html`
<script>
import './index.css'
let name = 'world'
</script>
<h1 class="local global underline">Hello {name}!</h1>
<style>
@import 'tailwindcss/theme' theme(reference);
@import './other.css';
</style>
`,
'src/index.css': css`
@import 'tailwindcss/theme' theme(reference);
@import 'tailwindcss/utilities';
`,
'src/other.css': css`
.local {
@apply text-red-500;
animation: 2s ease-in-out 0s infinite localKeyframes;
}
:global(.global) {
@apply text-green-500;
animation: 2s ease-in-out 0s infinite globalKeyframes;
}
@keyframes -global-globalKeyframes {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
@keyframes localKeyframes {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
`,
},
},
async ({ fs, spawn }) => {
await spawn(`pnpm vite build --watch`)
await retryAssertion(async () => {
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
let [, css] = files[0]
expect(css).toContain(candidate`underline`)
expect(css).toContain(
'.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}',
)
expect(css).toMatch(
/\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/,
)
expect(css).toMatch(/@keyframes globalKeyframes\{/)
expect(css).toMatch(/@keyframes svelte-.*-localKeyframes\{/)
})
await fs.write(
'src/App.svelte',
(await fs.read('src/App.svelte')).replace('underline', 'font-bold bar'),
)
await fs.write(
'src/other.css',
`${await fs.read('src/other.css')}\n.bar { @apply text-pink-500; }`,
)
await retryAssertion(async () => {
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
let [, css] = files[0]
expect(css).toContain(candidate`font-bold`)
expect(css).toContain(
'.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}',
)
expect(css).toMatch(
/\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/,
)
expect(css).toMatch(/@keyframes globalKeyframes\{/)
expect(css).toMatch(/@keyframes svelte-.*-localKeyframes\{/)
expect(css).toMatch(/\.bar.svelte-.*\{color:var\(--color-pink-500\)\}/)
})
},
)