Skip to content

Commit 225f323

Browse files
philipp-spiessRobinMalfaitthecrypticace
authored
Enable URL rewriting for PostCSS (#16965)
Fixes #16636 This PR enables URL rebasing for PostCSS. Furthermore it fixes an issue where transitive imports rebased against the importer CSS file instead of the input CSS file. While fixing this we noticed that this is also broken in Vite right now and that our integration test swallowed that when testing because it did not import any Tailwind CSS code and thus was not considered a Tailwind file. ## Test plan - Added regression integration tests - Also validated it against the repro of #16962: <img width="1149" alt="Screenshot 2025-03-05 at 16 41 01" src="https://github.com/user-attachments/assets/85396659-d3d0-48c0-b1c7-6125ff8e73ac" /> --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
1 parent d18fed1 commit 225f323

File tree

5 files changed

+98
-8
lines changed

5 files changed

+98
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919

2020
### Fixed
2121

22+
- Vite: Fix `url(…)` rebasing in transitively imported CSS files ([#16965](https://github.com/tailwindlabs/tailwindcss/pull/16965))
23+
- PostCSS: Rebase `url(…)`s in imported CSS files ([#16965](https://github.com/tailwindlabs/tailwindcss/pull/16965))
2224
- Ensure utilities are sorted based on their actual property order ([#16995](https://github.com/tailwindlabs/tailwindcss/pull/16995))
2325
- Ensure strings in Pug and Slim templates are handled correctly ([#17000](https://github.com/tailwindlabs/tailwindcss/pull/17000))
2426
- Ensure `}` and `{` are valid boundary characters when extracting candidates ([#17001](https://github.com/tailwindlabs/tailwindcss/pull/17001))
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { css, js, json, test } from '../utils'
2+
3+
test(
4+
'can rewrite urls in production builds',
5+
{
6+
fs: {
7+
'package.json': json`
8+
{
9+
"dependencies": {
10+
"postcss": "^8",
11+
"postcss-cli": "^10",
12+
"tailwindcss": "workspace:^",
13+
"@tailwindcss/postcss": "workspace:^"
14+
}
15+
}
16+
`,
17+
'postcss.config.js': js`
18+
module.exports = {
19+
plugins: {
20+
'@tailwindcss/postcss': {},
21+
},
22+
}
23+
`,
24+
'src/index.css': css`
25+
@reference 'tailwindcss';
26+
@import './dir-1/bar.css';
27+
@import './dir-1/dir-2/baz.css';
28+
@import './dir-1/dir-2/vector.css';
29+
`,
30+
'src/dir-1/bar.css': css`
31+
.test1 {
32+
background-image: url('../../resources/image.png');
33+
}
34+
`,
35+
'src/dir-1/dir-2/baz.css': css`
36+
.test2 {
37+
background-image: url('../../../resources/image.png');
38+
}
39+
`,
40+
'src/dir-1/dir-2/vector.css': css`
41+
@import './dir-3/vector.css';
42+
.test3 {
43+
background-image: url('../../../resources/vector.svg');
44+
}
45+
`,
46+
'src/dir-1/dir-2/dir-3/vector.css': css`
47+
.test4 {
48+
background-image: url('./vector-2.svg');
49+
}
50+
`,
51+
},
52+
},
53+
async ({ fs, exec, expect }) => {
54+
await exec('pnpm postcss src/index.css --output dist/out.css')
55+
56+
expect(await fs.dumpFiles('dist/out.css')).toMatchInlineSnapshot(`
57+
"
58+
--- dist/out.css ---
59+
.test1 {
60+
background-image: url('../resources/image.png');
61+
}
62+
.test2 {
63+
background-image: url('../resources/image.png');
64+
}
65+
.test4 {
66+
background-image: url('./dir-1/dir-2/dir-3/vector-2.svg');
67+
}
68+
.test3 {
69+
background-image: url('../resources/vector.svg');
70+
}
71+
"
72+
`)
73+
},
74+
)

integrations/vite/url-rewriting.test.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,36 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
4242
</head>
4343
<body>
4444
<div id="app"></div>
45-
<script type="module" src="./src/main.ts"></script>
4645
</body>
4746
</html>
4847
`,
49-
'src/main.ts': ts``,
5048
'src/app.css': css`
49+
@reference 'tailwindcss';
5150
@import './dir-1/bar.css';
5251
@import './dir-1/dir-2/baz.css';
5352
@import './dir-1/dir-2/vector.css';
5453
`,
5554
'src/dir-1/bar.css': css`
56-
.bar {
55+
.test1 {
5756
background-image: url('../../resources/image.png');
5857
}
5958
`,
6059
'src/dir-1/dir-2/baz.css': css`
61-
.baz {
60+
.test2 {
6261
background-image: url('../../../resources/image.png');
6362
}
6463
`,
6564
'src/dir-1/dir-2/vector.css': css`
66-
.baz {
65+
@import './dir-3/vector.css';
66+
.test3 {
6767
background-image: url('../../../resources/vector.svg');
6868
}
6969
`,
70+
'src/dir-1/dir-2/dir-3/vector.css': css`
71+
.test4 {
72+
background-image: url('./vector-2.svg');
73+
}
74+
`,
7075
'resources/image.png': binary(SIMPLE_IMAGE),
7176
'resources/vector.svg': svg`
7277
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
@@ -76,6 +81,14 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
7681
<circle cx="200" cy="100" r="80" fill="green" />
7782
</svg>
7883
`,
84+
'src/dir-1/dir-2/dir-3/vector-2.svg': svg`
85+
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
86+
<rect width="100%" height="100%" fill="blue" />
87+
<circle cx="200" cy="100" r="80" fill="green" />
88+
<rect width="100%" height="100%" fill="red" />
89+
<circle cx="200" cy="100" r="80" fill="pink" />
90+
</svg>
91+
`,
7992
},
8093
},
8194
async ({ fs, exec, expect }) => {
@@ -87,7 +100,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
87100
await fs.expectFileToContain(files[0][0], [SIMPLE_IMAGE])
88101

89102
let images = await fs.glob('dist/**/*.svg')
90-
expect(images).toHaveLength(1)
103+
expect(images).toHaveLength(2)
91104

92105
await fs.expectFileToContain(files[0][0], [/\/assets\/vector-.*?\.svg/])
93106
},

packages/@tailwindcss-node/src/compile.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ function createCompileOptions({
4040
async loadModule(id: string, base: string) {
4141
return loadModule(id, base, onDependency, customJsResolver)
4242
},
43-
async loadStylesheet(id: string, base: string) {
44-
let sheet = await loadStylesheet(id, base, onDependency, customCssResolver)
43+
async loadStylesheet(id: string, sheetBase: string) {
44+
let sheet = await loadStylesheet(id, sheetBase, onDependency, customCssResolver)
4545

4646
if (shouldRewriteUrls) {
4747
sheet.content = await rewriteUrls({

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

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
110110
DEBUG && I.start('Create compiler')
111111
let compiler = await compileAst(ast, {
112112
base: inputBasePath,
113+
shouldRewriteUrls: true,
113114
onDependency: (path) => {
114115
context.fullRebuildPaths.push(path)
115116
},

0 commit comments

Comments
 (0)