Allow users to disable url rewriting in the PostCSS plugin (#18321)

Since we (optionally) support source maps now it's possible that a later
PostCSS plugin that *still* does url rewriting might fail to do so
correctly because nodes will have preserved source locations in dev
builds where before we "pretended" that everything came from the
original file.

But, because we can't know if such a plugin is present, disabling this
behavior when source maps are enabled could cause issues *and* would be
a breaking change.

I wish everything *could just work* here but realistically we can't know
what plugins have run before our PostCSS plugin or what plugins will run
after so the best option (I think) we can offer here is to allow users
to disable url rewriting at the plugin level.

Fixes #16700
This commit is contained in:
Jordan Pittman 2025-07-30 10:35:10 -04:00 • committed by GitHub
parent afbfdebf06
commit 492304212f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 93 additions and 3 deletions

View file

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Extract candidates in Slang templates ([#18565](https://github.com/tailwindlabs/tailwindcss/pull/18565))
- Improve error messages when encountering invalid functional utility names ([#18568](https://github.com/tailwindlabs/tailwindcss/pull/18568))
- Don’t output CSS objects with false or undefined in the AST ([#18571](https://github.com/tailwindlabs/tailwindcss/pull/18571))
- Add option to disable url rewriting in `@tailwindcss/postcss` ([#18321](https://github.com/tailwindlabs/tailwindcss/pull/18321))
## [4.1.11] - 2025-06-26

View file

@ -72,3 +72,78 @@ test(
`)
},
)
test(
'url rewriting can be disabled',
{
fs: {
'package.json': json`
{
"dependencies": {
"postcss": "^8",
"postcss-cli": "^10",
"tailwindcss": "workspace:^",
"@tailwindcss/postcss": "workspace:^"
}
}
`,
'postcss.config.js': js`
module.exports = {
plugins: {
'@tailwindcss/postcss': {
transformAssetUrls: false,
},
},
}
`,
'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('./vector-2.svg');
}
.test3 {
background-image: url('../../../resources/vector.svg');
}
"
`)
},
)

View file

@ -48,16 +48,30 @@ function getContextFromCache(inputFile: string, opts: PluginOptions): CacheEntry
}
export type PluginOptions = {
// The base directory to scan for class candidates.
/**
* The base directory to scan for class candidates.
*
* Defaults to the current working directory.
*/
base?: string
// Optimize and minify the output CSS.
/**
* Optimize and minify the output CSS.
*/
optimize?: boolean | { minify?: boolean }
/**
* Enable or disable asset URL rewriting.
*
* Defaults to `true`.
*/
transformAssetUrls?: boolean
}
function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
let base = opts.base ?? process.cwd()
let optimize = opts.optimize ?? process.env.NODE_ENV === 'production'
let shouldRewriteUrls = opts.transformAssetUrls ?? true
return {
postcssPlugin: '@tailwindcss/postcss',
@ -123,7 +137,7 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
let compiler = await compileAst(ast, {
from: result.opts.from,
base: inputBasePath,
shouldRewriteUrls: true,
shouldRewriteUrls,
onDependency: (path) => context.fullRebuildPaths.push(path),
// In CSS Module files, we have to disable the `@property` polyfill since these will
// emit global `*` rules which are considered to be non-pure and will cause builds