diff --git a/CHANGELOG.md b/CHANGELOG.md index ba47afa1cabd..8cbb3aee9df0 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 000000000000..b07632583a3e --- /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 a7c6433d4d87..4077df16dd8a 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 9f11f1d5a91c..54e0256b96e4 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 d027fbd9ca67..e21217f12b86 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) },