Ignore the standalone CLI (#20139)

This PR fixes an issue where if you use the standalone CLI, and you move
the standalone CLI into the current project, then we would scan that
standalone CLI as-if it contains Tailwind CSS classes. Since the CLI
contains actual Tailwind CSS classes, and is in fact readable text, this
binary would've been used as a source.

There are a few ways of fixing this, we could hardcode all the known
names, but that would result in an issue if you rename the CLI. We could
check whether it's a binary format and look for magic numbers at the
top. We could also check for a shebang at the top of the file and skip
it that way.

While some of these solutions might still be useful for the future. For
now I fixed it by essentially always ignoring `process.execPath`. That
way we never ever scan the actual executable regardless of whether you
renamed it or not.

Fixes: #20134

## Test plan

- Added an integration tests
- Works on every OS [ci-all]
This commit is contained in:
Robin Malfait 2026-06-02 12:49:53 +02:00 • committed by GitHub
parent 44818a6cf6
commit 0c5f8bfd88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 48 additions and 1 deletions

View file

@ -1,6 +1,7 @@
import nodeFs from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
import { candidate, css, html, js, json, test, ts } from '../utils'
import { candidate, css, html, IS_WINDOWS, js, json, test, ts } from '../utils'
const STANDALONE_BINARY = (() => {
switch (os.platform()) {
@ -15,6 +16,41 @@ const STANDALONE_BINARY = (() => {
}
})()
test(
'does not scan itself for candidates',
{
fs: {
'package.json': json`
{
"dependencies": {}
}
`,
'src/index.css': css` @import 'tailwindcss'; `,
},
},
async ({ root, fs, exec }) => {
let sourceBinary = path.resolve(
__dirname,
`../../packages/@tailwindcss-standalone/dist/${STANDALONE_BINARY}`,
)
let binary = IS_WINDOWS ? 'tailwindcss.exe' : 'tailwindcss'
let localBinary = path.join(root, binary)
await nodeFs.copyFile(sourceBinary, localBinary)
if (!IS_WINDOWS) {
await nodeFs.chmod(localBinary, 0o755)
}
await exec(`${IS_WINDOWS ? binary : `./${binary}`} --input src/index.css --output dist/out.css`)
await fs.expectFileNotToContain('dist/out.css', [
candidate`flex`,
candidate`grid`,
candidate`underline`,
])
},
)
test(
'includes first-party plugins',
{