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 https://github.com/tailwindlabs/tailwindcss/issues/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>
This commit is contained in:
parent
d18fed1dca
commit
225f3233b6
5 changed files with 98 additions and 8 deletions
|
|
@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Fixed
|
||||
|
||||
- Vite: Fix `url(…)` rebasing in transitively imported CSS files ([#16965](https://github.com/tailwindlabs/tailwindcss/pull/16965))
|
||||
- PostCSS: Rebase `url(…)`s in imported CSS files ([#16965](https://github.com/tailwindlabs/tailwindcss/pull/16965))
|
||||
- Ensure utilities are sorted based on their actual property order ([#16995](https://github.com/tailwindlabs/tailwindcss/pull/16995))
|
||||
- Ensure strings in Pug and Slim templates are handled correctly ([#17000](https://github.com/tailwindlabs/tailwindcss/pull/17000))
|
||||
- Ensure `}` and `{` are valid boundary characters when extracting candidates ([#17001](https://github.com/tailwindlabs/tailwindcss/pull/17001))
|
||||
|
|
|
|||
74
integrations/postcss/url-rewriting.test.ts
Normal file
74
integrations/postcss/url-rewriting.test.ts
Normal file
|
|
@ -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');
|
||||
}
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
|
@ -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">
|
||||
|
|
@ -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 }) => {
|
||||
|
|
@ -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/])
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue