From bfb5732b0b948d89c6803cb537bca168ec8e0a46 Mon Sep 17 00:00:00 2001 From: It's Me! <192345912+rebasecase@users.noreply.github.com> Date: Sun, 26 Apr 2026 14:45:39 +0100 Subject: [PATCH] Fall back to the plugin `base` when PostCSS has no `from` option (#19980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `@tailwindcss/postcss` derives `inputBasePath` from `result.opts.from`: ```ts let inputFile = result.opts.from ?? '' let inputBasePath = path.dirname(path.resolve(inputFile)) ``` When PostCSS calls the plugin without `from` (some bundlers, including Turbopack, do this for certain CSS inputs), `inputFile` is `''`, `path.resolve('')` returns `process.cwd()`, and `path.dirname(...)` therefore returns the **parent of CWD**. The downstream `compileAst({ base: inputBasePath })` call then asks the resolver to find `tailwindcss` from one level above the project root, which fails with: ``` Can't resolve 'tailwindcss' in '' ``` The plugin already computes `base = opts.base ?? process.cwd()` near the top. Reusing that as the fallback gives a sensible default (CWD) and respects an explicit `opts.base` when set. ```diff -let inputBasePath = path.dirname(path.resolve(inputFile)) +let inputBasePath = inputFile + ? path.dirname(path.resolve(inputFile)) + : base ``` ## Test plan Added a test in `packages/@tailwindcss-postcss/src/index.test.ts` that processes `@import 'tailwindcss'` via `processor.process(input)` with no `from` option. Before the fix, this throws `Error: Can't resolve 'tailwindcss' in ''`; after the fix, the import resolves and the processor returns non-empty CSS. I wasn't able to run the suite locally — `pnpm build` requires `cargo` for `@tailwindcss/oxide` and I don't have a Rust toolchain set up — so the test has been written to match existing conventions in `index.test.ts` (vitest, plain `postcss([tailwindcss({...})]).process(...)`), and I'm relying on CI to verify. --------- Co-authored-by: rebasecase Co-authored-by: Robin Malfait --- CHANGELOG.md | 1 + packages/@tailwindcss-postcss/src/index.test.ts | 10 ++++++++++ packages/@tailwindcss-postcss/src/index.ts | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b21eed2..2768ffbc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `@plugin` resolves package JavaScript entries instead of browser CSS entries when using `@tailwindcss/vite` ([#19949](https://github.com/tailwindlabs/tailwindcss/pull/19949)) - Fix relative `@import` and `@plugin` paths resolving from the wrong directory when using `@tailwindcss/vite` ([#19965](https://github.com/tailwindlabs/tailwindcss/pull/19965)) - Ensure CSS files containing `@variant` are processed by `@tailwindcss/vite` ([#19966](https://github.com/tailwindlabs/tailwindcss/pull/19966)) +- Resolve imports relative to `base` when `result.opts.from` is not provided when using `@tailwindcss/postcss` ([#19980](https://github.com/tailwindlabs/tailwindcss/pull/19980)) ## [4.2.4] - 2026-04-21 diff --git a/packages/@tailwindcss-postcss/src/index.test.ts b/packages/@tailwindcss-postcss/src/index.test.ts index ff12e09ef..9d23d0a8d 100644 --- a/packages/@tailwindcss-postcss/src/index.test.ts +++ b/packages/@tailwindcss-postcss/src/index.test.ts @@ -140,6 +140,16 @@ describe('processing without specifying a base path', () => { }) }) +test('fallback to `base` directory when `result.opts.from` is not provided', async () => { + let processor = postcss([ + tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), + ]) + + let result = await processor.process(`@import 'tailwindcss'`) + + expect(result.css.length).toBeGreaterThan(0) +}) + describe('plugins', () => { test('local CJS plugin', async () => { let processor = postcss([ diff --git a/packages/@tailwindcss-postcss/src/index.ts b/packages/@tailwindcss-postcss/src/index.ts index 2ff4405b6..0bc70cb9c 100644 --- a/packages/@tailwindcss-postcss/src/index.ts +++ b/packages/@tailwindcss-postcss/src/index.ts @@ -115,7 +115,7 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { } let context = getContextFromCache(postcss, inputFile, opts) - let inputBasePath = path.dirname(path.resolve(inputFile)) + let inputBasePath = inputFile ? path.dirname(path.resolve(inputFile)) : base // Whether this is the first build or not, if it is, then we can // optimize the build by not creating the compiler until we need it.