Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Vite: Fix an issue where `url(…)` rebasing in transitively imported CSS files is not resolved correctly
- PostCSS: Rebase `url(…)` in CSS imported CSS files
- Ensure utilities are sorted based on their actual property order ([#16995](https://github.com/tailwindlabs/tailwindcss/pull/16995))

## [4.0.11] - 2025-03-06
Expand Down
74 changes: 74 additions & 0 deletions integrations/postcss/url-rewriting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { css, js, json, test } from '../utils'

test(
'can rewrite urls in production builds',
{
fs: {
'package.json': json`
{
"dependencies": {
"postcss": "^8",
"postcss-cli": "^10",
"tailwindcss": "workspace:^",
"@tailwindcss/postcss": "workspace:^"
}
}
`,
'postcss.config.js': js`
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
}
`,
'src/index.css': css`
@reference 'tailwindcss';
@import './dir-1/bar.css';
@import './dir-1/dir-2/baz.css';
@import './dir-1/dir-2/vector.css';
`,
'src/dir-1/bar.css': css`
.test1 {
background-image: url('../../resources/image.png');
}
`,
'src/dir-1/dir-2/baz.css': css`
.test2 {
background-image: url('../../../resources/image.png');
}
`,
'src/dir-1/dir-2/vector.css': css`
@import './dir-3/vector.css';
.test3 {
background-image: url('../../../resources/vector.svg');
}
`,
'src/dir-1/dir-2/dir-3/vector.css': css`
.test4 {
background-image: url('./vector-2.svg');
}
`,
},
},
async ({ fs, exec, expect }) => {
await exec('pnpm postcss src/index.css --output dist/out.css')

expect(await fs.dumpFiles('dist/out.css')).toMatchInlineSnapshot(`
"
--- dist/out.css ---
.test1 {
background-image: url('../resources/image.png');
}
.test2 {
background-image: url('../resources/image.png');
}
.test4 {
background-image: url('./dir-1/dir-2/dir-3/vector-2.svg');
}
.test3 {
background-image: url('../resources/vector.svg');
}
"
`)
},
)
25 changes: 19 additions & 6 deletions integrations/vite/url-rewriting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,36 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
`,
'src/main.ts': ts``,
'src/app.css': css`
@reference 'tailwindcss';
@import './dir-1/bar.css';
@import './dir-1/dir-2/baz.css';
@import './dir-1/dir-2/vector.css';
`,
'src/dir-1/bar.css': css`
.bar {
.test1 {
background-image: url('../../resources/image.png');
}
`,
'src/dir-1/dir-2/baz.css': css`
.baz {
.test2 {
background-image: url('../../../resources/image.png');
}
`,
'src/dir-1/dir-2/vector.css': css`
.baz {
@import './dir-3/vector.css';
.test3 {
background-image: url('../../../resources/vector.svg');
}
`,
'src/dir-1/dir-2/dir-3/vector.css': css`
.test4 {
background-image: url('./vector-2.svg');
}
`,
'resources/image.png': binary(SIMPLE_IMAGE),
'resources/vector.svg': svg`
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
Expand All @@ -76,6 +81,14 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
<circle cx="200" cy="100" r="80" fill="green" />
</svg>
`,
'src/dir-1/dir-2/dir-3/vector-2.svg': svg`
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="blue" />
<circle cx="200" cy="100" r="80" fill="green" />
<rect width="100%" height="100%" fill="red" />
<circle cx="200" cy="100" r="80" fill="pink" />
</svg>
`,
},
},
async ({ fs, exec, expect }) => {
Expand All @@ -87,7 +100,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
await fs.expectFileToContain(files[0][0], [SIMPLE_IMAGE])

let images = await fs.glob('dist/**/*.svg')
expect(images).toHaveLength(1)
expect(images).toHaveLength(2)

await fs.expectFileToContain(files[0][0], [/\/assets\/vector-.*?\.svg/])
},
Expand Down
4 changes: 2 additions & 2 deletions packages/@tailwindcss-node/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ function createCompileOptions({
async loadModule(id: string, base: string) {
return loadModule(id, base, onDependency, customJsResolver)
},
async loadStylesheet(id: string, base: string) {
let sheet = await loadStylesheet(id, base, onDependency, customCssResolver)
async loadStylesheet(id: string, sheetBase: string) {
let sheet = await loadStylesheet(id, sheetBase, onDependency, customCssResolver)

if (shouldRewriteUrls) {
sheet.content = await rewriteUrls({
Expand Down
1 change: 1 addition & 0 deletions packages/@tailwindcss-postcss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
DEBUG && I.start('Create compiler')
let compiler = await compileAst(ast, {
base: inputBasePath,
shouldRewriteUrls: true,
onDependency: (path) => {
context.fullRebuildPaths.push(path)
},
Expand Down