From 225f3233b6a40f2ac0e3aaa712e55a6baefee913 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Fri, 7 Mar 2025 12:18:10 +0100 Subject: [PATCH] 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: Screenshot 2025-03-05 at 16 41 01 --------- Co-authored-by: Robin Malfait Co-authored-by: Jordan Pittman --- CHANGELOG.md | 2 + integrations/postcss/url-rewriting.test.ts | 74 ++++++++++++++++++++++ integrations/vite/url-rewriting.test.ts | 25 ++++++-- packages/@tailwindcss-node/src/compile.ts | 4 +- packages/@tailwindcss-postcss/src/index.ts | 1 + 5 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 integrations/postcss/url-rewriting.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index ba47afa1c..8cbb3aee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/integrations/postcss/url-rewriting.test.ts b/integrations/postcss/url-rewriting.test.ts new file mode 100644 index 000000000..b07632583 --- /dev/null +++ b/integrations/postcss/url-rewriting.test.ts @@ -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'); + } + " + `) + }, +) diff --git a/integrations/vite/url-rewriting.test.ts b/integrations/vite/url-rewriting.test.ts index a7c6433d4..4077df16d 100644 --- a/integrations/vite/url-rewriting.test.ts +++ b/integrations/vite/url-rewriting.test.ts @@ -42,31 +42,36 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
- `, - '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` @@ -76,6 +81,14 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { `, + 'src/dir-1/dir-2/dir-3/vector-2.svg': 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/]) }, diff --git a/packages/@tailwindcss-node/src/compile.ts b/packages/@tailwindcss-node/src/compile.ts index 9f11f1d5a..54e0256b9 100644 --- a/packages/@tailwindcss-node/src/compile.ts +++ b/packages/@tailwindcss-node/src/compile.ts @@ -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({ diff --git a/packages/@tailwindcss-postcss/src/index.ts b/packages/@tailwindcss-postcss/src/index.ts index d027fbd9c..e21217f12 100644 --- a/packages/@tailwindcss-postcss/src/index.ts +++ b/packages/@tailwindcss-postcss/src/index.ts @@ -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) },