From 492304212f51c995f40f613480b89dfeffa30c87 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 30 Jul 2025 10:35:10 -0400 Subject: [PATCH] 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 --- CHANGELOG.md | 1 + integrations/postcss/url-rewriting.test.ts | 75 ++++++++++++++++++++++ packages/@tailwindcss-postcss/src/index.ts | 20 +++++- 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5315b9f96..062fdf107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/integrations/postcss/url-rewriting.test.ts b/integrations/postcss/url-rewriting.test.ts index b07632583..bac9d95d5 100644 --- a/integrations/postcss/url-rewriting.test.ts +++ b/integrations/postcss/url-rewriting.test.ts @@ -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'); + } + " + `) + }, +) diff --git a/packages/@tailwindcss-postcss/src/index.ts b/packages/@tailwindcss-postcss/src/index.ts index 8a37f542c..c0fa5fe97 100644 --- a/packages/@tailwindcss-postcss/src/index.ts +++ b/packages/@tailwindcss-postcss/src/index.ts @@ -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