Scanner `globs` walks gitignored directories (files pass respects .gitignore, globs pass does not)
Maintainers usually reply within 1 day
@akasakariko is already working on this.
Since Oct 2, 2026.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 58/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- node.js, vite
- Domain
- performance, tooling
Research direction
Start by running the self-contained repro.mjs and comparing the Scanner files and globs passes, then inspect the Scanner API and the oxide-helper.js integration mentioned in the report. Done means computing scanner.globs no longer traverses directories excluded by .gitignore, while the returned globs remain unchanged.
Written by the indexing model from the issue text.
Description
What version of Tailwind CSS are you using?
@tailwindcss/oxide 4.3.3 (same behaviour in 4.1.14)
What build tool (or framework if it abstracts the build tool) are you using?
@tailwindcss/vite; also reproduced with the JetBrains Tailwind CSS plugin (its oxide-helper.js) and with the Scanner API directly.
What version of Node.js are you using?
v24.18.1
What operating system are you using?
Linux (btrfs)
Reproduction
Self-contained script, no project needed:
// repro.mjs — run: strace -f -e trace=statx,openat -o trace.log node repro.mjs && grep -c 'repo/var/cache' trace.log
import { createRequire } from 'node:module';
import { mkdirSync, writeFileSync } from 'node:fs';
import { execSync } from 'node:child_process';
const require = createRequire(import.meta.url);
const { Scanner } = require('@tailwindcss/oxide');
const root = '/tmp/oxide-repro/repo';
mkdirSync(`${root}/var/cache/profiler/aa`, { recursive: true });
mkdirSync(`${root}/templates`, { recursive: true });
writeFileSync(`${root}/.gitignore`, '/var/\n');
writeFileSync(`${root}/templates/page.html`, '<div class="flex"></div>');
writeFileSync(`${root}/var/cache/profiler/aa/bb1234`, '<div class="grid"></div>');
execSync('git init -q', { cwd: root });
const scanner = new Scanner({ sources: [{ base: root, pattern: '**/*', negated: false }] });
console.log('files:', scanner.files); // correct: only templates/page.html
console.log('globs:', scanner.globs); // correct result, but computing it walks var/
Describe your issue
Auto source detection respects .gitignore when building scanner.files, but computing scanner.globs walks into gitignored directories anyway. The returned globs are correct (the ignored folder is not in them), so the problem is purely the traversal.
From the strace of the script above:
- The
filespass opensvar/, checksvar/.gitignore,var/.ignoreandvar/.git/info/exclude, then stops. That's correct. - The
globspass then opensvar/,var/cache,var/cache/profiler,var/cache/profiler/aaandstats every file inside. No ignore file is consulted on this pass.
With a large ignored directory this is very costly. In our case it was a Symfony var/cache/dev/profiler with ~13M small files:
vite buildhung for 20+ minutes inread_extent_buffer_pages, single-threaded on the main thread while readingglobs.- The JetBrains Tailwind helper kept spinning at 15–25% CPU per process. It always adds
{ base: <project root>, pattern: '**/*' }, so the walk happens whatever the CSS says.
scanner.files alone, on the same real project, returns in well under a second (3,299 files) and never touches the ignored folder.
Workaround
@import "tailwindcss" source(none); plus explicit @source paths avoids the root scan for the build. It doesn't help IDE integrations that hard-code a root source.
Possibly related: #20385 / #20397. That's a different trigger (allow-list .gitignore); here the .gitignore is a plain /var/.
- Dominant language
- TypeScript
- Stars
- 97.9k
- Forks
- 8.3k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 24
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from tailwindlabs/tailwindcss
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
tailwindlabs/tailwindcss#20491 · 1 reaction ·
Maintainers usually reply within 1 day
-
Source detection ignores `core.excludesFile`, so globally-ignored directories are scanned (reproduction for #19801)Possibly taken @Lukecele claimed this 22 days ago. Open
Difficulty 3/5 1-2 days Newbie friendliness 65/100
tailwindlabs/tailwindcss#20509 ·
Maintainers usually reply within 1 day
-
@tailwindcss/vite: cached Root.compiler pins the build's plugin context, keeping the finished bundle alive (multi-GB RSS in Astro SSG)Possibly taken @lazerg claimed this 28 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 68/100
tailwindlabs/tailwindcss#20501 · 4 comments ·
Maintainers usually reply within 1 day
-
Oxide 4.3.3: Windows access violation after scanning in a Node worker and unloading the addonPossibly taken @bompus claimed this 41 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 25/100
tailwindlabs/tailwindcss#20470 ·
Maintainers usually reply within 1 day
-
needs reproduction
Difficulty 4/5 3-5 days Newbie friendliness 45/100
tailwindlabs/tailwindcss#20464 · 9 comments ·
Maintainers usually reply within 1 day
All issues in tailwindlabs/tailwindcss
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
ccch1mneyyy/dsh-TUI#1631 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
MiniMax-AI/minimax-code#507 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Transient OAuth login failure persists in getLoginStatus and masks active account in dashboardMay be free again A pull request for this issue was closed without being merged. Openaccount-pool bug gui
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
lidge-jun/opencodex#7378 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day